web-dev-qa-db-ja.com

デーモンのDoctrine2接続タイムアウト

Redisのワークキューから作業を取得し、それらのジョブを実行してormを使用してデータベースに書き込む、長時間実行されているデーモン(Symfony2コマンド)があります。

ワーカーが仕事を待ってアイドリングしているときにMySQLへの接続がタイムアウトしたために、ワーカーが死ぬ傾向があることに気づきました。

具体的には、ログにこれが表示されます。MySQLサーバーがなくなりました。

とにかくdoctrine自動的に再接続することができますか?または手動で例外をキャッチしてdoctrine ormを再接続する方法はありますか?

ありがとう

19
James Cowhen

DoctrineのEntityManagerでエラー/例外が発生すると、接続が閉じられ、EntityManagerが停止しているようです。

通常、すべてがトランザクションにラップされ、そのトランザクションは$ entityManager-> flush()が呼び出されたときに実行されるため、例外をキャッチして再実行またはあきらめることができます。

PDOExceptionであるかどうかにかかわらず、タイプをより具体的にキャッチして、例外の正確な性質を調べることをお勧めします。

MySQLにGoneAway例外がある場合は、EntityManagerをリセットして再接続を試みることができます。

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

これにより、$ emが再び使用可能になります。この$ emは新しいため、すべてを再度永続化する必要があることに注意してください。

12
James Cowhen

私はこれをsymfony2beanstalkdデーモンで使用していますコマンドワーカー:

$em = $this->getContainer()->get('doctrine')->getManager();
if ($em->getConnection()->ping() === false) {
    $em->getConnection()->close();
    $em->getConnection()->connect();
}
24
tomcyr

PHPギアマンワーカーと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 begin/commit/rollbackステートメントがサイレントに無視され、最終的にデータがDBMSにコミットされなくなる可能性があります。

つまり、この方法を使用する場合は、必ずトランザクションをコミット/ロールバックしてください。

8
paul.ago

これはこのラッパーで私のために働いた:

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

5
blackuprise

デーモンでは、おそらくすべてのクエリの前に接続を再開するメソッドを追加できます。私はgaermanworkerを使用して同様の問題に直面していました:

接続データを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');
}

それがダメノンであるならば、あなたはおそらくそれを静的に呼ぶ必要があります。

2
Amorphous