MySQL соединение имеет свойство закрываться в долго висящих процессах, например демонах. Время, которое висит соединение задается в MySQL конфиге.
Один из выходов получить постоянное соединение это использовать persistent connection, что так же имеет свои минусы. Как же решить проблему с обычным соединением используя Doctrine 2 ?
Вообще ноги у проблемы растут издавна. Погуглив легко найти баг репорт еще для версии Doctrine 2.1.6.
http://www.doctrine-project.org/jira/browse/DBAL-275
Там же в приложенных файлах есть предлагаемое решение проблемы – своя обертка для драйвера, которая пробует переподключиться.
Но дело в том, что такое поведение не может быть принято по умолчанию, видимо по этому разработчики Doctrine тянули аж до 2.5 версии с закрытием бага.
В этом же репорте есть очень полезная ссылка по которой автор детально описал свой путь борьбы с проблемой
http://circlical.com/blog/2013/9/12/mysql-server-has-gone-away-atop-doctrine2-and-zend-framework-2
Да, кстати я столкнулся с этим тоже в контексте Zend Framework 2, поэтому первым, что я попробовал – это вот это адаптированное решение из поста выше в виде Zend модуля.
https://github.com/bushbaby/BsbDoctrineReconnect
К сожалению оно мне не помогло. Я не утверждаю, что решение не рабочее, но конкретно в моем случае не сработало. В итоге я обнаружил (уже позже, когда вернулся к вопросу) что в версии Doctrine 2.5 баг был закрыт. Разработчики добавили метод ping() и возможность программистам самостоятельно решать что делать с соединением.
Следующий код я использую в модели, где используется Doctrine Entity Manager и ошибки MYSQL SERVER HAS GONE AWAY больше нет. :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
public function disconnect() { $this->getEm()->getConnection()->close(); } public function connect() { $this->getEm()->getConnection()->connect(); } /** * MySQL Server has gone away */ public function reconnect() { Debug::vars(__METHOD__); $connection = $this->getEm()->getConnection(); if (!$connection->ping()) { Debug::vars("MySQL ping failed"); $this->disconnect(); $this->connect(); $this->checkEMConnection($connection); } } /** * method checks connection and reconnect if needed * MySQL Server has gone away * * @param $connection * @throws \Doctrine\ORM\ORMException */ protected function checkEMConnection($connection) { Debug::vars(__METHOD__); if (!$this->getEm()->isOpen()) { $config = $this->getEm()->getConfiguration(); $this->em = $this->getEm()->create( $connection, $config ); } } |
Для проверки я оставил на ночь демон в виде Gearman worker и примерно через 12-14 часов выполнил на нем работу, соединение с MySQL было установлено без ошибок.