以前 qiita で公開していた記事を引っ越してきたものです。最終更新からかなり経っているため、情報の正確性は落ちている可能性があります。
Laravel の queue を daemon で動かすにはぐぐってみると Supervisor を使っている事例が多く見つかる。
しかし、queue:listen
(または queue:work --daemon
) が pop した worker job を処理している最中でも、遠慮なく SIG* で終了させてしまう実装になっているように見えるため、タイミングによっては worker job が適切に完了されない場合もある。
ちなみに Laravel の queue は 4.2 の実装では 2 種類存在する。
- queue:listen は pop した worker job を Symfony/Component/Process/Process 経由で proc_open し、子プロセスとして処理する。
- queue:work --daemon は自身のプロセス内で都度 worker job を pop して実行する。
ただし、後者は worker job が終了する毎に queue:restart で終了命令が発行されていないか確認して、されている場合は queue:work --daemon
自身を終了するようになっている。
そこで queue:restart
を使って、実行中かもしれない worker job を SIG* で強制終了させることなく queue:work --daemon
を再起動させる仕組みを考えてみた。
Laravel の Command の fire() で以下の実装をしてみる。
// start.php $pidFile = '/var/run/laravel-queue-work-daemon.pid'; if (File::exists($pidFile)) { return; } $pid = pcntl_fork(); if ($pid === -1) { exit(); } elseif ($pid !== 0) { exit(); } else { posix_setsid(); File::append($pidFile, posix_getpid() . PHP_EOL); $this->call('queue:work', [ '--daemon' => true ]); }
// stop.php
$pidFile = '/var/run/laravel-queue-work-daemon.pid';
if (! File::exists($pidFile)) {
return;
}
$pid = intval(File::get($pidFile));
$this->call('queue:restart');
$procPath = '/proc/' . $pid;
while (true) {
if (! File::exists($procPath)) {
break;
}
sleep(1);
}
File::delete($pidFile);
これで daemon を起動する時は
$ /usr/bin/nohup php artisan myqueue:start < /dev/null > /dev/null 2>&1 &
終わらせる時は
$ php artisan myqueue:stop
とそれぞれ入力すればいい。