Подтвердить что ты не робот

Тайм-аут соединения Doctrine2 в демонах

У меня есть длинный демон (Symfony2 Command), который получает работу из рабочей очереди в Redis и выполняет эти задания и записывает в базу данных с помощью orm.

Я заметил, что когда есть тенденция к тому, что работник умирает, потому что соединение с MySQL истекает, когда рабочий работает на холостом ходу, ожидая работы.

В частности, я вижу это в журнале: MySQL Server ушел.

В любом случае, у меня может быть доктрина автоматически переподключиться? Или есть способ, которым я могу вручную поймать исключение и снова подключить доктрину orm?

Спасибо

4b9b3361

Ответ 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 и, в конечном итоге, данные, которые не передаются в СУБД.

Другими словами: обязательно выполняйте транзакции/откаты, если вы используете этот метод.

Ответ 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');
}

Если это чертовски, вам нужно, возможно, назвать его статически.