iOS simulator: in-flight `prepare ios-runner` keeps retrying the old runner port after the runner is relaunched on a new port
维护者通常 1 天内回复
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 35/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 停滞
- 技术栈
- ios, node.js, typescript
调研方向
Start with the ios_runner_connect retry loop in runner-startup-transport.js and trace how it handles a stopped or replaced runner session. Check the child process exit and signal state, and how the daemon updates session ports during relaunch. Done means an in-flight prepare request follows the new session or fails promptly with a clear replacement error; open pull request #4273 indicates work is already underway.
由索引模型根据 Issue 内容生成。
描述
Environment
- agent-device 0.21.27 (CLI through
npx, daemon mode) - Xcode 26.3
- iOS 26.2 simulator, x86_64 host (macOS 15, Darwin 24.6)
- Command:
agent-device prepare ios-runner --timeout 240000 - Host load average during the failing runs: 5–43 (1-minute)
Summary
The first xcodebuild test-without-building ends after exactly 45 s with ** BUILD INTERRUPTED **.
The daemon then runs build-for-testing and starts a new runner on a new port.
The new runner logs AGENT_DEVICE_RUNNER_LISTENER_READY.
The in-flight prepare request does not move to the new session.
It retries the old port until the full 240 s budget is used, then fails with Runner did not accept connection.
A longer --timeout does not help: the new runner is ready more than 2 minutes before the request gives up.
Three runs, same pattern
| Run (UTC) | Port the request retries | Port of the relaunched runner | New runner ready | Request exhausted | Attempts |
|---|---|---|---|---|---|
| 2026-11-06 00:23:43 | 61846 | 62919 | 00:26:10 | 00:27:44 | 957 / 957 |
| 2026-11-06 01:07:40 | 56766 | 58194 | 01:10:13 | 01:11:40 | 960 / 960 |
| 2026-11-06 02:15:17 | 57548 | 58795 | 02:17:05 | 02:19:18 | 960 / 960 |
In each run, the first test-without-building process ends at 00:45 elapsed.
Timeline (run 3, UTC)
02:15:11 xcodebuild test-without-building starts (pid A, port 57548)
02:15:17 prepare request starts
02:15:18 ios_runner_session_reuse sessionId=<SIM_UDID>:57548:… ready=false
02:15:18 ios_runner_readiness_preflight_skipped command=uptime reason=read_only_startup_command
02:15:18 retry ios_runner_connect attempt 1/960, remainingMs=239865
02:15:56 pid A ends after 45 s, runner.log: ** BUILD INTERRUPTED **
02:15:57 xcodebuild build-for-testing starts (58 s)
02:16:55 xcodebuild test-without-building starts (pid B, port 58795)
02:17:05 runner.log: AGENT_DEVICE_RUNNER_LISTENER_READY, AGENT_DEVICE_RUNNER_PORT=58795
02:19:18 retry ios_runner_connect exhausted 960/960
02:19:18 ios_runner_command_send error: Runner did not accept connection
02:19:18 runner_xctestrun_cache action=clean reason="Runner did not accept connection"
02:19:18 request_failed: prepare ios-runner timed out
02:19:20 daemon.log ios_runner_session_detach_skipped sessionId=<SIM_UDID>:58795:…
The request log shows only one ios_runner_session_reuse event (port 57548).
The relaunch on port 58795 is not in the request log.
Request log excerpt (run 3)
{"phase":"ios_runner_session_reuse","command":"prepare","data":{"sessionId":"<SIM_UDID>:57548:1793931310734","ready":false}}
{"phase":"retry","command":"prepare","data":{"phase":"ios_runner_connect","event":"attempt_failed","attempt":1,"maxAttempts":960,"elapsedMs":5,"remainingMs":239865}}
{"phase":"retry","command":"prepare","data":{"phase":"ios_runner_connect","event":"exhausted","attempt":960,"maxAttempts":960,"elapsedMs":239871,"remainingMs":0}}
{"phase":"ios_runner_command_send","level":"error","command":"prepare","durationMs":239871,"data":{"command":"uptime","readOnly":true,"sessionReady":false,"timeoutMs":239870,"error":"Runner did not accept connection"}}
{"phase":"request_failed","command":"prepare","data":{"error":"prepare ios-runner timed out"}}
daemon.log excerpt (run 3)
{"ts":"2026-11-06T02:19:20.493Z","phase":"ios_runner_session_detach_skipped","session":"daemon","data":{"sessionId":"<SIM_UDID>:58795:1793931415348"}}
Where we think it happens (reading the published dist)
- In
runner-startup-transport.js, the connect loop (phase: ios_runner_connect) readsendpoint.portonce and resolves the route once before the retry loop.
For simulators the route ishttp://127.0.0.1:<port>/commandand is not resolved again inside the loop. - The per-attempt guard stops the loop only when
session.child.exitCodeis notnull.
In Node.js, a child that a signal ends hasexitCode === nulland a non-nullsignalCode.
The session stop path sendsSIGTERM/SIGKILL.
So if the 45 s launch budget (runner_launch_budget_exhausted) stops the firstxcodebuild, the in-flight loop does not see it.
This is our hypothesis. We did not confirm the exit signal of pid A. - From 0.21.30, the guard also returns early when
session.state !== 'starting', but it does not stop the loop.
The session object stays the old one, so the loop keeps the old port.
We checked 0.21.28 to 0.21.36 and 0.21.37-nightly.20261103.128.
The connect loop has the same shape in all of them.
Expected behavior
When the daemon invalidates or replaces the runner session that a request waits on, the request does one of these:
- moves to the new session and its port, or
- fails fast with a clear "runner session replaced" error so that the caller can retry.
Workaround we use
None that works reliably. A longer --timeout does not help. Pre-warming with prepare ios-runner did not lower the failure rate (11 runs).
- 主要语言
- TypeScript
- 星标
- 5.3k
- 派生
- 377
- 平均合并
- 14 小时 6 分钟
- 30 天内合并 PR
- 650
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
callstack/agent-device 的其他 Issue
-
iOS alert wait: the last poll can get ~30 ms and turns "no alert" into a failed read可能已有人在做 @pcbeingused333 于 6 天前认领。 未关闭bug ready-for-agent
难度 2/5 1-3 小时 新手友好度 77/100
callstack/agent-device#4018 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
callstack/agent-device#1869 ·
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 48/100
callstack/agent-device#4274 ·
维护者通常 1 天内回复
-
bug ready-for-agent
难度 4/5 3-5 天 新手友好度 48/100
callstack/agent-device#4264 · 1 条评论 ·
维护者通常 1 天内回复
-
bug ready-for-agent
难度 3/5 1-2 天 新手友好度 62/100
callstack/agent-device#4262 · 1 条评论 ·
维护者通常 1 天内回复
查看 callstack/agent-device 的全部 Issue
相似的 Issue
-
The sample email preview's ResizeObserver is never disconnected and keeps raising errors after leaving Settings可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭bug
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
area:ui bug effort:S priority:P2
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
Typo in WSL project description on Projects page可能已有人在做 @akhil9tiet 今天认领。 未关闭
难度 1/5 1 小时以内 新手友好度 75/100
microsoft/opensource.microsoft.com#1066 · 1 条评论 ·
-
ArcGIS Maps SDK for JavaScript c-carousel calcite-design-tokens enhancement impact - p3 - not time sensitive needs triage
难度 2/5 1-3 小时 新手友好度 68/100
Esri/calcite-design-system#15565 ·
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 68/100
linkwarden/linkwarden#1891 ·
维护者通常 1 天内回复