使用学说的 Symfony 4 工作人员无法正常工作:SQLSTATE[HY000] [2002] 连接超时
Symfony 4 worker using doctrine not working properly : SQLSTATE[HY000] [2002] Connection timed out
我正在使用带有 Symfony 4 Messenger 组件的 worker。
这个工人是
- 正在接收消息(来自 rabbitMQ)
- 启动 ffmpeg
- 对视频进行处理
- 并在数据库中保存一些东西。
为了在 Symfony 上配置这个 worker,我已经这样做了(中间件很重要):
// config/packages/framework.yaml
framework:
messenger:
buses:
command_bus:
middleware:
# each time a message is handled, the Doctrine connection
# is "pinged" and reconnected if it's closed. Useful
# if your workers run for a long time and the database
# connection is sometimes lost
- doctrine_ping_connection
# After handling, the Doctrine connection is closed,
# which can free up database connections in a worker,
# instead of keeping them open forever
- doctrine_close_connection
transports:
ffmpeg:
dsn: '%env(CLOUDAMQP_URL)%'
options:
auto_setup: false
exchange:
name: amq.topic
type: topic
queues:
ffmpeg: ~
routing:
# Route your messages to the transports, for now all are AMQP messages
'App\Api\Message\AMQPvideoFFMPEG': ffmpeg
## Handle multiple buses ? https://symfony.com/doc/current/messenger/multiple_buses.html
## When queries and command should be distinguished
然后为了了解可能导致此问题的原因,我尝试调试 Messenger 以查看中间件是否已正确配置
root@b9eec429cb54:/var/www/html# php bin/console debug:messenger
Messenger
=========
command_bus
-----------
The following messages can be dispatched:
------------------------------------------------------
App\Api\Message\AMQPvideoFFMPEG
handled by App\Api\Message\Handler\FFMPEGHandler
------------------------------------------------------
一切似乎都还好吧?
所以怎么可能看到这个:
[2019-08-23 10:25:26] messenger.ERROR: Retrying App\Api\Message\AMQPvideoFFMPEG - retry #1. {"message":"[object] (App\Api\Message\AMQPvideoFFMPEG: {})","class":"App\Api\Message\AMQPvideoFFMPEG","retryCount":1,"error":"[object] (Doctrine\DBAL\Exception\ConnectionException(code: 0): An exception occurred in driver: SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:93, Doctrine\DBAL\Driver\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:27)"} []
我完全迷路了,我错过了什么吗?
这有时会发生,但大部分时间都有效,我想这个错误发生在我的工作人员失去与数据库的连接时,尤其是当 ffmpeg 处理持续 7 分钟或更长时间时,但这应该通过 ping 和关闭连接的中间件。所以我不清楚这里的问题是什么。
阅读我的中间件代码,尤其是这个块后
class DoctrinePingConnectionMiddleware extends AbstractDoctrineMiddleware
{
protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope
{
$connection = $entityManager->getConnection();
if (!$connection->ping()) {
$connection->close();
$connection->connect();
}
if (!$entityManager->isOpen()) {
$this->managerRegistry->resetManager($this->entityManagerName);
}
return $stack->next()->handle($envelope, $stack);
}
}
我们可以看到我的处理程序在连接打开后立即被调用。
这种行为应该有效,我认为它是,但 FFMPEG 可以在很长一段时间内使用相同的 RabbitMQ 消息工作。因此,我的处理程序将某些内容插入数据库的最后一步可以提供 mySQL 已经消失的错误,或者连接超时。
这就是为什么,我将这个片段放入一个方法中,而不调用处理程序,只调用与学说连接相关的代码,然后我在插入我的数据库之前调用它,如下所示:
public function __invoke(AMQPvideoFFMPEG $message)
{
// reset connection if not found
$this->processService->testConnection();
$process = $this->processService->find($message->getProcess());
$this->renderServcie->updateQueue($process->getQueue(), "processing");
// some other stuff
}
其中 testConnection() 方法是
/**
* Reconnect if connection is aborted for some reason
*/
public function testConnection()
{
$connection = $this->entityManager->getConnection();
if (!$connection->ping()) {
$connection->close();
$connection->connect();
}
}
但在那之后我又尝试了另一个问题
Resetting a non-lazy manager service is not supported. Set the
"doctrine.orm.default_entity_manager" service as lazy and require
"symfony/proxy-manager-bridge" in your composer.json file instead.
安装 "symfony/proxy-manager-bridge" 后,错误消失了。
到目前为止,还没有遇到连接超时的情况。拭目以待。
在任何插入操作之前简单地断开连接:
public function handle(…)
{
// your time-consuming business logic
// disconnect if needed
if (!$this->entityManager->getConnection()->ping()) {
$this->entityManager->getConnection()->close();
}
// save your work
$this->entityManager->flush();
}
我正在使用带有 Symfony 4 Messenger 组件的 worker。
这个工人是
- 正在接收消息(来自 rabbitMQ)
- 启动 ffmpeg
- 对视频进行处理
- 并在数据库中保存一些东西。
为了在 Symfony 上配置这个 worker,我已经这样做了(中间件很重要):
// config/packages/framework.yaml
framework:
messenger:
buses:
command_bus:
middleware:
# each time a message is handled, the Doctrine connection
# is "pinged" and reconnected if it's closed. Useful
# if your workers run for a long time and the database
# connection is sometimes lost
- doctrine_ping_connection
# After handling, the Doctrine connection is closed,
# which can free up database connections in a worker,
# instead of keeping them open forever
- doctrine_close_connection
transports:
ffmpeg:
dsn: '%env(CLOUDAMQP_URL)%'
options:
auto_setup: false
exchange:
name: amq.topic
type: topic
queues:
ffmpeg: ~
routing:
# Route your messages to the transports, for now all are AMQP messages
'App\Api\Message\AMQPvideoFFMPEG': ffmpeg
## Handle multiple buses ? https://symfony.com/doc/current/messenger/multiple_buses.html
## When queries and command should be distinguished
然后为了了解可能导致此问题的原因,我尝试调试 Messenger 以查看中间件是否已正确配置
root@b9eec429cb54:/var/www/html# php bin/console debug:messenger
Messenger
=========
command_bus
-----------
The following messages can be dispatched:
------------------------------------------------------
App\Api\Message\AMQPvideoFFMPEG
handled by App\Api\Message\Handler\FFMPEGHandler
------------------------------------------------------
一切似乎都还好吧?
所以怎么可能看到这个:
[2019-08-23 10:25:26] messenger.ERROR: Retrying App\Api\Message\AMQPvideoFFMPEG - retry #1. {"message":"[object] (App\Api\Message\AMQPvideoFFMPEG: {})","class":"App\Api\Message\AMQPvideoFFMPEG","retryCount":1,"error":"[object] (Doctrine\DBAL\Exception\ConnectionException(code: 0): An exception occurred in driver: SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:93, Doctrine\DBAL\Driver\PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 2002): SQLSTATE[HY000] [2002] Connection timed out at /var/www/html/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:27)"} []
我完全迷路了,我错过了什么吗?
这有时会发生,但大部分时间都有效,我想这个错误发生在我的工作人员失去与数据库的连接时,尤其是当 ffmpeg 处理持续 7 分钟或更长时间时,但这应该通过 ping 和关闭连接的中间件。所以我不清楚这里的问题是什么。
阅读我的中间件代码,尤其是这个块后
class DoctrinePingConnectionMiddleware extends AbstractDoctrineMiddleware
{
protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope
{
$connection = $entityManager->getConnection();
if (!$connection->ping()) {
$connection->close();
$connection->connect();
}
if (!$entityManager->isOpen()) {
$this->managerRegistry->resetManager($this->entityManagerName);
}
return $stack->next()->handle($envelope, $stack);
}
}
我们可以看到我的处理程序在连接打开后立即被调用。 这种行为应该有效,我认为它是,但 FFMPEG 可以在很长一段时间内使用相同的 RabbitMQ 消息工作。因此,我的处理程序将某些内容插入数据库的最后一步可以提供 mySQL 已经消失的错误,或者连接超时。
这就是为什么,我将这个片段放入一个方法中,而不调用处理程序,只调用与学说连接相关的代码,然后我在插入我的数据库之前调用它,如下所示:
public function __invoke(AMQPvideoFFMPEG $message)
{
// reset connection if not found
$this->processService->testConnection();
$process = $this->processService->find($message->getProcess());
$this->renderServcie->updateQueue($process->getQueue(), "processing");
// some other stuff
}
其中 testConnection() 方法是
/**
* Reconnect if connection is aborted for some reason
*/
public function testConnection()
{
$connection = $this->entityManager->getConnection();
if (!$connection->ping()) {
$connection->close();
$connection->connect();
}
}
但在那之后我又尝试了另一个问题
Resetting a non-lazy manager service is not supported. Set the "doctrine.orm.default_entity_manager" service as lazy and require "symfony/proxy-manager-bridge" in your composer.json file instead.
安装 "symfony/proxy-manager-bridge" 后,错误消失了。
到目前为止,还没有遇到连接超时的情况。拭目以待。
在任何插入操作之前简单地断开连接:
public function handle(…)
{
// your time-consuming business logic
// disconnect if needed
if (!$this->entityManager->getConnection()->ping()) {
$this->entityManager->getConnection()->close();
}
// save your work
$this->entityManager->flush();
}