Doctrine Database Connection Fails in Gearman Worker

Aug 30, 2016 php
This post is more than 18 months old. Since technology changes too rapidly, this content may be out of date (but that's not always the case). Please remember to verify any technical or programming information with the current release.

One of the things that was really bothering me when I first started using Gearman was my consistently failing doctrine database connection.

At first it seemed like it was randomly dropping the connection. Then, I noticed that it was after the gearman job had been running for a while. This makes sense - and I also decided that I don’t want to keep a database connection connected the entire time of my job either (entire time == forever basically). Oh - and finally - my entire application bootstrap consisted of connecting to the database on each request - and that bootstrap was used in my gearman worker.

So - since I was using Doctrine, I had some helpers from their DBAL. I made the following function:

/** @var \Doctrine\ORM\EntityManager $em */
$em = $container['em'];

$dbWakeUp = function() use ($em) {
  try {
    if (!$em->getConnection()->ping()) {
      $em->getConnection()->close();
      $em->getConnection()->connect();
    }
  }
  catch (\PDOException $pe) {
    $em->getConnection()->close();
    $em->getConnection()->connect();
    if (!$em->getConnection()->ping()) {
      throw $pe;
    }
  }
};

This function takes the entity manager into the current context. It’s very simple - it does a try-catch against pinging the database to verify a database connection. If this fails or throws an exception, close the connection (which is more of an internal state than an actual connection) - then connect. Now, if it fails, we do the same thing again and try a ping again. If that fails, then we know something’s wrong with the database and we’ll throw the exception.

Now, let’s see how this is actually used. The following code is in my gearman-worker.php file which is one of the workers that is registered with gearman.

$worker = new GearmanWorker();

$worker->addFunction('send-message', function(GearmanJob $job) use ($messageService) {
  $dbWakeUp();
  $messageService->sendById($job->workload());
});

This way - every time that this job is ran, the first thing it does is validate that the database is connected and responding.

Go to All Posts