[英]Library error: a socket error occurred in Symfony Messenger
In my Symfony project, there is a queue message handler, and I have an error that randomly appears during the execution:在我的Symfony项目中,有一个queue message handler,我在执行过程中随机出现一个错误:
[2022-10-12T07:31:40.060119+00:00] console.CRITICAL: Error thrown while running command "messenger:consume async --limit=10". Message: "Library error: a socket error occurred" {"exception":"[object] (Symfony\\Component\\Messenger\\Exception
TransportException(code: 0): Library error: a socket error occurred at /var/www/app/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php:62)
[previous exception] [object] (AMQPException(code: 0): Library error: a socket error occurred at /var/www/app/vendor/symfony/amqp-messenger/Transport/Connection.php:439)","command":"messenger:consume async --limit=10","message":"Library error: a socket error occurred"} []
The handler executes HTTP requests that could last some seconds and the whole process of a single message could even take more than one minute if APIs are slow.处理程序执行 HTTP 个请求,可能持续几秒钟,如果 API 速度慢,则单个消息的整个过程甚至可能需要一分钟以上。 The strange thing is that the problem disappears for hours but then it randomly appears again.
奇怪的是问题消失了几个小时,然后又随机出现了。 The more messages are sent to the queue, the easier it's to see the exception.
发送到队列的消息越多,就越容易看到异常。
config\packages\messenger.yaml配置\包\信使.yaml
framework:
messenger:
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async:
dsn: "%env(MESSENGER_TRANSPORT_DSN)%"
options:
exchange:
name: async_exchange
queues:
async: ~
heartbeat: 45
write_timeout: 90
read_timeout: 90
retry_strategy:
max_retries: 0
routing:
# Route your messages to the transports
'App\Message\MessageUpdateRequest': async
App\MessageHandler\MessageUpdateRequestHandler.php App\MessageHandler\MessageUpdateRequestHandler.php
<?php
declare(strict_types=1);
namespace App\MessageHandler;
use App\Message\MessageUpdateRequest;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class MessageUpdateRequestHandler implements MessageHandlerInterface
{
public function __invoke(MessageUpdateRequest $message)
{
// Logic executing API requests...
return 0;
}
}
Environment环境
Things that I tried我尝试过的事情
heartbeat
, write_timeout
and read_timeout
in the messenger.yaml
file.messenger.yaml
文件中添加以下选项: heartbeat
、 write_timeout
和read_timeout
。 Related issues/links相关问题/链接
How can I fix this issue?我该如何解决这个问题?
Regarding a socket error that occurs in Symfony Messenger, I always suggest following the step-wise approach and checking if you are missing anything.关于 Symfony Messenger 中发生的套接字错误,我始终建议遵循逐步方法并检查是否遗漏任何内容。 It should fix this type of error almost every time.
它几乎每次都应该修复此类错误。 Please follow these guidelines:
请遵循以下准则:
messenger.yaml
file are accurate.messenger.yaml
文件中列出的主机名、端口、用户名和密码是否准确。messenger.yaml
file, increase the heartbeat, write timeout, and read timeout settings.messenger.yaml
文件中,增加心跳、写超时、读超时设置。messenger.yaml
is appropriate.messenger.yaml
中的最大重试次数是否合适。MessageUpdateRequestHandler
class's logic.MessageUpdateRequestHandler
类的逻辑是否有问题。 Tip: Still stuck?提示:仍然卡住了? Try to reproduce the error with a smaller message set and in a controlled environment to isolate the root cause that we may be missing.
尝试使用较小的消息集并在受控环境中重现错误,以隔离我们可能遗漏的根本原因。
Hope it helps.希望能帮助到你。 Happy debugging and good luck.
调试愉快,祝你好运。
(May not be answer, but too long for comment. I don't use Symphony so can't test, but do a lot with queues.) (可能不是答案,但评论时间太长。我不使用 Symphony,所以无法测试,但对队列做了很多。)
In this code ( https://github.com/surfingmig/symfony/blob/608f4dade49f2f0367380d37c946b4a6a3d3985c/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php ) there is no verification that the connection is still alive before the ack()
;在此代码中( https://github.com/surfingmig/symfony/blob/608f4dade49f2f0367380d37c946b4a6a3d3985c/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php )在验证连接之前仍然没有活动
ack()
; everything is stored in locally held variables and they are only checked before get and send.所有内容都存储在本地变量中,并且仅在获取和发送之前进行检查。
I suggest you copy我建议你复制
$this->clearWhenDisconnected();
if ($this->autoSetupExchange) {
$this->setupExchangeAndQueues(); // also setup normal exchange for delayed messages so delay queue can DLX messages to it
}
from get()
into the top of the ack()
function.从
get()
到ack()
的顶部 function。
If that works, also copy to the nack()
, purge()
and countMessagesInQueues()
functions, or make a common function "checkStillConnected()" then turn into a pull request.如果可行,还可以复制到
nack()
、 purge()
和countMessagesInQueues()
函数,或者创建一个通用的 function “checkStillConnected()”,然后变成拉取请求。
Note: You will still get exceptions (there is always a gap between "am I connected", and "ack()", even if microseconds, where disconnect can happen).注意:您仍然会遇到异常(“我是否已连接”和“ack()”之间始终存在差距,即使是微秒,也可能发生断开连接)。 So a retry handler in your code as well would be appropriate.
因此,您的代码中的重试处理程序也是合适的。 I try three times before giving up.
在放弃之前,我尝试了三次。
(Other note: one of those change requests linked is only a stop-gap solution that triggers under certain conditions, but will miss most issues.) (另请注意:其中一个链接的变更请求只是在特定条件下触发的权宜之计解决方案,但会遗漏大多数问题。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.