fix(mobile): retain leased device sessions during worker replacement

Merged
KN
10d ago
+838-91

Why

  • After a failed test, worker cleanup closed the leased device session. Another session could claim the device before the replacement started, causing later tests to fail with "Device is already in use". Addresses #792.

What changed

  • Keep a healthy session during worker replacement. A revocable EngineDisposeContext.reuseSignal distinguishes replacement from final cleanup without calling the disposal hook twice.
  • Close the session on forced shutdown, IPC disconnect, or an unconfirmed native recording stop. Retry a retained provider recording stop before another attempt on the same worker.
  • Validate retention grants in the cloud-provider example, releasing declined grants before acquisition fails. Update lifecycle docs, TestMu wording, and release notes.
flowchart LR
  A[Mobile worker retires] --> B{Leased, reuse permitted, no unconfirmed native recording?}
  B -- Yes --> C[Replacement resumes session]
  B -- No --> D[Close session]
  C --> E[Run closes session and releases lease]

Scope

  • Covers worker replacement and cleanup. Explicit device.closeApp() still ends the session and drops its claim.
  • Cleanup remains bounded. A worker killed with SIGKILL or one that already exited cannot release daemon resources. Revocation only applies while disposal is pending.
  • Failed external recording stops keep the device claim. The worker retries while it owns the handle; providers must clean up remaining external recordings at lease release/run end. Session close cannot guarantee that a cloud recording stops.

Blast radius

  • Mobile keeps its existing e2e >=0.15.0 <1 peer range. Older cores omit reuse permission, so mobile closes the session during disposal. The engine owns the session; the provider owns the lease.

  • Open finding from Cubic: a provider video recovered after its original attempt report closes is cleaned up but may be absent from that report. The built CLI reproduces this loss. Reporting late artifacts across worker IPC and hosted sessions needs a scope decision; this finding remains open.

Verified

Ran it locally: yes

  • Built CLI, real subprocess workers, actual mobile engine, simulated backend. Checkers reproduce parent loss, third Ctrl-C, native recording-stop failure, and provider recording retry failure before their fixes, then pass here. Healthy replacement also passes. The executable cloud example's declined-grant test fails before its fix and passes after it.
mainthis branch
A competitor claims the device during worker replacement.The competitor is refused; the replacement uses the original lease; run cleanup releases it once.
BUG REPRODUCED parent-crash
BUG REPRODUCED third-sigint
BUG REPRODUCED recording-stop
BUG REPRODUCED provider-retry
PASS parent-crash
PASS third-sigint
PASS recording-stop
PASS provider-retry
  • Native simulator and hosted-provider behavior were not exercised locally. The simulated backend proves runner and engine cleanup behavior, not native daemon locking.

  • pnpm --filter @e2e-dev/testbed test passes, 78 tests and one skipped. Two measured forms pairs against the merge base each execute five tests per build with matching outcomes, steps, and counters. Timing is unresolved under high host load; no performance claim is made.

  • Maintainer follow-up restores the lifecycle comments, separates reuse revocation from worker retirement, names the keep-session decision, and documents native recording reset claim loss. The Cubic stop-confirmation wording is corrected.

  • The packed mobile package typechecks with skipLibCheck: false and closes its session without reuse permission on exact e2e@0.15.0 and e2e@0.21.2. This does not claim current mobile source can compile against the old core declarations.