nalogka/doctrine-reconnect-bundle
A Symfony bundle for Doctrine that automatically detects lost database connections and reconnects them, helping long-running workers, consumers, and console commands recover from stale or dropped connections without manual intervention.
This is a Symfony bundle, not a Laravel package — there is no service provider, no config/doctrine-reconnect.php, and Composer will not auto-wire anything into a Laravel app. Treat it as a reference implementation for "reconnect Doctrine DBAL after the TCP connection dies," not as a drop-in dependency.
If you're evaluating it:
src/ in the repo first. There are only a handful of classes at most; look for the Bundle subclass, a Doctrine\Common\EventSubscriber or kernel.event_listener tag, and the reconnect logic itself. That single class is the package.composer.json for doctrine/dbal / doctrine/orm version constraints. With 0 stars and 0 dependents there is no downstream signal that it works with DBAL 4 / ORM 3, so assume it targets an older line until you verify.ConnectionException, or only on isOpen() === false / MySQL server has gone away / SQLSTATE[HY000] [2006]? The narrower the trigger, the safer it is to leave enabled.Your first real use case is long-running processes that idle past MySQL's wait_timeout: queue workers, schedule:work daemons, Swoole/Octane-style servers, or a console command that loops over records. In Laravel the same need exists, but you solve it with DB::reconnect() or DB::purge() rather than this bundle — so read the bundle for the pattern, then port it.
Port the subscriber concept into a Laravel listener. The bundle's value is the shape of the solution: listen for a failed query, test whether the connection is still alive, and if not, drop and re-establish it. In Laravel that's an event listener or a small trait on your job/command.
Reconnect before each unit of work, not after the failure. The cheapest pattern is a guard at the top of a loop iteration:
if (! DB::connection()->getPdo()) {
DB::reconnect();
}
Cheaper still, and what most bundles actually do, is to catch the exception, verify liveness with a SELECT 1, and retry the operation exactly once. Never retry in a loop — a dropped connection that stays dropped will burn the queue.
Always reset the ORM after reconnecting. If you're using Doctrine alongside Laravel, $em->clear() (or resetManager() in Symfony) is mandatory after a reconnect. The entity manager caches managed entities and prepared statements bound to the dead connection; a raw reconnect alone will leave it in a state that throws EntityManager is closed on the next flush().
Wrap it around the retryable boundary. In a job, that boundary is handle(). In a console command, it's the batch. Structure:
try {
$this->process($chunk);
} catch (ConnectionException | QueryException $e) {
if (! $this->isConnectionLoss($e)) {
throw $e;
}
DB::reconnect();
$this->process($chunk); // one retry only
}
Match the reconnect to the driver. MySQL drops idle connections at wait_timeout (default 28800s, but often 60s behind a proxy or PgBouncer). Postgres surfaces it differently (server closed the connection unexpectedly). The bundle likely hardcodes MySQL-flavoured detection — verify before reusing that predicate for Postgres or SQL Server.
DB::transactionLevel() > 0 — rethrow instead.PDOStatement you've stashed are stale after reconnect. Clear caches ($em->clear(), DB::purge($name)) rather than just calling reconnect().read/write splits, DB::reconnect() with no argument only touches the default connection. Iterate config('database.connections') or reconnect each named connection explicitly.DB::reconnect() semantics explicitly. Laravel's reconnect() closes the existing PDO and makes a new one; purge() only forgets the resolved instance. For Octane and long-lived workers, purge() followed by a fresh resolve is the more reliable pair.ConnectionException, PDOException, QueryException are all distinct paths). If the bundle swallows them, you will not know whether reconnects are frequent — and frequent reconnects mean a broken proxy or too-tight wait_timeout, which reconnecting only papers over.How can I help you explore Laravel packages today?