Configurable boot deadlines for full iOS simulators and Android emulators

オープン
#1,315 コメント 0 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@V3RON がすでに取り組んでいます。

2026年11月5日 から。

  • #1320 @sreejithraman による — オープン
  • #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
平均マージ
9時間 31分
マージ済み PR(30日)
434

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

callstackincubator/simlock のほかの issue

callstackincubator/simlock の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。