Laravel Artisan CLI 安全地停止守护进程队列工作者

Posted

技术标签:

【中文标题】Laravel Artisan CLI 安全地停止守护进程队列工作者【英文标题】:Laravel Artisan CLI safely stop daemon queue workers 【发布时间】:2015-07-15 15:11:30 【问题描述】:

为了处理大量作业,我根据要完成的工作量运行可变数量的队列工作人员。我不希望在我们认为合适的时间内完成需要完成的工作所需的员工数量。

目前,出于测试目的,我启动了 5 个守护进程队列工作人员,但在生产中,这个数量可能在 25 到 100 个工作人员之间,甚至可能更多。我知道在部署时,我必须先使用php artisan down 将框架置于维护模式来停止队列工作人员,因为--daemon 标志会导致框架仅在工作人员启动时加载,因此新代码不会在部署期间生效,直到 worker 重新启动。

如果我出于某种原因需要停止工作人员,我可以使用 php artisan down 将应用程序置于维护模式,这将导致工作人员在完成当前工作(如果他们正在工作)后死亡。但是,有时我想杀死工作人员而不将整个应用程序置于维护模式。

是否有一种安全的方法可以阻止工作人员继续处理当前工作,然后在不将整个应用程序置于维护模式的情况下死亡?

基本上我需要的是一个php artisan queue:stop,它的行为类似于php artisan queue:restart,但是一旦工作完成就不会重新启动worker。

我期待有一个类似php artisan queue:stop 的命令可以执行此操作,但事实并非如此。

使用ps aux | grep php,我可以获取工作人员的进程ID,并且我可以通过这种方式终止进程,但我不想在工作过程中终止进程。

谢谢。

【问题讨论】:

对于任何发现此问题的人。 ***.com/questions/30060526/… 有答案。 php artisan queue:restart 将停止工作人员。 “重启”名称具有误导性。工人停止后实际上不会重新启动。 是正确的。 “重新启动”只有在您有像 Supervisor setup 这样的东西来监控并在它们退出后自动重新启动它们时才会发生。 (这是典型的设置。) 【参考方案1】:

我们已经在我们的应用程序中实现了类似的东西 - 但它不是 Laravel 本身内置的东西。您必须编辑this file,通过向 if 块添加另一个条件,以便它调用stop 函数。您可以通过在Worker 类中设置一个静态变量来执行此操作,该变量在您运行必须执行的自定义命令时更改(即php artisan queue:pause)或通过检查某处的原子值(即设置它一些缓存,例如 redis、memcached、APC 甚至 mysql,尽管这意味着您将使用相同的自定义命令设置此 while 循环的每个循环都有一个 MySQL 查询。

【讨论】:

是的,我担心我将不得不做这样的事情。必须设置 redis 或 memcache,检查标志有点浪费查询,特别是当它发生在循环中的每次迭代时,有 25 - 100 个工作人员。到目前为止我得到的最佳答案,所以+。希望他们在以后的版本中添加类似的内容。 是的,APC/redis/memcached 是最好的选择,APC 在这种情况下是最好的。【参考方案2】:

使用--daemon 标志时,工作人员不应在队列为空时退出。

我想你要找的是in the documentation for queues.

php artisan queue:restart 命令将提示工作人员在完成当前工作后重新启动。

【讨论】:

正确,我不希望工作人员在队列为空时停止。我要做的是按命令停止队列工作人员,但要“安全”地进行,这样他们就不会在处理工作的过程中停下来。 php artisan queue:restart,不幸的是没有做我需要做的事情。我不希望重新启动工人,我希望“安全地”阻止他们。该文档不包含有关停止队列工作人员的任何信息,它仅提到您可能必须“手动”执行此操作。 基本上我需要的是一个php artisan queue:stop,它的行为类似于php artisan queue:restart,但是一旦工作完成就不会重启worker。 php artisan queue:work --daemon打开一个终端,在另一个终端运行php artisan queue:restart。第一个终端实际上​​会在一段时间后关闭。它实际上并没有重新启动它,这取决于像supervisord.org这样的单独进程来处理。【参考方案3】:

从 Laravel 5.5 开始,有一个名为 Illuminate\Queue\Events\Looping 的事件会从 Illuminate\Queue\Worker 的主工作循环内的 daemonShouldRun() 调用中触发。因此,如果您设置一个侦听器来执行您的应该处理作业检查,并返回 false,那么队列工作人员将停止,直到检查返回 true。下次检查之间会有一个睡眠,您可以通过将 --sleep <seconds> 传递给 queue:work 命令来自定义它。

我目前在部署过程中使用这种技术来阻止在 docker 容器中运行的工作人员,因为要在他们身上运行建议的 queue:restart 并不容易。

【讨论】:

【参考方案4】:

我的 Laravel 是 5.6。 你可以(杀死你的 pid)别担心失去你的工作 只需加载 pcntl(extension) Laravel 即可监听信号并安全退出

在下面显示部分源代码(在 ./vendor/laravel/framework/src/Illuminate/Queue/Worker.php):

protected function listenForSignals()

    pcntl_async_signals(true);

    pcntl_signal(SIGTERM, function () 
        $this->shouldQuit = true;
    );

    pcntl_signal(SIGUSR2, function () 
        $this->paused = true;
    );

    pcntl_signal(SIGCONT, function () 
        $this->paused = false;
    );

下面是我的测试:

for($i=0; $i<100; $i++)
        pcntl_async_signals(true);

    pcntl_signal(SIGTERM, function () 
        echo 'SIGTERM';
    );

    pcntl_signal(SIGUSR2, function () 
        echo 'SIGUSR2';
    );

    pcntl_signal(SIGCONT, function () 
        echo 'SIGCONT';
    );
echo $i; 
sleep(1);
 

你可以尝试杀死它

【讨论】:

不要低估pcntl 扩展的重要性,并确保你的终止信号没有设置为SIGKILL(在官方Docker PHP 图像上默认),而是SIGTERM 修复它! 【参考方案5】:

还有——如果(某事=某事)? app('queue.worker')->shouldQuit = 1;

效果很好

它也非常适合那些吸走 ram 的工作,因为它会杀死进程,然后你的视野或任何会重新启动它的东西。

【讨论】:

以上是关于Laravel Artisan CLI 安全地停止守护进程队列工作者的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Artisan cli 添加到现有的 laravel 项目?

Laravel - 在我运行 composer update CLI artisan 之后出现问题

Laravel Artisan CLI 没有设置正确的 URL

Laravel 4 migrate:rollback with --path on artisan CLI

Laravel 4 migrate:rollback with --path on artisan CLI

Laravel 4.2 artisan CLI 在作曲家更新后不再工作