Symfony messenger 工作人员在主管下运行时不会停止

Posted

技术标签:

【中文标题】Symfony messenger 工作人员在主管下运行时不会停止【英文标题】:Symfony messenger workers do not stop when running under supervisor 【发布时间】:2020-12-10 00:14:38 【问题描述】:

我正面临 Symfony Messenger 组件的奇怪行为。我根据documentation 进行设置,并按照here 的指示在每次部署时发出messenger:stop-workers 信号。然而,我们的系统中出现了一个错误,我追溯到 Messenger 工作人员正在使用旧版本的代码。

经过进一步调查,我们的设置中会发生以下情况:

工作人员正在运行,由主管管理。 只是为了调试这个特殊情况,我在终端 app/console messenger:consume --env=prod -vv async 中启动了一个新工作人员,看看会发生什么 我发出停止命令app/console messenger:stop-workers --env=prod 我现在希望这两个工作人员都将停止(并且主管将重新启动它正在处理的工作人员)。但是,这不会发生。 “调试”工作人员确实停止了,但在主管下运行的工作人员什么也不做。

主管管理的工作人员被限制为 1 小时的处理时间,之后它们会停止并重新启动。我可以在supervisord.log 中看到这很好用。每小时都有关于进程停止和启动的日志条目。但是他们并没有停止messenger:stop-workers 命令。

我正在寻找关于为什么会发生这种情况的想法。我阅读了workers的实现,关闭信号是通过缓存发送的,但我没有发现我们的配置有任何问题。

【问题讨论】:

supervisorctl restart all 部署不是一个选项? 这是一个选项,这就是我现在所做的,以解决当前的问题。但这(或至少感觉)不太优雅,因为它杀死了工作进程,而不是按照预期的方式发送停止信号。如果这被证明是进行部署的最佳方式,那么 Symfony 文档具有误导性,应该更新,因为它根本没有警告这一点。 也许这会有所帮助:在幕后,这个命令会向每个工作人员发送一个应该退出的信号。但是工人很聪明:他们不会立即退出,他们会完成他们正在处理的任何消息然后退出:优雅的退出。为了发送这个信号,Symfony 实际上在缓存系统中设置了一个标志——每个工作人员都会检查这个标志。如果你有一个多服务器设置,你需要确保你的 Symfony “应用程序缓存” 存储在 Redis 或 Memcache 之类的东西而不是 fs 中,以便每个人都可以读取这些密钥。 symfonycasts.com/screencast/messenger/deploy-restarting 【参考方案1】:

我遇到了类似的问题。

如您所见,为了强制停止其余消费者,该命令使用缓存池。在我的情况下(可能也是你的情况),是存储在/your_symfony_app/var/cache/env/pools中的文件系统池

因此,如果您使用 Deployer 或任何其他部署系统来替换每个新部署的符号链接,则需要在 上一个版本的文件夹中执行命令 messenger:stop-workers。。 p>

另一种选择是配置所有版本共享的缓存池,例如 memcached 或 redis。

就我而言,使用 Deployer(软件仍在开发中)我已经能够通过声明这样的任务并将其放入部署主任务中来解决它:

task('messenger:stop', function () 
    if (has('previous_release')) 
        run('bin/php previous_release/bin/console messenger:stop-workers');
    
)->desc('Stop workers');

【讨论】:

感谢您的回答!您会将messenger:stop 放在您的部署流程中的什么位置?作为第一件事? 在这种情况下,我就在“deploy:symlink”任务之后拥有它。【参考方案2】:

在我们等待更好的解决方案时,这里有一个解决此问题的方法。

仅当您的 Symfony Messenger 支持此处提交的 --failure-limit 选项时,您才能使用此解决方法: https://github.com/symfony/symfony/pull/35453/commits/ea79206470ac3b71520a35129d36ca0d11ce4a09

    通过主管启动信使总是有一个最大失败: php bin/console messenger:consume async --failure-limit=1

    在您的代码库中定义一个消息RestartMessenger 和相应的处理程序RestartMessengerHandler,它只是抛出一个异常,例如MessengerNeedsToBeRestartedException

    创建一个名为 app:messenger-restart-request 的 Symfony 命令,用于调度 RestartMessenger

    在您的部署脚本(bash、Ansible 或其他)中添加作为最后一步:php bin/console app:messenger-restart-request。这会抛出一个异常,导致 Messenger 重启,因为--failure-limit=1

【讨论】:

有趣的想法!虽然这将导致每次由于错误或其他原因在代码中引发实际异常时重新启动信使工作人员。

以上是关于Symfony messenger 工作人员在主管下运行时不会停止的主要内容,如果未能解决你的问题,请参考以下文章

Symfony Messenger:重试延迟不适用于 Redis 传输

Symfony:我如何在 Messenger 中使用远程过程调用(RPC)?

Symfony 5 Messenger 不自动配置消息处理程序

如何在 Symfony Messenger 的中间件上禁用日志“信息”?

在 Symfony Messenger 组件中使用独立的发件人

Symfony Messenger 如何确定应由哪个处理程序处理每种类型的消息?