Wait for SQLite locks instead of crashing

A second process (rebuild, ghidra refresh) holding a write lock made the
verifier's timer throw "database is locked" and took the coordinator down.
Set a busy timeout and keep timer errors from killing the process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNwtXPYqFu3oKaaXwYwNWW
This commit is contained in:
Saty 2026-10-18 03:01:14 +02:00
commit 5900fe2ecf
4 changed files with 5 additions and 3 deletions

View file

@ -631,7 +631,7 @@ export async function startServer(dataDir) {
ctx.tasks.generate();
ctx.verifier.start();
ctx.merger.start();
const sweeper = setInterval(() => ctx.tasks.sweepExpired(), 60_000);
const sweeper = setInterval(() => { try { ctx.tasks.sweepExpired(); } catch (e) { console.error(`lease sweep: ${e.message}`); } }, 60_000);
const server = createApp(ctx);
await new Promise((r) => server.listen(ctx.config.listen.port, ctx.config.listen.host, r));
console.log(`clank together coordinator listening on http://${ctx.config.listen.host}:${ctx.config.listen.port} (public url ${ctx.config.publicUrl})`);

View file

@ -214,6 +214,8 @@ export const hashToken = (t) => crypto.createHash('sha256').update(t).digest('he
export class Store {
constructor(file) {
this.db = new DatabaseSync(file);
// CLI commands (rebuild, ghidra refresh) write from a second process; wait for their locks.
this.db.exec('PRAGMA busy_timeout = 15000');
this.migrateUsers();
this.db.exec(SCHEMA);
this.addColumn('func_status', 'confirmed', 'INTEGER NOT NULL DEFAULT 0');

View file

@ -15,7 +15,7 @@ export class Merger {
start() {
this.store.run(`UPDATE batches SET state = 'open' WHERE state = 'merging'`);
this.store.run(`UPDATE tasks SET state = 'approved' WHERE state = 'merging'`);
this.timer = setInterval(() => this.pump(), 3000);
this.timer = setInterval(() => { try { this.pump(); } catch (e) { console.error(`merge pump: ${e.message}`); } }, 3000);
}
stop() {

View file

@ -38,7 +38,7 @@ export class Verifier {
);
this.store.run('UPDATE attempts SET batch_id = ? WHERE id = ?', Number(b.lastInsertRowid), a.id);
}
this.timer = setInterval(() => this.pump(), 2000);
this.timer = setInterval(() => { try { this.pump(); } catch (e) { console.error(`verify pump: ${e.message}`); } }, 2000);
this.pump();
}