fix: serialize autonomy job leases

This commit is contained in:
ImBenji
2026-08-04 21:07:42 +01:00
parent 5037e1e192
commit b9ee10a83a
6 changed files with 14 additions and 1 deletions
+9 -1
View File
@@ -31,7 +31,15 @@ function leaseNextJob(db, workerId, leaseSeconds = 60, jobTypes = null) {
`).run(workerId, `+${Math.max(1, Math.floor(leaseSeconds))} seconds`, job.id);
return updated.changes ? { ...job, status: 'leased', leased_by: workerId } : null;
});
return tx();
try {
// Acquire the write reservation before selecting. A deferred transaction can
// otherwise read a snapshot, lose the writer race, and fail with
// SQLITE_BUSY_SNAPSHOT when it attempts the lease update.
return tx.immediate();
} catch (error) {
if (String(error.code || '').startsWith('SQLITE_BUSY')) return null;
throw error;
}
}
function completeJob(db, id, workerId) {
+1
View File
@@ -71,6 +71,7 @@ async function runAutonomyWorker({ archivePath, intelligencePath, workerId = `au
const archiveDb = new Database(archivePath, { readonly: true });
const intelligenceDb = new Database(intelligencePath);
intelligenceDb.pragma('journal_mode = WAL');
intelligenceDb.pragma('busy_timeout = 5000');
initAutonomySchema(intelligenceDb);
while (true) {
+1
View File
@@ -71,6 +71,7 @@ function createDecisions(db, strategyVersion = 'autonomy-1') {
async function runCalibrationWorker({ intelligencePath, pollMs = 60000, workerId = `calibration-${os.hostname()}-${process.pid}` } = {}) {
const db = new Database(intelligencePath);
db.pragma('journal_mode = WAL');
db.pragma('busy_timeout = 5000');
initAutonomySchema(db);
while (true) {
try {
+1
View File
@@ -34,6 +34,7 @@ async function runCoordinatorWorker({ archivePath, intelligencePath, workerId =
const archiveDb = new Database(archivePath, { readonly: true });
const intelligenceDb = new Database(intelligencePath);
intelligenceDb.pragma('journal_mode = WAL');
intelligenceDb.pragma('busy_timeout = 5000');
initAutonomySchema(intelligenceDb);
const config = loadConfig();
while (true) {
+1
View File
@@ -10,6 +10,7 @@ async function runExecutionWorker({ intelligencePath, pollMs = 10000, mode = 'sh
if (!['shadow', 'paper'].includes(mode)) throw new Error(`unsupported execution mode: ${mode}`);
const db = new Database(intelligencePath);
db.pragma('journal_mode = WAL');
db.pragma('busy_timeout = 5000');
initAutonomySchema(db);
const paperClient = mode === 'paper'
? createAlpacaPaperClient({ keyId: process.env.ALPACA_PAPER_KEY_ID, secretKey: process.env.ALPACA_PAPER_SECRET_KEY })
+1
View File
@@ -33,6 +33,7 @@ async function history(symbol) {
async function resolveAutonomyOutcomes({ intelligencePath, workerId = `outcome-${os.hostname()}-${process.pid}`, pollMs = 60000 } = {}) {
const db = new Database(intelligencePath);
db.pragma('journal_mode = WAL');
db.pragma('busy_timeout = 5000');
initAutonomySchema(db);
const cache = new Map();
while (true) {