Repository navigation
fix(studio-server): a history claim on Windows waits out a lock file being deleted - #5923
miguel-heygen wants to merge 3 commits into
Conversation
Edit accuracy: accurate 271 (base branch 271), smooth 178 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
vanceingalls
left a comment
There was a problem hiding this comment.
Reviewed at ceecd011. Approving.
The retry is narrow.
- Only a
win32EPERM/EACCES/EBUSY raised by one claim attempt is retried (ownerLock.ts:15-21,:128-133), and only until the existing deadline. Past the deadline the original error is rethrown, so a lock that stays unreadable still fails, as before. - Off Windows, every error path is unchanged.
- Every step inside
attemptClaimis safe to repeat:claimremoves its draft infinally, so alinkSyncthat hits a deletingowner.pidleaves nothing behind.ownerOfonly reads.evictDeadOwnerreleases its evict lock infinallyand re-reads the owner under it, so a retry can't take a live owner's lock.
- A caught busy error falls to
"wait", so the loop sleeps 50 ms rather than spinning.
The work after the claim is unchanged. advertise and the release closure moved out of the loop verbatim, so only the claim is retried, as the body says.
The tests exercise the real path. A mode-000 owner.pid gives a real EACCES on Linux and macOS, and process.platform is stubbed to win32 and restored in afterEach. The first test fails on main, because the old loop has no catch. Skipping on root and on real Windows is right, since mode 000 can't produce the error there.
Nit
- This is pre-existing, not new here. If
advertise'srenameSynchits a Windows busy code (for example a waiter readingowner.urlat its deadline), it throws after this process already holdsowner.pid. The lock then stays held until the process exits, and no release is returned. If the history CLI ever hits that, wrappingadvertisein the same busy retry, or releasing the lock on failure, would close it.
Verdict: APPROVE
Reasoning: The retry is limited to Windows busy codes within the existing deadline, every retried step is idempotent, and the test drives a real EACCES through the Windows branch. Required CI is green at this head.
— Via
What changes for users
On Windows, two
hyperframes history begincalls on one project at the same moment no longer crash one of them withEPERM: operation not permitted, open '...\owner.pid'. The second waits for the history lock and gets the normal refusal ("'s turn is open; it has to end before yours begins"), as on macOS and Linux.Why it failed
The history owner lock reads and hard-links
owner.pid. When the owner releases the lock it deletes that file, and on Windows a file that is being deleted cannot be opened or linked for a moment: the call fails with EPERM (sometimes EACCES or EBUSY) instead of ENOENT or EEXIST. The lock treated that as a fatal error, so the waiting process exited with code 1.Seen on a hosted Windows runner looping the existing test
serializes concurrent begin --exclusive claims under the history owner lock30 times with each process's stderr printed: one run in 30 had the waiting process exit 1 withEPERM: operation not permitted, open '...\owner.pid'; the other 29 refused with code 2 as expected.The fix
On Windows, an EPERM, EACCES or EBUSY while claiming or reading the lock means the lock is busy: the claimer waits and tries again until its existing deadline, then gives up with the same error. Elsewhere these errors still fail at once. Only the claim is retried, not the work after this process holds the lock. One claim attempt moved into its own function to keep the loop readable. The codes are the ones the shared atomic-file writes already treat as Windows-busy.
Proof
ownerLock.test.tsmakes the lock file unreadable with mode 000 (a real EACCES on Linux and macOS) and deletes it after 200 ms, as a finishing delete would:20 runs in a row pass; the history suites (203 tests) and the package typecheck pass.
No visible change
Nothing changes outside Windows, and nothing changes on Windows unless two processes race for one project's history.