Skip to content

bug: readiness-timeout cleanup reports proven while a blocked Metro survives as an orphan #1013

Description

@Lykhoyda

When managed Metro misses its readiness deadline while its main thread is blocked, the failed-start cleanup reports success but leaves a Metro grandchild running as an orphan. The orphan is reparented to launchd inside the launcher's process group, keeps the session's metro.log open and ignores SIGTERM even after the stall ends. The refusal is still an ordinary METRO_START_UNAVAILABLE with cleanup counted as proven, and the product's own rn_session stop_metro then answers alreadyStopped: true without seeing it. This is likely a specific root cause behind #969.

Evidence (independent QA of #998 at 2e183515c6266a7899de67d1022f7de0876f7aa8, plugin 1.0.6, iOS 26.4 simulator, 2026-09-10; report: #998 (comment))

  • Reproduced in 2 of 2 synchronous-stall failures (default 90 s budget with a 150 s stall; 30 s configured budget with a 60 s stall). Refusal: METRO_START_UNAVAILABLE: allocated Metro did not become authoritative (launcher alive at deadline; readiness deadline 90000 ms expired: listener absent 485 probes, probe unknown 0, unowned listener none) at 90.13 s, exit 2.
  • Afterwards stop_metroalreadyStopped: true, while ps showed the orphan (ppid 1, launcher pgid) holding the log open. SIGTERM was ignored; SIGKILL was needed.
  • Control: with an async stall (event loop free, 20 s budget), Metro exited on SIGTERM and nothing was orphaned. The defect needs a Metro that is alive with a blocked main thread at the deadline, a plausible shape for a slow synchronous cold start.

Repro

  1. Prepend an env-gated synchronous stall (for example Atomics.wait for 150 s) to the app's metro.config.js.
  2. Build through the integrated launcher with the default readiness budget.
  3. After the refusal, run rn_session stop_metro and list processes for the session's Metro port/log.

Impact: a leaked Metro survives with no owner the session can see, holds session resources, and can contend with the next attempt (#969). Cleanup is misreported as proven.

Suggested direction: in stopManagedMetroProcesses (packages/rn-dev-agent-core/src/session/managed-metro.ts), when no listener was ever observed, do not treat "launcher gone and port absent" as proven. After SIGTERM, require the launcher's process group to be empty (the processGroupExists check managed-metro-enforcement.ts already uses) and escalate to SIGKILL on the group before returning. Regression test: a SIGTERM-ignoring child.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-qaIndependent dogfood QA on test-app simulator; Orchestrator posts a PR comment report

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions