fix(ios): reap orphaned simulator recorders with a graceful finalize window - #2457
fix(ios): reap orphaned simulator recorders with a graceful finalize window#2457thymikee wants to merge 3 commits into
Conversation
Classify `simctl recordVideo` exit 16 (POSIX EBUSY) as a typed COMMAND_FAILED with an actionable hint and the recorder's stderr instead of an unclassified UNKNOWN, so a caller learns another recording holds the one host-wide CoreSimulator slot or a prior recorder died without detaching. Give a recorder that is rolled back or reaped the same graceful SIGINT -> SIGTERM -> SIGKILL escalation the live stop path already uses, and widen the daemon-startup reaper's recorder grace to match it, so finalize-and-detach releases the host-wide recording lock instead of a mid-detach SIGKILL dangling it for every later recording. Closes #2170
Size Report
Startup median (7 runs, lower is better):
|
…ack helper Simplify #2170. The exit-code classification lives beside `startError` that is its only caller, so drop the separate module and its test and assert through the real start path instead. Test through `normalizeError` to keep the wire-shape (hint lifted, reason and exit code retained) guarantee. Revert the start-rollback SIGKILL sites: the identity arm fires only when the recorder already exited, and the acquisition rollback discards an explicitly canceled recording, so fast-kill there is fine. The dangling-host path is the startup reaper, which keeps the wider finalize grace added earlier.
|
The startup failure is still missed at 1fb63cb: an immediate exit 16 can happen before process identity is readable, so waitForManagedProcessIdentity returns no marker and the new classifier is never reached. The test keeps identity metadata available for an already-exited child, masking that path. Observe process exit during identity acquisition and add a regression with missing identity plus exit 16.\n\nCanceled acquisition and identity-failure cleanup still use immediate SIGKILL. A recorder may already hold the stream slot there; discarding the video does not remove the need to detach cleanly. Reuse graceful rollback and verify recording works afterward. #2447 already addresses these same paths with a different error contract, so consolidate the overlapping changes before either lands.\n\nCI is green, but the reported normal start/stop run does not validate orphan recovery or the busy failure path. |
…grace The exit-16 classifier and graceful start rollback are owned by #2447 with the DEVICE_IN_USE contract; drop the overlapping COMMAND_FAILED classifier here to keep one start-path error contract. Keep only the non-overlapping daemon-startup fix: an orphaned simctl recorder is reaped with the same finalize grace the live stop path allows, plus a startup-wiring test. Refs #2170.
|
@thymikee consolidating per your comment so #2447 and this don't land two start-path error contracts:
Gate on head |
|
The overlap is resolved at 99a379f: this now only gives the existing recorder-only startup reaper five seconds to finalize after SIGINT. No code findings. Before marking it ready, please show a CoreSimulator run that leaves a live recorder orphaned after an ungraceful daemon exit, restarts the daemon, and then successfully starts and stops a new recording. The wiring test and normal recording runs do not prove that recovery. The current iOS failure concerns alert replacement and appears unrelated. |
Summary
Narrows #2170 to its non-overlapping piece. #2447 already owns the simulator-recording start path — the exit-16 busy classifier, the fast-exit observation, and the graceful SIGINT rollback — under the
DEVICE_IN_USEcontract. To land a single start-path error contract, this PR keeps only the daemon-startup fix that #2447 does not touch.When the daemon starts, it reaps orphaned
simctl recordVideochildren (purposes: ['simctl-screen-recording']). It previously used the generic 2s reaper grace. An orphaned recorder releases CoreSimulator's host-wide recording lock only after finalizing onSIGINT; force-killing it after 2s fixes the one device but leaves the lock dangling so every later recording on the host fails withEBUSY. This passes the recorder the same finalize grace the live stop path allows (5s). Bounded to the recorder purpose, so it never widens the web or generic reap budgets.Adds one startup-wiring test proving the recording purpose is reaped with a
>= 5000msterm timeout.Closes #2170 (recorder-recovery half); start-path recovery and the busy error contract land in #2447.
Why 5s
simctl recordVideofinalizes the mp4 onSIGINT; the host recording slot frees only after that.instantly), and the host-wide lock permits at most one live recorder — so startup stays under the
15s client timeout.
Validation
daemon-runtime-recording-reaper.test.ts: drives realstartDaemonRuntime(reaper spied) andasserts it invokes
reapOwnedProcessRecordsAtStartupfor thesimctl-screen-recordingpurpose witha graceful finalize window. Fails if the grace drops to the generic default.
pnpm check:affected --run,tsc, andoxlintpass on head99a379f9f0.src/daemon/server/daemon-runtime.ts+5 and one new test; host start path unchanged.EBUSYfailure path and in-session rollback are validated in fix(ios): recover simulator recorder startup failures #2447, nothere; a normal start/stop run does not exercise this startup reap (it only matters after an
ungraceful daemon exit leaves a recorder orphan).
Related: #2170, #2447.