Configurable boot deadlines for full iOS simulators and Android emulators
メンテナーはふだん 1 日以内に返信
評価
この issue はまだ評価されていません。
説明
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 forios.full.bootTimeoutMsandandroid.bootTimeoutMs.src/contract/schemas.ts:configSchemagains 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
makingsweep (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.bootTimeoutMsplus 600 s (1200 s at the default).avdmanager createhas 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
--fulldevice, a runtime below the floor, or a recovery boot keeps the normal deadline": the normal deadline becomesios.full.bootTimeoutMs. - ADR 0060 §5: "
ios.slim.bootTimeoutMskeeps 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 withBootTimeoutError: prepare full; prepare slim on an iOS 18.4 runtime; recover full; recover slim; prepare slim on iOS 18.5 keepsios.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 withBootTimeoutError: 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.bootTimeoutMsis: 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.bootTimeoutMs600 s, listing 1000 s into the make: kept; listing past the larger of 900 s and twiceandroid.bootTimeoutMsplus 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:changedpasses, 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-failedrow 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-
simctlcall, 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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
callstackincubator/simlock のほかの issue
-
agent-device devices fails with "Request ID is already in flight" when a token holds several leases on one worker対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープンbug:new platform:ios
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
callstackincubator/simlock#1293 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
request:new
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
callstackincubator/simlock#1248 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug:new
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
callstackincubator/simlock#1234 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug:new
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
callstackincubator/simlock#1229 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
os:windows request:new
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
callstackincubator/simlock#1071 ·
メンテナーはふだん 1 日以内に返信
callstackincubator/simlock の issue をすべて見る
似ている issue
-
Navbar avatar and name stay stale after saving profile changes対応中かも @alexechoi が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
marmelab/atomic-crm#416 ·
メンテナーはふだん 1 日以内に返信
-
feature-request
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
bluesky-social/social-app#12343 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
lucide-icons/lucide#5165 ·
メンテナーはふだん 1 日以内に返信
-
[Feature] Preferences - Keep the theme selection popover open after selection for quick previewオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
marktext/marktext#6033 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
area:desktop bug has repro platform:macos
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
anthropics/claude-code#107903 ·