Supervisord :如果有任何工人,我如何执行自定义 php 命令进程 ID 123 停止

Supervisord : How do I execute custom php command if any of worker e.g. process id 123 stops

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php artisan queue:work --tries=3 --queue=checkin_checkout
directory=/var/www/byjus-ams
autostart=true
autorestart=true
numprocs=5
redirect_stderr=true
stdout_logfile=/var/log/supervisor/supervisord.log
#stopwaitsecs=3600

截至目前,我的主管配置与上面的 运行s 5 worker 并行。 现在我想要的是:当任何工人被杀时,我想触发自定义 php 命令(例如:php artisan broadcast-process-killed) . 任何人都知道如何处理此类事件并在任何工作进程获取后触发自定义 php 命令以及如何配置它?

下面还要简化

supervisor> status
laravel-worker:laravel-worker_00   RUNNING   pid 9460, uptime 4:32:43
laravel-worker:laravel-worker_01   RUNNING   pid 15907, uptime 7:01:51
laravel-worker:laravel-worker_02   RUNNING   pid 22621, uptime 6:30:17
laravel-worker:laravel-worker_03   RUNNING   pid 15909, uptime 7:01:51
laravel-worker:laravel-worker_04   RUNNING   pid 24049, uptime 6:23:00
supervisor> 

如果我使用 kill -9 9460 ,我想 运行 启用自定义命令。有人用过自定义事件吗?

我找到了一个解决方案,您可以在实际命令之前 运行 命令:

command=/bin/sh -c "php artisan broadcast-process-started; exec php artisan queue:work --tries=3 --queue=checkin_checkout"

这样做将在您的工作人员停止工作并重新启动后始终执行 broadcast-process-started

通过使用/bin/sh -c,您可以将这两个命令合二为一。通过将 execute 添加到第二个 'actual' 命令,supervisord 将能够处理它的 pid。

如果您省略 exec,您将获得由 /bin/sh 分叉的 pid,并且您在其中的所有命令将作为子进程产生,supervisord 无法处理。因此,当您重新加载子进程时,它仍然存在!所以保留 exec!

如果翻转命令,广播将不会执行。


Event-Listener解决方案


监督者配置

[eventlistener:test-listener]
command=php /some/dir/event-listener.php <name>
events=PROCESS_STATE
stderr_logfile=/some/dir/event_err.log

其中 <name> 指的是您配置的 [program:<name>] - 您要观察的程序。


event-listener.php

写为 php-script - 您也可以将其编码为 artisan 命令。

<?php

declare(strict_types=1);

$programToListen = $argv[1] ?? false;
$eventsToListen = [
    'PROCESS_STATE_EXITED',
    'PROCESS_STATE_FATAL',
    'PROCESS_STATE_STOPPED',
];

if ($programToListen === false) {
    exit(1);
}

while (true) {
    // tell supervisord we are ready to receive event-headers
    echo 'READY' . PHP_EOL;
    
    $eventHeader = parseEventHeader(fgets(STDIN));
    
    if (
        ($eventHeader['groupname'] ?? '') === $programToListen &&
        in_array(($eventHeader['eventname'] ?? ''), $eventsToListen)
    ) {
        debug(sprintf(
            'Handling %s of %s',
            $eventHeader['eventname'],
            $eventHeader['groupname']
        ));
       
        // add your code here
        // exec('php artisan ...') for example
    }

    // Tell supervisord we are done handling the event-header
    echo 'RESULT 2' . PHP_EOL . 'OK';
}

function debug(string $message): void {
    fwrite(STDERR, $message . PHP_EOL);
    return;
}

function parseEventHeader(string $eventHeaderString): array {
    $keyValuePairs = explode(' ', $eventHeaderString);

    $eventArray = [];
    foreach ($keyValuePairs as $keyValuePair) {
        $keyValue = explode(':', $keyValuePair);

        $eventArray[$keyValue[0]] = $keyValue[1];
    }

    return $eventArray;
}

exit(0)
?>

琐事

  • 除了使用 echo 你也可以 fwrite(STDOUT,..),但这对我来说有点太花哨了。
  • 我留在我的调试机制中,以防你想fiddle使用它(你会的:D)。

补充信息

  • 在此处查看可用的 Process-Types 处理。
  • 在此处查看 Subprocess-States(产生事件)。
  • Event-Listener 通知 protocol(我们的 echo 消息和 event-header 解析)。
  • PROCESS_STATE_EXITED 将在 > kill 或执行结束时触发
  • PROCESS_STATE_STOPPED 将由主管触发(restart 等)
  • 我没能触发 PROCESS_STATE_FATAL - 但会收听它,以防万一:)