Configurable boot deadlines for full iOS simulators and Android emulators

已关闭
#1,315 0 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@V3RON 已经在做这个了。

开始于 2026年11月5日。

  • #1321 来自 @V3RON —— 已合并

评估

这个 Issue 还没有评估数据。

描述

task:ready

Part of #1311.

Scope

An operator sets how long a full iOS simulator boot (ios.full.bootTimeoutMs) and an Android emulator boot (android.bootTimeoutMs) may take. Both default to 300 s, up from today's fixed 120 s (iOS, F1) and 180 s (Android, F8). The whole feature in one PR: two config keys, the two drivers, the daemon wiring, config.get, the docs.

In short

A full iOS boot now waits ios.full.bootTimeoutMs (300 000 ms unless set, counted from the end of simctl boot) and an Android boot waits android.bootTimeoutMs (300 000 ms unless set, counted from the emulator's spawn) before giving up. A slim iOS boot keeps ios.slim.bootTimeoutMs. The timeout's message stays Timed out waiting for device to boot: <device id> (F13).

flowchart LR
  A[config.json] --> B[loadConfig]
  B --> C[discoverDrivers]
  C --> D[iOS driver]
  C --> E[Android driver]
  D --> F["full boot, recovery boot, seed boot: ios.full.bootTimeoutMs (changed)"]
  D --> G[slim boot: ios.slim.bootTimeoutMs]
  E --> H["every emulator boot: android.bootTimeoutMs (changed)"]
  E --> I[emulator exit wait at shutdown and delete: 180 s fixed]
Config Today After
nothing set iOS full 120 s, Android 180 s 300 s each
ios.full.bootTimeoutMs: 400000 warned Unknown config key: "ios.full.bootTimeoutMs", ignored (F19) full iOS boots wait 400 s
android.bootTimeoutMs: 600000 warned Unknown config key: "android.bootTimeoutMs", ignored (F19) Android boots wait 600 s; exit waits stay 180 s
either key 0, -1 or "300000" warned, ignored daemon refuses to start; message names the key, as ios.slim.bootTimeoutMs does (F5)

If this goes wrong, a user sees one kind of boot (a seed, a recovery, an Android copy) still fail at the old deadline.

Technical spec

Facts

Commit 85944c1f6.

# Fact Source
F1 The iOS full boot deadline is the constant BOOTSTATUS_TIMEOUT_MS = 120_000 src/drivers/ios/index.ts:91
F2 A new iOS seed boots with that constant src/drivers/ios/index.ts:1033
F3 planSlimBoot gives the constant to a recovery boot, a boot without slim options, a non-slim mode and a runtime below iOS 18.5; only a slim prepare on 18.5+ gets slim.bootTimeoutMs src/drivers/ios/index.ts:2561-2586
F4 #bootAndWait runs simctl boot (30 s), then counts one deadline over bootstatus -b and the listapps polls; expiry shuts the device down and throws BootTimeoutError src/drivers/ios/index.ts:1188-1210
F5 ios.slim.bootTimeoutMs defaults to 600_000 and is validated positiveNumber; bad values are refused naming the key src/core/config.ts:1005-1010, src/core/config.ts:1170-1175, src/core/config.test.ts:1187-1190
F6 config.get's output is configSchema, which declares ios.slim.bootTimeoutMs and android.emulator; an undeclared field is stripped src/contract/operations.ts:692-697, src/contract/schemas.ts:1096-1112
F7 The daemon passes config.ios.slim and config.android.emulator to discoverDrivers; AndroidDriver.create gets no readinessTimeoutMs src/daemon/main.ts:482-484, src/daemon/main.ts:1517-1530
F8 Android's boot deadline is DEFAULT_READINESS_TIMEOUT_MS = 180_000, overridable by the readinessTimeoutMs create option and handed to the emulator part src/drivers/android/index.ts:91, src/drivers/android/index.ts:128, src/drivers/android/index.ts:332
F9 waitForReadiness throws BootTimeoutError once readinessTimeoutMs has passed since its startedAt: the spawn for start (every boot), the call itself for a second makeReady of a booting device src/drivers/android/emulator.ts:197-205, src/drivers/android/emulator.ts:305, src/drivers/android/index.ts:591
F10 The same readinessTimeoutMs bounds the wait for an emulator to exit before a delete (waitForEmulatorsToExit) and before SIGKILL at shutdown src/drivers/android/emulator.ts:166, src/drivers/android/emulator.ts:351
F11 An Android seed make boots cold twice through emulator.start src/drivers/android/seeds.ts:588, src/drivers/android/seeds.ts:624
F12 A making seed row this process is making is removed by the sweep once older than SEED_MAKE_CEILING_MS = 900_000 src/drivers/android/seeds.ts:40, src/drivers/android/seeds.ts:165-171
F13 BootTimeoutError's message is Timed out waiting for device to boot: <deviceId> src/core/driver.ts:653
F14 iOS joins concurrent makes of one seed kind, so its 300 s stale-making sweep never runs during a make src/drivers/ios/index.ts:966-971, src/drivers/ios/index.ts:996-1002
F15 Existing tests pin the 120 s seed and full boot timeouts and model a deadline test on a fake clock src/drivers/ios/index.test.ts:874, src/drivers/ios/index.test.ts:1698, src/drivers/ios/index.test.ts:3063-3102
F16 Android tests pass readinessTimeoutMs: 0 to make the exit wait instant before a destroy src/drivers/android/index-lifecycle.test.ts:685
F17 discoverDrivers is exported and tested with scripted runners src/daemon/main.ts:1372, src/daemon/main.test.ts:2247-2274
F18 simlock config set validates through loadConfig and prints Updated <key> in <path>; takes effect on daemon restart. src/cli/commands/config.ts:49-70
F19 An unknown config key is warned Unknown config key: "<path>" and ignored src/core/config.ts:1065, src/core/config.test.ts:1173-1183
F20 The website pages that describe boot deadlines (doc lines, no code): the configuration reference row, the slim note and boot-failed row in capacity, the 180 s line in requirements website/src/content/docs/docs/reference/configuration.mdx:197, website/src/content/docs/docs/worker/capacity.mdx:126, website/src/content/docs/docs/worker/capacity.mdx:220, website/src/content/docs/docs/introduction/requirements.mdx:58
F21 The module manuals list both deadlines as having no key src/drivers/ios/AGENTS.md:111, src/drivers/android/AGENTS.md:120
F22 A seed make's steps besides its two boots are bounded at 60 s (shell sync), 60 s (reboot -p), 60 s (power-off wait), 60 s (snapshot save), 5 s (snapshot list), 5 s (emu kill) and the 180 s exit wait: 430 s; avdmanager create has no limit src/drivers/android/seeds.ts:39, src/drivers/android/seeds.ts:588-594, src/drivers/android/seeds.ts:637, src/drivers/android/seeds.ts:657-668, src/drivers/android/emulator.ts:344, src/drivers/android/emulator.ts:351
Modules touched

Searches: BOOTSTATUS_TIMEOUT_MS (5 hits, one file), readinessTimeoutMs (src, non-test: android/index.ts, emulator.ts, testing.ts), bootTimeoutMs (src, non-test: core/config.ts, contract/schemas.ts, drivers/ios/index.ts, daemon/main.ts), SEED_MAKE_CEILING_MS (one file).

  • src/core/config.ts: type, defaults, validators for ios.full.bootTimeoutMs and android.bootTimeoutMs.
  • src/contract/schemas.ts: configSchema gains both.
  • src/daemon/main.ts: passes both to the drivers.
  • src/drivers/ios/index.ts: the full deadline comes from the option.
  • src/drivers/android/index.ts, emulator.ts, seeds.ts: the boot deadline comes from the option; the exit waits keep 180 s; the seed make ceiling covers two boots.
  • Docs: F20 pages, F21 manuals.
flowchart LR
  config["core/config.ts (changed)"] --> main["daemon/main.ts (changed)"]
  main --> ios["drivers/ios/index.ts (changed)"]
  main --> android["drivers/android (changed)"]
  schemas["contract/schemas.ts (changed)"] --> dispatcher[daemon/dispatcher.ts config.get]
Contract and event changes

configSchema (config.get's output, F6) gains ios.full: { bootTimeoutMs: number } and android.bootTimeoutMs: number. This PR bumps the protocol by one. No event changes. Bounds come from loadConfig: a positive number, else the daemon refuses to start naming the key (F5).

Other code on the same state

Searches: the two deadlines' uses (F1-F4, F8-F11), the stale-making sweeps (STALE_MAKING_MS, SEED_MAKE_CEILING_MS), boot estimates (COLD_BOOT_ESTIMATE_MS, SEED_MAKE_ESTIMATE_MS), the gateway's leaseRequestTimeoutMs.

  • iOS stale making sweep (F14): never runs during a make of its kind, so a longer seed boot cannot be swept. No change.
  • Android seed sweep (F12): a make takes two boots plus steps bounded at up to 430 s in all (F22); at the 300 s default that is about 1030 s, past today's 900 s, so a running make would be removed. The ceiling becomes the larger of 900 s and twice android.bootTimeoutMs plus 600 s (1200 s at the default). avdmanager create has no limit of its own, as today.
  • Boot estimates and Doctor's stall threshold read the estimate, not the deadline: unchanged.
  • Gateway leaseRequestTimeoutMs (5 min): a cold lease that makes a seed can now take up to two deadlines. Slim already can (600 s). No change.
Failure modes
Call Outcome What happens Limit, counted from
iOS bootstatus -b + listapps ok device ready ios.full.bootTimeoutMs, from the end of simctl boot
iOS bootstatus -b + listapps no answer in time best-effort shutdown, BootTimeoutError (F4) same
Android readiness poll ok device ready android.bootTimeoutMs, from the spawn (a second makeReady: from that call)
Android readiness poll no answer in time SIGKILL, BootTimeoutError (F9) same
Android emulator exit at shutdown or delete never exits SIGKILL / refuse delete, as today 180 s, from the kill request

A restart in the middle writes nothing new: the deadline is read at start. Two boots at once each count their own deadline.

Rules in play
  • ADR 0002 §8: "a --full device, a runtime below the floor, or a recovery boot keeps the normal deadline": the normal deadline becomes ios.full.bootTimeoutMs.
  • ADR 0060 §5: "ios.slim.bootTimeoutMs keeps its meaning ... and its default": unchanged.
  • Contract rule: "Every change to a contract shape bumps it by one in the same PR": bumped.
  • Documentation rule 9: the public config surface changes, so the F20 pages change in this PR.
Tests

Seams: IosSimctlDriver in src/drivers/ios/index.test.ts (model: the slim deadline test, F15), AndroidDriver in src/drivers/android/index-lifecycle.test.ts, loadConfig in src/core/config.test.ts, Dispatcher in src/daemon/dispatcher.test.ts, discoverDrivers in src/daemon/main.test.ts. The tests pinning 120 s (F15) move to 300 s. The Android tests that pass readinessTimeoutMs: 0 to make the exit wait instant (F16; index-lifecycle.test.ts:712, :739, :771) advance the fake clock past 180 s instead; Tests line 4 extends the one at 712. About 21 test files build a full config by hand and gain the two new fields.

  • An operator's full iOS boot waits ios.full.bootTimeoutMs, then fails with BootTimeoutError: prepare full; prepare slim on an iOS 18.4 runtime; recover full; recover slim; prepare slim on iOS 18.5 keeps ios.slim.bootTimeoutMs; key unset (300 s) and set (400 s).
  • A provision that makes a new iOS seed boots the seed within ios.full.bootTimeoutMs: key unset (300 s); key set (400 s).
  • An Android boot waits android.bootTimeoutMs, then fails with BootTimeoutError: prepare from the snapshot; recover; a seed's two cold boots; a second makeReady while the device still boots; key unset (300 s) and set (600 s).
  • An Android shutdown or delete waits 180 s for the emulator to exit, whatever android.bootTimeoutMs is: key 600 s, emulator never exits.
  • An Android seed still being made is kept by a source listing while its two boots may still run: android.bootTimeoutMs 600 s, listing 1000 s into the make: kept; listing past the larger of 900 s and twice android.bootTimeoutMs plus 600 s: removed.
  • An operator's config sets the two keys, or leaves them out: both unset (300000 each); both set; 0, -1, "300000" each refused naming the key.
  • An admin reads the config and sees both keys: defaults; set values.
  • A worker starts its drivers with the two keys from its config: iOS key set; Android key set.

Done when

  • pnpm test:changed passes, and holds the eight Tests lines above.
  • The configuration reference has a row for each key with its default (300000, 5 min); capacity's slim note, its boot-failed row and the requirements 180 s line point to the right key.
  • The iOS and Android manuals' timer tables name both keys.

Out of scope

  • Admission under memory pressure (#1246).
  • The boot estimates, the BootTimeoutError text, the 30 s per-simctl call, the slim readback, Android's snapshot save and power-off waits.

Depends on

Written by an agent.

主要语言
TypeScript
星标
535
派生
21
平均合并
8 小时 58 分钟
30 天内合并 PR
472

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

callstackincubator/simlock 的其他 Issue

查看 callstackincubator/simlock 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。