From 98016b3eb3b3cddad0005b9891aaedeef597e7de Mon Sep 17 00:00:00 2001 From: Brandon Li Date: Sun, 18 Oct 2026 22:21:28 -0500 Subject: [PATCH] Seed the instruments table in one immediate transaction `next build` imports lib/db.ts from several workers at once. On a fresh machine they all saw an empty instruments table and raced to insert the same symbols, failing the build with "UNIQUE constraint failed: instruments.symbol". The emptiness check and the inserts now share one IMMEDIATE transaction, and the insert is OR IGNORE as a backstop. Co-Authored-By: Claude Opus 5.5 --- lib/db.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/db.ts b/lib/db.ts index 01ad444..cb7464c 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -247,12 +247,17 @@ const SYMBOLS = ['NQ','MNQ','ES','MES','YM','MYM','RTY','M2K','GC','MGC','SI','C // from the Instruments page, they just start off. const DEFAULT_ENABLED = new Set(['NQ', 'GC', 'CL']); -// Seed instruments table if empty -const instrCount = (db.prepare('SELECT COUNT(*) as count FROM instruments').get() as { count: number }).count; -if (instrCount === 0) { - const ins = db.prepare('INSERT INTO instruments (symbol, enabled) VALUES (?, ?)'); +// Seed instruments table if empty. Check and insert share one IMMEDIATE +// transaction: `next build` imports this module from several workers at once, +// and on a fresh machine they all saw an empty table and raced to insert the +// same symbols (UNIQUE constraint failed: instruments.symbol). OR IGNORE is +// the backstop if the lock is ever skipped. +db.transaction(() => { + const instrCount = (db.prepare('SELECT COUNT(*) as count FROM instruments').get() as { count: number }).count; + if (instrCount > 0) return; + const ins = db.prepare('INSERT OR IGNORE INTO instruments (symbol, enabled) VALUES (?, ?)'); for (const s of SYMBOLS) ins.run(s, DEFAULT_ENABLED.has(s) ? 1 : 0); -} +}).immediate(); export interface InstrumentRow { symbol: string;