























@@ -320,7 +320,7 @@ describe("stuck session diagnostics threshold", () => {
320320expect(events).toHaveLength(1);
321321expect(recoverStuckSession).toHaveBeenCalledTimes(1);
322322323-vi.advanceTimersByTime(30_000);
323+vi.advanceTimersByTime(31_000);
324324} finally {
325325unsubscribe();
326326}
@@ -442,6 +442,48 @@ describe("stuck session diagnostics threshold", () => {
442442expect(recoverStuckSession).not.toHaveBeenCalled();
443443});
444444445+it("throttles repeated long-running active-work warnings", () => {
446+const events: DiagnosticEventPayload[] = [];
447+const recoverStuckSession = vi.fn();
448+const unsubscribe = onDiagnosticEvent((event) => {
449+events.push(event);
450+});
451+try {
452+startDiagnosticHeartbeat(
453+{
454+diagnostics: {
455+enabled: true,
456+stuckSessionWarnMs: 30_000,
457+},
458+},
459+{ recoverStuckSession },
460+);
461+logSessionStateChange({ sessionId: "s1", sessionKey: "main", state: "processing" });
462+vi.advanceTimersByTime(45_000);
463+markDiagnosticEmbeddedRunStarted({ sessionId: "s1", sessionKey: "main" });
464+vi.advanceTimersByTime(16_000);
465+466+expect(events.filter((event) => event.type === "session.long_running")).toHaveLength(1);
467+468+vi.advanceTimersByTime(28_000);
469+emitDiagnosticEvent({
470+type: "run.progress",
471+sessionId: "s1",
472+sessionKey: "main",
473+reason: "stream",
474+});
475+vi.advanceTimersByTime(2_000);
476+477+expect(events.filter((event) => event.type === "session.long_running")).toHaveLength(1);
478+} finally {
479+unsubscribe();
480+}
481+482+const longRunningEvents = events.filter((event) => event.type === "session.long_running");
483+expect(longRunningEvents).toHaveLength(1);
484+expect(recoverStuckSession).not.toHaveBeenCalled();
485+});
486+445487it("keeps queued sessions non-recoverable while active work is making progress", () => {
446488const events: DiagnosticEventPayload[] = [];
447489const recoverStuckSession = vi.fn();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。