Files
wikideck/server/market/reconciliation-commit-worker.js
T

53 lines
2.4 KiB
JavaScript
Executable File

import { DatabaseSync } from 'node:sqlite';
import { parentPort, workerData } from 'node:worker_threads';
import { isDeepStrictEqual } from 'node:util';
const db = new DatabaseSync(workerData.marketFile);
db.exec('PRAGMA busy_timeout=5000; PRAGMA synchronous=FULL;');
const port = parentPort;
if (!port) throw new Error('Reconciliation commit worker requires a parent port');
function atomic(fn) {
db.exec('BEGIN IMMEDIATE');
try { const result = fn(); db.exec('COMMIT'); return result; }
catch (error) { db.exec('ROLLBACK'); throw error; }
}
function assertCurrentJob(expected) {
const row = db.prepare("SELECT value FROM market_meta WHERE key='canonical_reconciliation_job'").get();
if (!row || !isDeepStrictEqual(JSON.parse(row.value), expected)) {
throw new Error('Reconciliation job changed before worker commit');
}
}
port.on('message', request => {
try {
if (request.operation === 'persist-batch') {
atomic(() => {
assertCurrentJob(request.expectedJob);
const order = db.prepare(`INSERT INTO orders(id,data) VALUES(?,?)
ON CONFLICT(id) DO UPDATE SET data=excluded.data WHERE orders.data<>excluded.data`);
for (const row of request.orders) order.run(row.id, row.data);
const listing = db.prepare(`INSERT INTO listings(id,card,status,data) VALUES(?,?,?,?)
ON CONFLICT(id) DO UPDATE SET status=excluded.status,data=excluded.data WHERE listings.data<>excluded.data`);
for (const row of request.listings) listing.run(row.id, row.card, row.status, row.data);
db.prepare("UPDATE market_meta SET value=? WHERE key='canonical_reconciliation_job'")
.run(JSON.stringify(request.nextJob));
});
} else {
atomic(() => {
assertCurrentJob(request.expectedJob);
db.prepare('DELETE FROM receipts WHERE expires < ?').run(request.observedAt - 86400_000);
if (request.cursor) {
db.prepare(`INSERT INTO market_meta(key,value) VALUES('canonical_event_cursor',?)
ON CONFLICT(key) DO UPDATE SET value=excluded.value`).run(request.cursor);
}
db.prepare("DELETE FROM market_meta WHERE key='canonical_reconciliation_job'").run();
});
}
port.postMessage({ id: request.id, ok: true });
} catch (error) {
port.postMessage({ id: request.id, ok: false, error: error instanceof Error ? error.message : 'Worker batch failed' });
}
});
port.on('close', () => db.close());