Skip to content

Commit 56fa542

Browse files
committed
fix(agents): release session lock on manual abort
1 parent 5a0e677 commit 56fa542

3 files changed

Lines changed: 69 additions & 5 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import { releaseEmbeddedAttemptSessionLockForAbort } from "./attempt-abort.js";
3+
4+
describe("releaseEmbeddedAttemptSessionLockForAbort", () => {
5+
it("releases the retained session lock for manual aborts", async () => {
6+
const releaseHeldLockForAbort = vi.fn(async () => {});
7+
const warn = vi.fn();
8+
9+
releaseEmbeddedAttemptSessionLockForAbort({
10+
sessionLockController: { releaseHeldLockForAbort },
11+
log: { warn },
12+
runId: "run-manual",
13+
abortKind: "abort",
14+
});
15+
16+
await Promise.resolve();
17+
18+
expect(releaseHeldLockForAbort).toHaveBeenCalledTimes(1);
19+
expect(warn).not.toHaveBeenCalled();
20+
});
21+
22+
it("logs release failures without throwing from the abort path", async () => {
23+
const releaseError = new Error("locked");
24+
const releaseHeldLockForAbort = vi.fn(async () => {
25+
throw releaseError;
26+
});
27+
const warn = vi.fn();
28+
29+
releaseEmbeddedAttemptSessionLockForAbort({
30+
sessionLockController: { releaseHeldLockForAbort },
31+
log: { warn },
32+
runId: "run-timeout",
33+
abortKind: "timeout abort",
34+
});
35+
36+
await Promise.resolve();
37+
await Promise.resolve();
38+
39+
expect(releaseHeldLockForAbort).toHaveBeenCalledTimes(1);
40+
expect(warn).toHaveBeenCalledWith(
41+
"failed to release session lock on timeout abort: runId=run-timeout Error: locked",
42+
);
43+
});
44+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { EmbeddedAttemptSessionLockController } from "./attempt.session-lock.js";
2+
3+
type AbortLockReleaseLog = {
4+
warn(message: string): void;
5+
};
6+
7+
export function releaseEmbeddedAttemptSessionLockForAbort(params: {
8+
sessionLockController: Pick<EmbeddedAttemptSessionLockController, "releaseHeldLockForAbort">;
9+
log: AbortLockReleaseLog;
10+
runId: string;
11+
abortKind: "abort" | "timeout abort";
12+
}): void {
13+
void params.sessionLockController.releaseHeldLockForAbort().catch((err) => {
14+
params.log.warn(
15+
`failed to release session lock on ${params.abortKind}: runId=${params.runId} ${String(err)}`,
16+
);
17+
});
18+
}

src/agents/embedded-agent-runner/run/attempt.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ import {
308308
rotateTranscriptAfterCompaction,
309309
shouldRotateCompactionTranscript,
310310
} from "../compaction-successor-transcript.js";
311+
import { releaseEmbeddedAttemptSessionLockForAbort } from "./attempt-abort.js";
311312
import { resolveAttemptWorkspaceBootstrapRouting } from "./attempt-bootstrap-routing.js";
312313
import { configureEmbeddedAttemptHttpRuntime } from "./attempt-http-runtime.js";
313314
import {
@@ -2984,12 +2985,13 @@ export async function runEmbeddedAttempt(
29842985
sessionFile: params.sessionFile,
29852986
reason: "timeout",
29862987
});
2987-
void sessionLockController.releaseHeldLockForAbort().catch((err) => {
2988-
log.warn(
2989-
`failed to release session lock on timeout abort: runId=${params.runId} ${String(err)}`,
2990-
);
2991-
});
29922988
}
2989+
releaseEmbeddedAttemptSessionLockForAbort({
2990+
sessionLockController,
2991+
log,
2992+
runId: params.runId,
2993+
abortKind: isTimeout ? "timeout abort" : "abort",
2994+
});
29932995
};
29942996
abortRunForExternalSignal = abortRun;
29952997
const idleTimeoutTrigger: ((error: Error) => void) | undefined = (error) => {

0 commit comments

Comments
 (0)