53 lines
2.4 KiB
JavaScript
Executable File
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());
|