← back to Dw Photo Capture
harden all-dw cache write: atomic tmp+rename, refresh disk-cache sig
2bc0f06432e590c72350274ab377158c771be4c1 · 2026-09-22 13:58:08 -0700 · Steve Abrams
Write the ~hundreds-of-MB all-catalog.json via a sibling .tmp + rename() so an
interrupted write can never leave a truncated cache the feed-down fallback would
choke on. Also stamp _diskCacheSig from the just-written file so the first
feed-down tick after a refresh skips a redundant reparse (TK-11962 guard).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142i1ci5jdMrmc8DNr6RjUS
Files touched
Diff
commit 2bc0f06432e590c72350274ab377158c771be4c1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 22 13:58:08 2026 -0700
harden all-dw cache write: atomic tmp+rename, refresh disk-cache sig
Write the ~hundreds-of-MB all-catalog.json via a sibling .tmp + rename() so an
interrupted write can never leave a truncated cache the feed-down fallback would
choke on. Also stamp _diskCacheSig from the just-written file so the first
feed-down tick after a refresh skips a redundant reparse (TK-11962 guard).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142i1ci5jdMrmc8DNr6RjUS
---
server.js | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index 7569885..0ebc5d3 100644
--- a/server.js
+++ b/server.js
@@ -2772,7 +2772,22 @@ async function buildCatalog() {
const feed = await fetchAllDwCatalog();
if (feed && Array.isArray(feed.rows) && feed.rows.length) {
CATALOG = feed.rows.map(feedRowToItem);
- try { fs.writeFileSync(CATALOG_CACHE, JSON.stringify(feed)); } catch (e) { /* cache best-effort */ }
+ try {
+ // Atomic write: this cache is a multi-hundred-MB JSON; an in-place writeFileSync that is
+ // interrupted (OOM/restart/disk-full mid-write) leaves a TRUNCATED file that the feed-down
+ // fallback (branch 2 below) would then JSON.parse and fail on every 15-min tick. Write to a
+ // sibling .tmp on the same filesystem, then rename() — rename is atomic, so a reader ever
+ // only sees the complete old file or the complete new one, never a torn one.
+ const tmp = CATALOG_CACHE + '.tmp';
+ fs.writeFileSync(tmp, JSON.stringify(feed));
+ fs.renameSync(tmp, CATALOG_CACHE);
+ // Record the signature of the file we just wrote so a later feed-down tick recognizes that
+ // CATALOG already reflects this exact cache and skips a redundant ~hundreds-of-MB reparse
+ // (the TK-11962 guard keys on size+mtime). Without this, the first feed-down tick after every
+ // refresh needlessly re-reads+re-parses the file it just produced — costly with a flapping feed.
+ const st = fs.statSync(CATALOG_CACHE);
+ _diskCacheSig = st.size + ':' + st.mtimeMs;
+ } catch (e) { /* cache best-effort */ }
console.log(`catalog indexed: ${CATALOG.length} products from all-dw feed`);
return rebuildIndex();
}
← 77ae6ab harden(TK-11962): catalog-cache guard survives corrupt/unrea
·
back to Dw Photo Capture
·
gitignore 5x/out/ screen-capture test artifacts 0d34d1b →