Тайм-аут соединения Doctrine2 в демонах
У меня есть длинный демон (Symfony2 Command), который получает работу из рабочей очереди в Redis и выполняет эти задания и записывает в базу данных с помощью orm.
Я заметил, что когда есть тенденция к тому, что работник умирает, потому что соединение с MySQL истекает, когда рабочий работает на холостом ходу, ожидая работы.
В частности, я вижу это в журнале: MySQL Server ушел.
В любом случае, у меня может быть доктрина автоматически переподключиться? Или есть способ, которым я могу вручную поймать исключение и снова подключить доктрину orm?
Спасибо
Ответы
Ответ 1
Похоже, что всякий раз, когда в Doctrine возникает ошибка/исключение, встречающееся EntityManager, соединение закрывается и EntityManager мертв.
Так как в целом транзакция завершается транзакцией и эта транзакция выполняется при вызове метода $entityManager- > flush(), вы можете попытаться поймать исключение и попытаться повторно удалить или отказаться.
Вы можете изучить точный характер исключения с более конкретным уловом типа, будь то PDOException или что-то еще.
Для исключения MySQL исключен Gone Away, вы можете попытаться восстановить соединение, сбросив EntityManager.
$managerRegistry = $this->getContainer()->get('doctrine');
$em = $managerRegistry->getEntityManager();
$managerRegistry->resetEntityManager();
Это должно снова использовать $em. Обратите внимание, что вам нужно будет повторно сохранить все снова, так как этот $em является новым.
Ответ 2
Я использую это в своем Symfony2 beanstalkd daemon Командный рабочий:
$em = $this->getContainer()->get('doctrine')->getManager();
if ($em->getConnection()->ping() === false) {
$em->getConnection()->close();
$em->getConnection()->connect();
}
Ответ 3
У меня была такая же проблема с работником PHP Gearman и 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() не означает reset значение $_transactionNestingLevel, поэтому, если вы не совершаете транзакцию, это приведет к тому, что Doctrine не синхронизируется с состоянием трансляции с помощью базовой СУБД. Это может привести к тому, что Doctrine молча игнорирует операторы start/commit/rollback и, в конечном итоге, данные, которые не передаются в СУБД.
Другими словами: обязательно выполняйте транзакции/откаты, если вы используете этот метод.
Ответ 4
Это с этой оберткой для меня работало:
https://github.com/doctrine/dbal/issues/1454
Ответ 5
В вашем демоне вы можете добавить метод для перезапуска соединения, возможно, перед каждым запросом. Я столкнулся с подобными проблемами, используя 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');
}
Если это чертовски, вам нужно, возможно, назвать его статически.