From 48e9c9c79aa87b5e5450c76afd00b31de6597d6c Mon Sep 17 00:00:00 2001 From: Luca <102960244+Luca-Timo@users.noreply.github.com> Date: Sun, 31 May 2026 22:43:40 +0200 Subject: [PATCH] fix(restore): re-init knex pool after DROP/CREATE DATABASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `db.destroy()` during restore tore down the in-process connection pool to release PG sessions so DROP DATABASE could succeed. After CREATE DATABASE + psql restore, the old code did `require('../database/db')` expecting a fresh instance — but Node caches require results, so it got the SAME destroyed instance back. Every subsequent query in the process failed with "Unable to acquire a connection" until the container was manually restarted, even though the restore technically succeeded. Net effect for admins: login showed "An error occurred", customer / invoice / quote pages were blank, no surface hinted at the dead pool. Cure: db.js now wraps the live knex instance in a Proxy that forwards to a mutable internal reference, with a `reinitPool()` function that destroys the old instance + builds a fresh one + probes with `SELECT 1` so any reconnect failure surfaces immediately. The thousands of existing `const { db } = require(...)` imports work unchanged — they capture the Proxy once, and every call goes through to the current pool. restoreService calls reinitPool() after CREATE DATABASE and before migrate.latest(), so the rest of the request + every subsequent admin action runs against the fresh pool. Container restart no longer needed after restore. --- backend/src/services/restoreService.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/backend/src/services/restoreService.js b/backend/src/services/restoreService.js index a17ecc52..fb6d31ac 100644 --- a/backend/src/services/restoreService.js +++ b/backend/src/services/restoreService.js @@ -954,12 +954,27 @@ END $$;` this.log('info', 'Sequence resync completed'); } - // Re-initialize database connection - const { db: newDb } = require('../database/db'); - - // Run migrations to ensure schema is up to date + // Re-initialize the in-process knex pool. The DROP/CREATE + // DATABASE pair above destroyed our connections and the recreated + // database has a different pg_database OID — any pooled + // connection from before would either be dead or pointed at a + // ghost. Without explicit reinit, every query in the process + // after restore returns `Error: Unable to acquire a connection` + // until the container is manually restarted (and admin sees + // "An error occurred" on the login screen even after the restore + // technically succeeded). reinitPool destroys + rebuilds the + // pool and probes the new one with `SELECT 1` so failures here + // surface immediately instead of polluting the next request. + const { reinitPool } = require('../database/db'); + this.log('info', 'Re-initializing knex pool against the restored database...'); + await reinitPool(); + this.log('info', 'Knex pool re-initialized'); + + // Run migrations to ensure schema is up to date. Use the + // module-level `db` export, which is the Proxy that now points + // at the freshly-initialized pool. this.log('info', 'Running database migrations...'); - await newDb.migrate.latest(); + await db.migrate.latest(); return { success: true };