Skip to content

Commit bd6c346

Browse files
kyletaborclaude
andcommitted
fix: address review feedback — stale timeout warning, active count, default timeout
- Gate timeout diag.warn on completedCurrentGeneration; stale post-reset timeouts downgrade to diag.debug to avoid misleading on-call noise - Capture activeTaskIds.size before completeTask() removal so the timeout warning reports the pre-removal active count - Increase DEFAULT_TASK_TIMEOUT_MS from 5 to 15 minutes — the lane timeout is a last-resort safety net above the agent-level timeout (default 600s / 10 min), so it must be higher to avoid killing legitimate long-running tasks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f767196 commit bd6c346

2 files changed

Lines changed: 28 additions & 7 deletions

File tree

src/process/command-queue.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,8 @@ describe("command queue", () => {
429429
{ taskTimeoutMs: 0 },
430430
);
431431

432-
// Advance well past the default 5-minute timeout.
433-
await vi.advanceTimersByTimeAsync(10 * 60 * 1000);
432+
// Advance well past the default 15-minute timeout.
433+
await vi.advanceTimersByTimeAsync(20 * 60 * 1000);
434434

435435
// Task should still be active — not timed out.
436436
expect(getActiveTaskCount()).toBe(1);
@@ -501,6 +501,14 @@ describe("command queue", () => {
501501
const err = await stuckResult;
502502
expect(err).toBeInstanceOf(CommandLaneTaskTimeoutError);
503503

504+
// Stale timeout should use debug, not warn.
505+
expect(diagnosticMocks.diag.debug).toHaveBeenCalledWith(
506+
expect.stringContaining("stale, post-reset"),
507+
);
508+
expect(diagnosticMocks.diag.warn).not.toHaveBeenCalledWith(
509+
expect.stringContaining("lane task timed out:"),
510+
);
511+
504512
// Verify lane still works after all of this.
505513
const fresh = enqueueCommandInLane(lane, async () => "still works");
506514
await vi.advanceTimersByTimeAsync(10);

src/process/command-queue.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,14 @@ export class CommandLaneTaskTimeoutError extends Error {
4141
// low-risk parallelism (e.g. cron jobs) without interleaving stdin / logs for
4242
// the main auto-reply workflow.
4343

44-
/** Default task execution timeout (5 minutes). */
45-
const DEFAULT_TASK_TIMEOUT_MS = 5 * 60 * 1000;
44+
/**
45+
* Default task execution timeout (15 minutes). This is a last-resort
46+
* safety net above the agent-level timeout (default 600s / 10 min in
47+
* `src/agents/timeout.ts`). Set high enough to avoid killing legitimate
48+
* long-running tasks while still recovering stuck lanes within a
49+
* reasonable window.
50+
*/
51+
const DEFAULT_TASK_TIMEOUT_MS = 15 * 60 * 1000;
4652

4753
type QueueEntry = {
4854
task: () => Promise<unknown>;
@@ -166,12 +172,19 @@ function drainLane(lane: string) {
166172
if (timeoutHandle !== undefined) {
167173
clearTimeout(timeoutHandle);
168174
}
175+
const activeBeforeComplete = state.activeTaskIds.size;
169176
const completedCurrentGeneration = completeTask(state, taskId, taskGeneration);
170177
const isProbeLane = lane.startsWith("auth-probe:") || lane.startsWith("session:probe-");
171178
if (err instanceof CommandLaneTaskTimeoutError) {
172-
diag.warn(
173-
`lane task timed out: lane=${lane} timeoutMs=${effectiveTimeout} durationMs=${Date.now() - startTime} active=${state.activeTaskIds.size} queued=${state.queue.length}`,
174-
);
179+
if (completedCurrentGeneration) {
180+
diag.warn(
181+
`lane task timed out: lane=${lane} timeoutMs=${effectiveTimeout} durationMs=${Date.now() - startTime} active=${activeBeforeComplete} queued=${state.queue.length}`,
182+
);
183+
} else {
184+
diag.debug(
185+
`lane task timed out (stale, post-reset): lane=${lane} timeoutMs=${effectiveTimeout} durationMs=${Date.now() - startTime}`,
186+
);
187+
}
175188
} else if (!isProbeLane) {
176189
diag.error(
177190
`lane task error: lane=${lane} durationMs=${Date.now() - startTime} error="${String(err)}"`,

0 commit comments

Comments
 (0)