fix: open sqlite lazily so parallel build workers stop locking the file

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ahmed mohammed
2026-09-22 07:56:18 +03:00
co-authored by Claude Opus 4.7
parent 396b0edd9e
commit 13bd2e6bfd
+18 -3
View File
@@ -5,9 +5,15 @@ import { randomUUID } from "node:crypto";
const dir = process.env.DATA_DIR ?? "data";
mkdirSync(dir, { recursive: true });
const g = globalThis as { __qaiDb?: DatabaseSync };
export const db = (g.__qaiDb ??= (() => {
// Open on first query, not at import: `next build` imports every page through lib/auth -> lib/db in ~6 parallel
// workers, and six processes running DDL against one file at once fails with "database is locked".
let _db: DatabaseSync | null = null;
function openDb(): DatabaseSync {
if (_db) return _db;
const d = new DatabaseSync(`${dir}/qai.db`);
d.exec(`
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;`);
d.exec(`
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS users (
@@ -25,8 +31,17 @@ export const db = (g.__qaiDb ??= (() => {
status TEXT NOT NULL DEFAULT 'running', error TEXT,
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL);
CREATE INDEX IF NOT EXISTS ix_analyses_user ON analyses(user_id, created_at DESC);`);
_db = d;
return d;
})());
}
// Proxy keeps the terse call sites (db.prepare) while deferring the open; methods must be bound to the real
// instance or node:sqlite rejects the receiver ("Illegal invocation").
export const db: DatabaseSync = new Proxy({} as DatabaseSync, {
get: (_t, k) => {
const v = (openDb() as any)[k];
return typeof v === "function" ? v.bind(openDb()) : v;
},
});
const now = () => Date.now();
type Row = string | number | null;