Skip to content

[build-tools] Start independent device session setup in parallel - #4490

Closed
szdziedzic wants to merge 2 commits into
mainfrom
szdziedzic-claude/parallel-session-startup
Closed

szdziedzic wants to merge 2 commits into
mainfrom
szdziedzic-claude/parallel-session-startup

Conversation

@szdziedzic

@szdziedzic szdziedzic commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Why

I read the worker logs of 12 simulator sessions from 2026-09-29 (6 iOS, 6 Android). The setup is strictly sequential, but some parts do not depend on each other:

Part iOS Android
Device boot ~21–24 s 65–76 s
agent-device install + daemon + tunnel 2.3–4.6 s ~1.7 s
Session host + web preview 5–7 s 30–32 s, of which ~25 s is apt install ffmpeg
Created → ready 47–112 s 185–196 s
  • ffmpeg is only needed by expo-device-hub (Android). It does not need the emulator, but it ran after the boot.
  • The agent-device daemon and the session host do not use each other, but the host started only after the daemon and its tunnel were up.

How

  • eas/start_android_emulator: when DEVICE_RUN_SESSION_ID is set (only simulator session jobs have it), start ensureFfmpegInstalledOnceAsync in the background at the start of the step. The call is not awaited, and it never rejects (it catches and logs its own errors). startDeviceSessionHostAsync still awaits the same install, which then usually finishes during the boot. Other users of the step (for example Maestro jobs) are not affected.
  • eas/start_agent_device_remote_session: start two chains with Promise.all:
    1. daemon install → daemon credentials → agent-device tunnel
    2. session host → web preview
    • Each chain stores what it started.
    • The finally block waits for both chains (Promise.allSettled) before the teardown, because Promise.all rejects on the first failure while the other chain can still be starting.
    • This also fixes a leak: before, a daemon whose credentials never appeared was not stopped, because it was started outside the try.
  • No step, input or step order changes, so universe does not change.

Expected gain (estimates from the logs above, not yet measured with this change):

  • Android: about 25 s per session. ffmpeg overlaps the 65–76 s boot.
  • iOS: about 2–4.5 s. The daemon chain overlaps the serve-sim start.
  • Android also gets about 1.7 s from the parallel daemon.

Risks:

  • apt now runs during the emulator boot (network, disk, CPU). If it slows the boot, we see it in the step timings.
  • The session host picks a free port (findAvailablePortAsync) while the daemon may bind its own port at the same time. Before, the daemon was already listening. A collision is possible but unlikely.

Test Plan

  • New tests in startAndroidEmulator.test.ts:
    • ffmpeg starts before the emulator, and the boot does not wait for it (the mock never settles).
    • No ffmpeg install outside a device run session.
  • New tests in startAgentDeviceRemoteSession-orchestration.test.ts:
    • The session host starts before the daemon credentials exist. A mock releases the credentials only after the host started, so a sequential startup would hang.
    • When the session host fails, the daemon and its tunnel stop.
    • When the daemon fails, the session host and the daemon process stop.
    • Against the previous code, the parallel test times out and the daemon-failure test fails (the daemon was not stopped).
  • yarn jest-unit for the changed suites: 25 tests pass.
  • The whole build-tools suite: 1584 tests pass. Only repack.test.ts fails (3 tests) with spawn yarn ENOENT, both with and without this change. It is a problem of my local setup; the same tests pass in CI.
  • yarn typecheck, oxlint and oxfmt pass.
  • After deploy: compare the step timings in the worker logs (Installed ffmpeg. → Web preview URL, and the step Start agent device until ready) with the table above, using the EAS Simulator benchmark harness.

🤖 Generated with Claude Code


Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.75%. Comparing base (1c61614) to head (4edb600).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4490      +/-   ##
==========================================
+ Coverage   72.74%   72.75%   +0.02%     
==========================================
  Files         980      980              
  Lines       47040    47051      +11     
  Branches    10168    10171       +3     
==========================================
+ Hits        34214    34229      +15     
+ Misses      11830    11826       -4     
  Partials      996      996              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

szdziedzic and others added 2 commits September 29, 2026 16:49
- start_android_emulator: in a device run session (DEVICE_RUN_SESSION_ID
  is set), start the ffmpeg install in the background when the step
  starts. It ran after the boot and took about 25 s with apt. The session
  host still waits for the same install.
- start_agent_device_remote_session: start the agent-device daemon (with
  its tunnel) and the session host (with the web preview) in parallel.
  The teardown waits for both chains and stops what each one started,
  which also stops the daemon when its credentials never appear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@szdziedzic
szdziedzic force-pushed the szdziedzic-claude/parallel-session-startup branch from 81382c4 to 4edb600 Compare September 29, 2026 14:49
@szdziedzic
szdziedzic changed the base branch from szdziedzic-claude/warm-ios-runner to main September 29, 2026 14:49
@github-actions

Copy link
Copy Markdown

✅ Thank you for adding the changelog entry!

@szdziedzic

Copy link
Copy Markdown
Contributor Author

Closing: we are moving the device run session startup into a single step, so the setup can run in parallel as much as possible. A new PR replaces this one.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant