fix: resolve database-is-locked error in completeRoutineExecution

completeRoutineExecution was reading from the DB outside the per-routine
lock then calling recordRun which acquires the lock internally. This
allowed concurrent operations on the same routine to hit SQLite
simultaneously. Inlined the logic inside a single withRoutineLock call
so the read and write are serialized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-10 11:32:48 -07:00
parent afc70f15e6
commit 82fc649db6

View File

@@ -404,16 +404,34 @@ export class RoutineStore extends EventEmitter<RoutineStoreEvents> {
id: string,
meta: { completedAt: string; success: boolean; resultJson?: Record<string, unknown>; error?: string },
): Promise<void> {
const routine = await this.getRoutine(id);
const result: RoutineExecutionResult = {
routineId: id,
success: meta.success,
output: meta.success ? JSON.stringify(meta.resultJson ?? {}) : "",
error: meta.error,
startedAt: routine.lastRunAt ?? meta.completedAt,
completedAt: meta.completedAt,
};
await this.recordRun(id, result);
await this.withRoutineLock(id, async () => {
const routine = await this.getRoutine(id);
const result: RoutineExecutionResult = {
routineId: id,
success: meta.success,
output: meta.success ? JSON.stringify(meta.resultJson ?? {}) : "",
error: meta.error,
startedAt: routine.lastRunAt ?? meta.completedAt,
completedAt: meta.completedAt,
};
routine.lastRunAt = result.startedAt;
routine.lastRunResult = result;
routine.runCount += 1;
routine.runHistory.unshift(result);
if (routine.runHistory.length > MAX_ROUTINE_RUN_HISTORY) {
routine.runHistory = routine.runHistory.slice(0, MAX_ROUTINE_RUN_HISTORY);
}
if (routine.enabled && isCronTrigger(routine.trigger)) {
routine.nextRunAt = this.computeNextRun(routine.trigger.cronExpression);
}
routine.updatedAt = new Date().toISOString();
this.upsertRoutine(routine);
this.emit("routine:run", { routine, result });
});
}
/**