fix(agent-jobs): add heartbeat cancel and stale recovery

This commit is contained in:
Gabriel Brown
2026-07-10 18:03:45 -04:00
parent cbbb168e7c
commit 470af043fa
5 changed files with 266 additions and 1 deletions
+47 -1
View File
@@ -1201,6 +1201,52 @@ export const failClaimInternal = internalMutation({
},
});
export const recoverStaleJobs = internalMutation({
args: { staleMs: v.optional(v.number()) },
handler: async (ctx, { staleMs }) => {
const threshold = Date.now() - (staleMs ?? 3 * 60 * 1000);
const activeStatuses = [
'claimed',
'preparing',
'running',
'checks_running',
] as const;
let recovered = 0;
for (const status of activeStatuses) {
const jobs = await ctx.db
.query('agentJobs')
.withIndex('by_status', (q) => q.eq('status', status))
.collect();
for (const job of jobs) {
const last = job.lastHeartbeatAt ?? job.claimedAt ?? job.createdAt;
if (last > threshold) continue;
const now = Date.now();
await ctx.db.patch(job._id, {
status: 'timed_out',
error:
job.error ??
'The worker stopped reporting progress; the job timed out.',
completedAt: now,
updatedAt: now,
});
await ctx.db.patch(job.agentRequestId, {
status: 'failed',
updatedAt: now,
});
if (job.threadId) {
await ctx.db.patch(job.threadId, {
status: 'failed',
updatedAt: now,
resolvedAt: now,
});
}
recovered += 1;
}
}
return { recovered };
},
});
export const updateStatus = mutation({
args: {
workerToken: v.string(),
@@ -1471,7 +1517,7 @@ export const heartbeatWorkspace = mutation({
lastHeartbeatAt: Date.now(),
updatedAt: Date.now(),
});
return { success: true };
return { success: true, cancelRequested: job.status === 'cancelled' };
},
});
+6
View File
@@ -12,6 +12,12 @@ crons.interval(
limit: 10,
},
);
crons.interval(
'Recover stale agent jobs',
{ minutes: 1 },
internal.agentJobs.recoverStaleJobs,
{},
);
/* Example cron jobs
crons.cron(
// Run at 7:00 AM CST / 8:00 AM CDT