如何解决能否允许 Messenger 的消耗命令从 SQS 消息读取失败中恢复?
我正在处理 a simple microservice,我们已将它们放在一起排队并发送电子邮件。在实时环境中,队列目前通过最新的 Symfony Messenger 组件 (v5.2.x) 及其 SQS 桥使用 SQS。
这通常运行良好,但偶尔(大约每隔几周)我们会看到 SQS 向使用者/工作人员返回一个流氓 500 服务器错误,这是一个运行 Messenger 的现成的 ECS 服务 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 原生的 TransportException
,但传入原始 AWS 异常以供 Messenger 处理,因为它认为合适 –然后有些东西(我还没有完全弄清楚)似乎稍后会重新抛出它,导致致命的未处理异常。
感觉可能有一种不同的行为可以用来代替强制退出到 ConsumeMessagesCommand
,也许通过配置一个稍微不同的接收器,或者通过提议改变 SQS 处理这个问题的方式如果一致认为其他东西对大多数用例更好。我很高兴尝试研究后者,但我觉得我对 Messenger 的一些类及其预期用途的理解到目前为止有点薄弱。我注意到最近添加了新的 RecoverableExceptionInterface
,但我不知道将它用于像这样的接收器是否在预期范围内。
我快速浏览了将 AmazonSqsReceiver
扩展为仅调整 get()
而无需维护完全独立的 Receiver,但由于 Connection
之类的属性是私有的,因此很快就会变得混乱。
我认为我在错误情况下的理想结果是要么:
- 来自 SQS 的单个
HttpException
将导致get()
被重试 X 次,其中可能有可配置的暂停 Y 毫秒 - 只有在 X 次连续失败后,我们才会抛出
TransportException
或
- 失败会抛出
TransportException
但这会将消息 ID 放入某种失败/死信队列中,以便通过原始接收器使用的相同连接进行 X 次重试——但我不确定 Messenger 是否重新-排队模型是这样工作的,当消息在消费者中获取本身失败时?感觉就像我们可能没有必要的信息以有组织的 Messenger 队列方式重新排队,如果我们无法读取超出我们要求 SQS 的 ID 的消息详细信息。
任何想法都非常感谢 - 关于这是否按设计运行,以及如果是这样我可以做些什么来解决它!
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/sqs
和 aws-async/core
(特别是 v1.7.0 or newer of the latter)来解决这个问题,而无需更改 Symfony Messenger 本身。
在我尝试在 PR 中修补 Messenger 之后,@jderusse(我认为他在上述库上工作过)suggested 这应该通过使用 RetryableHttpClient
来解决问题。
由于 lib 的标准重试策略 includes repeating failed calls that get HTTP 500 responses,这似乎应该可以捕获边缘情况,并且可能是最佳解决方案。
我们的开发分支已经有了库更新,因此将优先发布实时更改以进行验证。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。