supervisor 简单理解

1. 找到配置文件,/etc/supervisor/supervisor.conf

添加

include

files = /www/server/panel/plugin/supervisor/profile/*.ini

test.ini文件内容

复制代码
[program:rabbitmq-consume]
process_name=%(program_name)s_%(process_num)02d
directory=/www/wwwroot
command=/www/server/php/73/bin/php /www/wwwroot/project/yii swoole-consume/run
autostart=true
autorestart=true
user=www
numprocs=1
redirect_stderr=true
stdout_logfile=/www/wwwlogs/project_rabbitmq_consume.log


[program:swoole-crontab-server]
process_name=%(program_name)s_%(process_num)02d
directory=/www/wwwroot
command=/www/server/php/73/bin/php /www/wwwroot/project/yii swoole-crontab/server-run
autostart=true
autorestart=true
user=www
numprocs=1
redirect_stderr=true
stdout_logfile=/www/wwwlogs/project_swoole_crontab.log


[program:swoole-crontab-client]
process_name=%(program_name)s_%(process_num)02d
directory=/www/wwwroot
command=/www/server/php/73/bin/php /www/wwwroot/project/yii swoole-crontab/client-run
autostart=true
autorestart=true
user=www
numprocs=2
redirect_stderr=true
stdout_logfile=/www/wwwlogs/project_swoole_crontab.log

swoole-consume/run.php

复制代码
<?php

/**
 * 进程池多消费者,多队列消费rabbitMQ队列
 */
namespace console\controllers;

use common\enums\RabbitMqEnum;
use console\controllers\swoole_server\BaseSwooleServer;
use Exception;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use ReflectionMethod;
use Swoole\Process\Pool;
use Yii;
/**
 * rabbitMQ队列消费者进程池
 */
class SwooleConsumeController extends BaseSwooleServer
{
    public $worker_num;
    
    public $consume_setting = [
    ];
    // 进程与消费者的对应关系
    public $worker_queue_relate = [];
    public function init(){
        $worker_num_arr = array_column($this->consume_setting,'worker_num');
        $this->worker_num = array_sum($worker_num_arr);
        $worker_id = 0;
        foreach($this->consume_setting as $key=>$queue_info){
            $wait_assign_worker_num = $queue_info['worker_num'];
            while($wait_assign_worker_num > 0){
                $this->worker_queue_relate[$worker_id] = $key;
                $worker_id ++;
                $wait_assign_worker_num --;
            }
        }
    }

    /**
     * 启动消费者
     * @return void
     */
    public function actionRun(){
        // 计数器,当进程反复退出重启时,可能代码有致命错误,需要处理
        // $atomic = new Atomic();
        $pool = new Pool($this->worker_num);
        //绑定一个事件
        $pool->on("WorkerStart", function ($pool, $worker_id) {
            echo 'worker_id:'.$worker_id.PHP_EOL;
            $queue_key = $this->worker_queue_relate[$worker_id];
            $queue_info = $this->consume_setting[$queue_key];
            //设置进程名称
            swoole_set_process_name('swoole : rabbitmq_process '.$queue_info['queue_name'].'_'.$worker_id);
            $process = $pool->getProcess($worker_id);
            try {
                Yii::$app->services->rabbitMq->listen($queue_info['exchange'], $queue_info['queue_name'], function ($message) {
                    $res = $this->handleMessage($message);
                    Yii::getLogger()->flush(true);
                    return $res;
                });
            } catch (Exception $e) {
                Yii::getLogger()->flush(true);
                echo 'exception:' . $e->getMessage().$e->getFile().':'.$e->getLine().PHP_EOL;
            }
        });

        //子进程关闭
        $pool->on("WorkerStop", function ($pool, $workerId) {
            echo "Worker#{$workerId} is stopped\n";
        });
        $pool->start();
    }

    /**
     * 消息处理
     * @param AMQPMessage $message
     * @throws
     * @return bool
     */
    private function handleMessage($message)
    {
        $date = date('Y-m-d H:i:s');
        $routing_key = $message->getRoutingKey();
        $flush = '['.$date.']'.'队列(' . $routing_key . ')接收到消息,其内容为:' . $message->getBody();

        $message_body = json_decode($message->getBody(), true);

        $class = $message_body['handler_class'];
        $method = $message_body['method'];
        $data = $message_body['data'];
        $data['message_id'] = $message->get('message_id');
        if (!method_exists($class, $method)) {
            //方法不存在,忽略
            Yii::error('actionTaskConsume: class' . $class . ' ,method:' . $method . ' ,not exist');
            return false;
        }

        $reflect_method = new ReflectionMethod($class, $method);
        Yii::$app->db->close();
        Yii::$app->redis->close();
        $time1 = time();
        if ($reflect_method->isStatic()) {
            $res = $class::$method($data);
            if ($res === false) Yii::error($class::$static_error ?? '未定义错误');
            //if($res === false) throw new Exception($class::$static_error ?? '未定义错误');
        } else {
            $obj = new $class();
            $res = $obj->$method($data);
            if ($res === false) Yii::error($obj->error ?? '未定义错误');
            //if($res === false) throw new Exception($obj->error ?? '未定义错误');
        }
        $time2 = time();
        $total_time = $time2 - $time1;
        if ($total_time > 1) $flush .= ',队列耗时:' .$total_time . '秒';
        echo $flush . PHP_EOL . PHP_EOL;
        return $res;
    }

    /**
     * 重启消费者
     * @return void
     */
    public function actionRestartConsume(){
        
    }
}
相关推荐
红尘散仙5 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记7 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆7 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪7 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6168 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364578 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao8 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
IT_陈寒9 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
ayqy贾杰10 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理
Apifox10 小时前
Apifox 5 月更新|Postman 导入优化、Runner 支持非 root 运行、请求代码自动带鉴权
前端·后端·安全