Commit 1d91f1a
fix(agents): release session write lock if fence read throws on prompt release
releaseHeldLockWithFence (the embedded-attempt session-lock controller's
release-for-prompt path) cleared its in-memory `heldLock` reference and then
performed fence bookkeeping — readSessionFileFingerprint and
readSessionFileFenceSnapshot — before calling lock.release(). Both perform
filesystem I/O that can reject with a transient non-ENOENT error (e.g.
EIO/EMFILE under load). Because release() was not in a finally, such a throw
exited the function with `heldLock` already nulled and the underlying file
lock never released.
The lock then leaked on the live gateway process for the full maxHoldMs lease.
Since the controller holds the lock with maxHoldMs derived from the agent
timeout (~17 min) and the holder is the live pid (its /proc starttime matches
the lock payload), the stale-lock breaker correctly refuses to reclaim it — only
the watchdog TTL frees it. Meanwhile the attempt teardown still releases the
in-process session-file owner mutex, so the next interactive turn sails past the
mutex and blocks on the orphaned file lock, failing every turn with
SessionWriteLockTimeoutError for up to 17 minutes (observed: a Discord channel
dead 00:08–00:27).
Wrap the fence bookkeeping in try/finally so the file lock is always released
once heldLock is cleared, even if the fence reads throw. The original error
still propagates; only the lock-release invariant is made exception-safe.
Add regression coverage: a fence-read failure during releaseForPrompt must still
release the underlying lock.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 0fa384c commit 1d91f1a
2 files changed
Lines changed: 46 additions & 11 deletions
Lines changed: 25 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
139 | 164 | | |
140 | 165 | | |
141 | 166 | | |
| |||
Lines changed: 21 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
801 | 801 | | |
802 | 802 | | |
803 | 803 | | |
804 | | - | |
805 | | - | |
806 | | - | |
807 | | - | |
808 | | - | |
809 | | - | |
810 | | - | |
811 | | - | |
812 | | - | |
813 | | - | |
814 | | - | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
815 | 825 | | |
816 | 826 | | |
817 | 827 | | |
| |||
0 commit comments