我有一个长时间运行的守护进程(Symfony2 命令),它从 Redis 中的工作队列中获取工作,并使用 orm 执行这些工作并写入数据库。
我注意到,当工作人员空闲等待工作时,由于与 MySQL 的连接超时,工作人员有死亡的趋势。
具体来说,我在日志中看到了这一点:MySQL Server has gone away。
无论如何我可以让学说自动重新连接吗?或者有什么方法可以手动捕获异常并重新连接学说 orm?
谢谢
我有一个长时间运行的守护进程(Symfony2 命令),它从 Redis 中的工作队列中获取工作,并使用 orm 执行这些工作并写入数据库。
我注意到,当工作人员空闲等待工作时,由于与 MySQL 的连接超时,工作人员有死亡的趋势。
具体来说,我在日志中看到了这一点:MySQL Server has gone away。
无论如何我可以让学说自动重新连接吗?或者有什么方法可以手动捕获异常并重新连接学说 orm?
谢谢
我在我的 symfony2 beanstalkd 守护进程命令工作者中使用它:
$em = $this->getContainer()->get('doctrine')->getManager();
if ($em->getConnection()->ping() === false) {
$em->getConnection()->close();
$em->getConnection()->connect();
}
看来,只要 EntityManager 在 Doctrine 中遇到任何错误/异常,连接就会关闭并且 EntityManager 已死。
由于通常所有内容都包含在事务中,并且在调用 $entityManager->flush() 时执行该事务,因此您可以尝试捕获异常并尝试重新执行或放弃。
您可能希望通过更具体的类型捕获来检查异常的确切性质,无论是 PDOException 还是其他。
对于 MySQL has Gone Away 异常,您可以尝试通过重置 EntityManager 来重新连接。
$managerRegistry = $this->getContainer()->get('doctrine');
$em = $managerRegistry->getEntityManager();
$managerRegistry->resetEntityManager();
这应该使 $em 再次可用。请注意,您必须再次重新持久化所有内容,因为这个 $em 是新的。
我对 PHP Gearman worker 和 Doctrine 2 有同样的问题。
我想出的最干净的解决方案是:在每个作业中关闭并重新打开连接:
<?php
public function doWork($job){
/* @var $em \Doctrine\ORM\EntityManager */
$em = Zend_Registry::getInstance()->entitymanager;
$em->getConnection()->close();
$em->getConnection()->connect();
}
更新
上面的解决方案不能处理事务状态。这意味着 Doctrine\DBAL\Connection::close() 方法不会重置 $_transactionNestingLevel 值,因此如果您不提交事务,这将导致 Doctrine 与底层 DBMS 的翻译状态不同步. 这可能会导致 Doctrine 默默地忽略开始/提交/回滚语句,并最终导致数据不提交给 DBMS。
换句话说:如果您使用此方法,请务必提交/回滚事务。
这个包装器对我有用:
在您的守护程序中,您可以在每次查询之前添加重新启动连接的方法。我在使用 gaerman worker 时遇到了类似的问题:
我将连接数据保存在 zend 注册表中,所以它看起来像这样:
private function resetDoctrineConnection() {
$doctrineManager = Doctrine_Manager::getInstance();
$doctrineManager->reset();
$dsn = Zend_Registry::get('dsn');
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
Doctrine_Manager::connection($dsn, 'doctrine');
}
如果它是 damenon,您可能需要静态调用它。