能否允许 Messenger 的消费命令从 SQS 消息读取失败中恢复?

Can Messenger's consume command be allowed to recover from SQS message read failures?

我正在研究 a simple microservice 我们已经放在一起排队和发送电子邮件。在实时环境中,队列目前通过最新的 Symfony Messenger 组件 (v5.2.x) 及其 SQS 桥使用 SQS。

这在大多数情况下运行良好,但偶尔(大约每隔几周)我们会看到 SQS return 对 consumer/worked 的流氓 500 服务器错误,这是一个 ECS 服务 运行 Messenger 的现成 ConsumeMessagesCommand。该错误导致消费者完全退出 - 不是 ECS 启动另一个世界末日,但感觉我们应该能够做得更好!

我查看的最后一条跟踪是 Messenger v5.1.5,但我认为涉及的 Messenger 代码此后没有发生实质性变化。错误来自 AmazonSqsReceiver::get() on this line 并且消费者应用程序崩溃报告 PHP Fatal error: Uncaught AsyncAws\Core\Exception\Http\ServerException。我在这个问题的底部粘贴了带有日志时间戳的完整跟踪。

因为 ServerException implements HttpException 被捕获,据我所知,代码接下来会抛出一个 Symfony-native TransportException,但是传入原始的 AWS 异常供 Messenger 处理,因为它看到适合 – 然后某些东西(我还没有弄清楚)似乎稍后会重新抛出,导致致命的未处理异常。

感觉也许可以使用不同的行为而不是强制退出到 ConsumeMessagesCommand,可能是通过配置稍微不同的接收器,或者建议更改 SQS 处理此问题的方式如果一致认为其他东西对大多数用例来说更好,那就开箱即用。我很高兴尝试在后者上工作,但我觉得我对 Messenger 的一些 类 的理解以及它们的预期用途到目前为止有点脆弱。我注意到最近添加了新的 RecoverableExceptionInterface,但我不知道将它用于这样的 Receiver 是否在预期范围内。

我快速浏览了扩展 AmazonSqsReceiver 以仅调整 get() 而无需维护完全独立的接收器,但由于 Connection 等属性是私有的,因此很快就会变得混乱。

我认为我在错误情况下的理想结果是 或者:

任何想法都非常感谢——关于这是否按设计运行,如果是这样我可以做些什么来解决它!

2020-11-29T09:14:04.977+02:00   [29-Nov-2020 07:14:04 UTC] PHP Fatal error: Uncaught AsyncAws\Core\Exception\Http\ServerException: HTTP 500 returned for "https://sqs.eu-west-1.amazonaws.com/".
2020-11-29T09:14:04.977+02:00   Code: InternalError
2020-11-29T09:14:04.977+02:00   Message: We encountered an internal error. Please try again.
2020-11-29T09:14:04.977+02:00   Type: Receiver
2020-11-29T09:14:04.977+02:00   Detail:
2020-11-29T09:14:04.977+02:00   in /var/www/html/vendor/async-aws/core/src/Response.php:358
2020-11-29T09:14:04.977+02:00   Stack trace:
2020-11-29T09:14:04.977+02:00   #0 /var/www/html/vendor/async-aws/core/src/Response.php(117): AsyncAws\Core\Response->getResolveStatus()
2020-11-29T09:14:04.977+02:00   #1 /var/www/html/vendor/async-aws/core/src/Result.php(63): AsyncAws\Core\Response->resolve(0.1)
2020-11-29T09:14:04.977+02:00   #2 /var/www/html/vendor/symfony/amazon-sqs-messenger/Transport/Connection.php(202): AsyncAws\Core\Result->resolve(0.1)
2020-11-29T09:14:04.977+02:00   #3 /var/www/html/vendor/symfony/amazon-sqs-messenger/Transport/Connection.php(193): Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\Connection->fetchMessage()
2020-11-29T09:14:04.977+02:00   #4 /var/www/html/vendor/symfony/amazon-sqs-messenger/Transport/Connection.php(165): Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\Connection->getNewMessages()
2020-11-29T09:14:04.977+02:00   #5 /var/www/html/vendor/symfony/amazon-sqs-messenger/Transport/Connection.php(152): Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\Connection->getNextMessages()
2020-11-29T09:14:04.977+02:00   #6 /var/www/html/vendor/symfony/amazon-sqs-messenger/Transport/AmazonSqsReceiver.php(44): Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\Connection->get()
2020-11-29T09:14:04.977+02:00   #7 /var/www/html/vendor/symfony/messenger/Worker.php(74): Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsReceiver->get()
2020-11-29T09:14:04.977+02:00   #8 /var/www/html/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php(197): Symfony\Component\Messenger\Worker->run(Array)
2020-11-29T09:14:04.977+02:00   #9 /var/www/html/vendor/symfony/console/Command/Command.php(258): Symfony\Component\Messenger\Command\ConsumeMessagesCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
2020-11-29T09:14:04.977+02:00   #10 /var/www/html/vendor/symfony/console/Application.php(916): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
2020-11-29T09:14:04.977+02:00   #11 /var/www/html/vendor/symfony/console/Application.php(264): Symfony\Component\Console\Application->doRunCommand(Object(Symfony\Component\Messenger\Command\ConsumeMessagesCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
2020-11-29T09:14:04.977+02:00   #12 /var/www/html/vendor/symfony/console/Application.php(140): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
2020-11-29T09:14:04.977+02:00   #13 /var/www/html/mailer-cli.php(18): Symfony\Component\Console\Application->run()
2020-11-29T09:14:04.977+02:00   #14 {main}
2020-11-29T09:14:04.977+02:00   thrown in /var/www/html/vendor/async-aws/core/src/Response.php on line 358
2020-11-29T09:14:04.981+02:00
Script php mailer-cli.php messenger:consume -vv --time-limit=86400 handling the messenger:consume event returned with error code 1

现在看来可以通过使用最新的稳定 aws-async/sqsaws-async/core(特别是 v1.7.0 or newer of the latter)来解决这个问题,而无需更改 Symfony Messenger 本身。

在我尝试在 PR 中修补 Messenger 后,@jderusse – 我认为他曾在上述库中工作 – suggested 这应该通过使用 RetryableHttpClient.[=16= 来解决问题]

由于 lib 的标准重试策略 includes repeating failed calls that get HTTP 500 responses 这似乎应该抓住边缘情况并且可能是最佳修复。

我们的开发分支上已经有了库更新,因此将优先发布实时更改以进行验证。

编辑:我可以确认此排序没有更改应用程序代码。