supervisorctl配置,php脚本启动多个进程

supervisorctl 是 Supervisor 的命令行工具,用于管理和控制 Supervisor 中配置的进程。Supervisor 是一个进程管理工具,用于启动、停止和监控进程。

[program:tdcrm_chat_message_0]
command=/usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message 0
stdout_logfile=/data/logs/supervisor/tdcrm_syn_chat_message_0.log
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
user=www

[program:tdcrm_chat_message_1]
command=/usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message 1
stdout_logfile=/data/logs/supervisor/syn_chat_message_1.log
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
user=www

[program:tdcrm_chat_message_2]
command=/usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message 2
stdout_logfile=/data/logs/supervisor/tdcrm_syn_chat_message_2.log
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
user=www

[program:syn_chat_message_ai]
command=/usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai %(process_num)d
stdout_logfile=/data/logs/supervisor/syn_chat_message_ai.log
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)d
numprocs=5
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
user=www

[program:syn_chat_ai_list_return_ai]
command=/usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_ai_list return_ai %(process_num)d
stdout_logfile=/data/logs/supervisor/syn_chat_ai_list_return_ai.log
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)d
numprocs=5
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
user=www

 

字段解释[program ]: 定义一个名为 syn_chat_message_ai 的程序。program: 后面的名字是你为这个程序定义的标识符。

  • command: 执行的命令。这里是运行一个PHP脚本,%(process_num)d 是一个占位符,会被替换为 numprocs 中定义的进程编号。

  • stdout_logfile: 标准输出日志文件的路径。程序运行时的输出会被写入这个文件。

  • autostart: 是否在Supervisor启动时自动启动这个程序。true 表示自动启动。

  • autorestart: 当程序退出时,是否自动重启。true 表示自动重启。

  • process_name: 进程名称模板。%(program_name)s 是程序名称的占位符,%(process_num)d 是进程编号的占位符。例如,如果程序名是 syn_chat_message_ai,进程编号是 0,那么进程名将是 syn_chat_message_ai_0

  • numprocs: 启动的进程数量。这里设置为 5,表示将启动 5 个进程,每个进程的 command 参数中的 %(process_num)d 会被替换为 04

  • startsecs: 程序启动后在这段时间内(秒)没有退出,Supervisor会认为启动成功。这里设置为 5 秒。

  • priority: 程序启动的优先级。值越小,优先级越高。这里设置为 1

  • stopasgroup: 是否将 stop 信号发送到进程组。true 表示会将停止信号发送给进程组中的所有进程。

  • killasgroup: 是否将 kill 信号发送到进程组。true 表示会将杀死信号发送给进程组中的所有进程。

  • user: 以哪个用户的身份运行这个程序。这里设置为 www,表示以 www 用户身份运行。

进程编号的替换

numprocs 设置为 5 时,Supervisor会启动5个进程,command 中的 %(process_num)d 会被分别替换为 01234。这样每个进程都会有一个唯一的编号,并且会分别执行以下命令:

  • /usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai 0
  • /usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai 1
  • /usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai 2
  • /usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai 3
  • /usr/local/php/bin/php /data/wwwroot/tdcrm/artisan app:syn_chat_message_ai 4

每个进程的输出会被写入到同一个日志文件 /data/logs/supervisor/syn_chat_message_ai.log

 

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Mockery\Exception;
use Modules\Brain\Service\ChatMessage;
use Modules\Brain\Service\WorkFlow;
use Modules\System\Models\ConfigCenter;
use function Laravel\Prompts\select;

class syn_chat_ai_list extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:syn_chat_ai_list {opt} {process_num}';

protected $signature_full = 'app:syn_chat_ai_list ';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';

private $processNum = 0;

/**
* Execute the console command.
*/
public function handle()
{
/* $redis = Redis::connection('default');*/
$this->processNum = $this->argument('process_num');
$opt = $this->argument('opt');
$this->signature_full .= $opt;
/* $binNum = exec("ps -ef |grep '" . $this->signature_full . "' |grep -v grep |grep -v '/bin/sh -c' |wc -l");
if (intval($binNum) > 1) {//最多1个进程
echo '不能启用太多进程';
exit;
}*/
while (true) {
try {
switch ($opt) {
case 'create':
$this->create_message_list();
break;
case 'return_ai':
$this->return_ai();
break;
}
} catch (Exception $e) {
Log::error($this->signature_full . "执行异常", ['error' => $e->getMessage(), 'line' => $e->getLine()]);
}
usleep(100);
}

}

private function create_message_list()
{

$redis = Redis::connection('default');
$c_k = "c_s_h";
$keys = $redis->hkeys($c_k);
if (empty($keys)) {
return [];
}
foreach ($keys as $key) {
$payloads = [];
$item = $redis->hget($c_k, $key);
if (empty($item)) {
Log::error("读取消息" . $c_k, [$key, $item]);
continue;
}
$item = json_decode($item, true);
extract($item);
// 时间小于10s的等候一下
/* if ((time() - $t) <= 10) {
continue;
}*/
$m_k = "c_m_h_" . $u . "_wxid_" . $w;
$message_keys = $redis->hkeys($m_k);
if (empty($message_keys)) {
/* $err = [
'msg' => '消息记录不存在',
'm_k' => $m_k
];
WorkFlow::add_message_log("error", "syn_chat_message_ai", $err, 0);*/
Log::error("消息记录不存在syn_chat_message_ai", [$message_keys]);
continue;
}
foreach ($message_keys as $mk) {
$i = $redis->hget($m_k, $mk);
if (empty($i)) {
Log::error("消息记录不存在", [$m_k, $i, $mk]);
continue;
}
$i = json_decode($i, true);
// Log::info("消息记录详情", [$i]);
$payloads[] = $i;
$redis->hdel($m_k, $mk);

$message = [];
$message['botUserId'] = $botUserId;
$message['customerExternalUserId'] = $customerExternalUserId;
$message['externalUserId'] = $externalUserId;
$message['coworker'] = $coworker;
$message['projectId'] = $projectId;
$message['period_id'] = $period_id;
$message['period'] = $period;
$message['stage'] = $stage;
$message['wxid'] = $w;
$message['bot_id'] = $bot_id;
$message['customer_profile'] = $customer_profile;
$message['ex_nickname'] = $ex_nickname;
$message['nickname'] = $nickname;
$message['payloads'] = $payloads;
$message['timestamp'] = time();
$message['member_id'] = $member_id;
Log::info("ai请求数据", $message);
$redis->lpush("chat_message_ai_list", json_encode($message));
}
$redis->hdel($c_k, $key);

}
}

private function return_ai()
{
$redis = Redis::connection('default');
$key = "chat_message_ai_list_" . $this->processNum;
$info = $redis->lpop($key);

if (empty($info)) {
return [];
}
$info = json_decode($info, true);
// Log::error("请求ai",[$info['messageId']??'']);
if (empty($info)) {
Log::error("请求ai数据为空", [$info]);
return [];
}
if ($info['wxid'] == $info['bot_id']) {
Log::error("给自己发送消息", [$info]);
return [];
}
Log::info("ai请求数据", [$info]);
if (empty($info['roomWecomChatId'])) {
$returns = ChatMessage::getAiReturn($info);
} else {
$returns = ChatMessage::getGroupAiReturn($info);
}
Log::info("ai返回数据", [$info, $returns]);
$answers = $returns['data']['answers'] ?? [];
if (empty($answers)) {
return [];
}
$data = ['answers' => $answers, 'wxid' => $info['wxid'], 'bot_id' => $info['bot_id'],
'botUserId' => $info['botUserId'], 'projectId' => $info['projectId'],
"roomWecomChatId" => $info['roomWecomChatId'] ?? '', "imContactId" => $info['imContactId'] ?? ''];
$redis->lpush("chat_message_ai_return_" . $this->processNum, json_encode($data));
}

}
posted @ 2024-07-03 11:00  菜鸟的地盘  阅读(10)  评论(0编辑  收藏  举报