[object Object]

← back to Mfr Review Viewer Corruption

yoloforever c1 (Cody fix): single-flight lock in enrich-suggestions — concurrent rebuild-triggered runs can't race + corrupt queue.jsonl

d32eae4518a6a8a2f4d57827d5b1fe4698d1a4f8 · 2026-08-28 00:45:04 -0700 · Steve Abrams

Files touched

Diff

commit d32eae4518a6a8a2f4d57827d5b1fe4698d1a4f8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 28 00:45:04 2026 -0700

    yoloforever c1 (Cody fix): single-flight lock in enrich-suggestions — concurrent rebuild-triggered runs can't race + corrupt queue.jsonl
---
 scripts/enrich-suggestions.mjs | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/scripts/enrich-suggestions.mjs b/scripts/enrich-suggestions.mjs
index fa59795..d446250 100644
--- a/scripts/enrich-suggestions.mjs
+++ b/scripts/enrich-suggestions.mjs
@@ -10,12 +10,28 @@
 //   node scripts/enrich-suggestions.mjs --limit 50   # sample
 //   node scripts/enrich-suggestions.mjs --force      # re-enrich even filled rows
 
-import { readFileSync, writeFileSync, existsSync } from 'node:fs';
+import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'node:fs';
 import { fileURLToPath } from 'node:url';
 import { dirname, join } from 'node:path';
 
 const __dir = dirname(fileURLToPath(import.meta.url));
 const QUEUE = join(__dir, '..', 'data', 'queue.jsonl');
+
+// ---- SINGLE-FLIGHT LOCK (Cody, cycle 1): two enrichers writing queue.jsonl at once
+// (e.g. ↻ Rebuild clicked twice) would race on the full-file rewrite and lose updates.
+// Take a lock; a stale lock (>2h, a crashed run) is reclaimed. Released on exit.
+const LOCK = join(__dir, '..', 'data', '.enrich.lock');
+if (existsSync(LOCK)) {
+  let age = Infinity;
+  try { age = Date.now() - JSON.parse(readFileSync(LOCK, 'utf8')).ts; } catch { age = Infinity; }
+  if (age < 2 * 60 * 60 * 1000) { console.log('enrich-suggestions: another run holds the lock — exiting (no double-write).'); process.exit(0); }
+  console.log('enrich-suggestions: reclaiming a stale lock (>2h).');
+}
+try { writeFileSync(LOCK, JSON.stringify({ pid: process.pid, ts: Date.now() })); } catch { /* best-effort */ }
+const releaseLock = () => { try { unlinkSync(LOCK); } catch { /* already gone */ } };
+process.on('exit', releaseLock);
+process.on('SIGTERM', () => { releaseLock(); process.exit(143); });
+process.on('SIGINT', () => { releaseLock(); process.exit(130); });
 const LIMIT = (() => { const i = process.argv.indexOf('--limit'); return i > -1 ? parseInt(process.argv[i + 1], 10) : 0; })();
 const FORCE = process.argv.includes('--force');
 const PACE_MS = 350;

← 039cfdc yoloforever c1: wire /api/rebuild to auto-refill FileMaker s  ·  back to Mfr Review Viewer Corruption  ·  fix [110]: route sweep deletes/writes through Basic List of 1ba8310 →