Skip to content

Commit f00c655

Browse files
committed
fix(agents): release session write-lock immediately when holder PID is dead
When an agent run fails abnormally during tool execution, the session write-lock remains held in memory. The watchdog's force-release threshold inherited the full maxHoldMs (up to 17 minutes for a 15-minute agent timeout), causing all subsequent requests to the same session to fail with SessionWriteLockTimeoutError until the watchdog fires. Fix: read the lock file payload during each watchdog check and release the lock immediately if the holder PID is no longer alive, regardless of maxHoldMs. Fixes #100872
1 parent 1ce0d4b commit f00c655

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

src/agents/session-write-lock.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,26 @@ function releaseAllLocksSync(): void {
286286
async function runLockWatchdogCheck(nowMs = Date.now()): Promise<number> {
287287
let released = 0;
288288
for (const held of SESSION_LOCKS.heldEntries()) {
289+
// Release locks whose holder process is no longer alive, regardless of
290+
// maxHoldMs. This prevents sessions from being locked for the full agent
291+
// timeout duration (up to 17 minutes) when the owner process terminates
292+
// abnormally during tool execution. (#100872)
293+
const lockPayload = await readLockPayload(held.lockPath);
294+
if (lockPayload) {
295+
const pid =
296+
isValidLockNumber(lockPayload.pid) && lockPayload.pid > 0 ? lockPayload.pid : null;
297+
if (pid !== null && !isPidAlive(pid)) {
298+
process.stderr.write(
299+
`[session-write-lock] releasing lock held by dead pid ${pid}: ${held.lockPath}\n`,
300+
);
301+
const didRelease = await held.forceRelease();
302+
if (didRelease) {
303+
released += 1;
304+
}
305+
continue;
306+
}
307+
}
308+
289309
const maxHoldMs =
290310
typeof held.metadata.maxHoldMs === "number"
291311
? held.metadata.maxHoldMs

0 commit comments

Comments
 (0)