20

我有一个长时间运行的守护进程(Symfony2 命令),它从 Redis 中的工作队列中获取工作,并使用 orm 执行这些工作并写入数据库。

我注意到,当工作人员空闲等待工作时,由于与 MySQL 的连接超时,工作人员有死亡的趋势。

具体来说,我在日志中看到了这一点:MySQL Server has gone away。

无论如何我可以让学说自动重新连接吗?或者有什么方法可以手动捕获异常并重新连接学说 orm?

谢谢

4

5 回答 5

29

我在我的 symfony2 beanstalkd 守护进程命令工作者中使用它:

$em = $this->getContainer()->get('doctrine')->getManager();
if ($em->getConnection()->ping() === false) {
    $em->getConnection()->close();
    $em->getConnection()->connect();
}
于 2014-11-06T23:15:12.947 回答
12

看来,只要 EntityManager 在 Doctrine 中遇到任何错误/异常,连接就会关闭并且 EntityManager 已死。

由于通常所有内容都包含在事务中,并且在调用 $entityManager->flush() 时执行该事务,因此您可以尝试捕获异常并尝试重新执行或放弃。

您可能希望通过更具体的类型捕获来检查异常的确切性质,无论是 PDOException 还是其他。

对于 MySQL has Gone Away 异常,您可以尝试通过重置 EntityManager 来重新连接。

$managerRegistry = $this->getContainer()->get('doctrine');
$em = $managerRegistry->getEntityManager();
$managerRegistry->resetEntityManager();

这应该使 $em 再次可用。请注意,您必须再次重新持久化所有内容,因为这个 $em 是新的。

于 2013-01-02T17:32:41.963 回答
9

我对 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。

换句话说:如果您使用此方法,请务必提交/回滚事务。

于 2013-08-02T13:54:39.253 回答
5

这个包装器对我有用:

https://github.com/doctrine/dbal/issues/1454

于 2013-04-21T13:33:21.340 回答
2

在您的守护程序中,您可以在每次查询之前添加重新启动连接的方法。我在使用 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,您可能需要静态调用它。

于 2013-06-07T12:13:57.140 回答