能否允许 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
等属性是私有的,因此很快就会变得混乱。
我认为我在错误情况下的理想结果是 或者:
- 来自 SQS 的单个
HttpException
将导致 get()
被重试 X 次,可能在 之间有一个可配置的暂停 Y 毫秒
- 只有在 X 次连续失败后,我们才会抛出
TransportException
或
- 失败会抛出一个
TransportException
但这会将消息 ID 放入某种 failure/dead 字母队列中,以便通过原始接收者使用的相同连接进行 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
.[=16= 来解决问题]
由于 lib 的标准重试策略 includes repeating failed calls that get HTTP 500 responses 这似乎应该抓住边缘情况并且可能是最佳修复。
我们的开发分支上已经有了库更新,因此将优先发布实时更改以进行验证。
编辑:我可以确认此排序没有更改应用程序代码。
我正在研究 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
等属性是私有的,因此很快就会变得混乱。
我认为我在错误情况下的理想结果是 或者:
- 来自 SQS 的单个
HttpException
将导致get()
被重试 X 次,可能在 之间有一个可配置的暂停 Y 毫秒
- 只有在 X 次连续失败后,我们才会抛出
TransportException
或
- 失败会抛出一个
TransportException
但这会将消息 ID 放入某种 failure/dead 字母队列中,以便通过原始接收者使用的相同连接进行 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
.[=16= 来解决问题]
由于 lib 的标准重试策略 includes repeating failed calls that get HTTP 500 responses 这似乎应该抓住边缘情况并且可能是最佳修复。
我们的开发分支上已经有了库更新,因此将优先发布实时更改以进行验证。
编辑:我可以确认此排序没有更改应用程序代码。