fix(shared): preserve recorder artifacts during signal shutdown - #3049
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9cfbb971d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Temporary real Computer recorder acceptance passed on GitHub Actions: https://github.com/web-infra-dev/midscene/actions/runs/33138403058/job/98743638436 The job launched the actual This run also exposed the XIO-on-Xvfb-shutdown edge case; commits |
Summary
Root cause
In a foreground PTY, Ctrl+C targets the entire process group. A package runner such as pnpm exits at the same time as the Midscene child, forwards SIGTERM, and can trigger SIGHUP when the controlling PTY closes. The recorder had already started asynchronous
observer.stop(), but the process was terminated before the manifest and final frames directory were persisted.Keeping signal listeners through finalization protects externally delivered termination. Capturing Ctrl+C as terminal input additionally prevents the package runner from exiting in the first place, so it waits for Midscene to save and return normally.
The temporary Linux acceptance test exposed a second shutdown edge case: libnut keeps a process-wide X11 connection open. Stopping the CLI-owned Xvfb from
destroy()or a Nodeexithandler triggers an XIO fatal error even after the manifest is saved. The CLI now delegates Xvfb shutdown to a detached monitor that waits for the owner process to disappear. SDK/API-owned Xvfb instances still stop synchronously during normaldestroy().Follow-up safeguards
The finalization guard distinguishes automatic follow-up signals from an explicit second terminal Ctrl+C. SIGTERM and SIGHUP remain absorbed while saving, but pressing Ctrl+C again restores stdin and exits with the conventional SIGINT code 130. In Linux headless mode, the detached monitor keeps the display alive through representative-frame capture and CLI teardown, then removes it after process exit.
Validation
pnpm run lintpnpm exec nx test @midscene/shared(500 tests passed)pnpm exec nx test @midscene/computer(96 tests passed)pnpm exec nx run-many -t build -p @midscene/shared @midscene/computer @midscene/androidR5CN90V1AYP) through a pnpm package-runner PTY; Ctrl+C exited with code 0 and saved a v1 observation manifest containing 14 frames and 10 screenshotsmidscene-android assert --record <manifest> --prompt "The observation shows the Samsung Android device transitioning from the home screen to the Settings screen."(Assertion passed.)midscene-computer record startCLI through pnpm in a PTY on Ubuntu/Xvfbrecording_stopping,Observation record saved,command_done: ok, and exit code 0midscene-computer assert --recordcommand against that manifest (Assertion passed.)Prepatch
1.12.2-beta-20260827111913.0(@midscene/core,@midscene/android, and@midscene/computer)