Daemon startup: wait for a live daemon instead of a fixed 15 s deadline on slow or overloaded hosts
Maintainer thường phản hồi trong vòng 1 ngày
Một pull request liên quan đã được merge.
- #3791 của @thymikee — đã merge
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 35/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- node.js, typescript
Hướng nghiên cứu
Start with startLocalDaemon and waitForDaemonStartup in src/daemon-client/daemon-client-lifecycle.ts; trace how startup results, timeouts, and daemon logs are handled. Then read the existing lifecycle and startup-race tests and the daemon environment-variable documentation. Done when the completion conditions pass, including typed failure reasons, configurable timing, progress reporting, and updated help or docs.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Purpose
On a slow or overloaded host, the CLI kills a healthy daemon that is still starting. The result is daemon_startup_failed, and the run fails before any work starts. This happens on any CI that can clog: shared macOS runners, small Linux containers, Windows runners, and nested virtualization. It also happens on a developer machine under load. A slow host must make startup slower, not fail it.
#3342 records this failure class (more than 12 instances on unrelated diffs since 2026-10-08; re-runs at the same head pass). This issue is the fix contract for that class.
Current behavior (origin/main)
startLocalDaemon in src/daemon-client/daemon-client-lifecycle.ts:
- It sets one wall-clock deadline:
DAEMON_STARTUP_TIMEOUT_MS = 15_000(line 83, used at line 480). waitForDaemonStartup(line 818) polls until the daemon publishes a reachabledaemon.json, or until the process exits, or until the deadline.- At the deadline, the client retires the daemon, even when the process is alive. A
timeoutresult never retries (retryis true only forearly_exit), soDAEMON_STARTUP_ATTEMPTS = 2does not help. Every report showsstartupAttempts: 1. - No setting can change the 15 s budget.
Evidence from run 39019020372 (PR #3760, 2026-10-17):
- The step
pnpm clean:daemontook 70 s on that runner, which shows that the host was overloaded. - The CLI spawned daemon pid 6849 at 09:30:03. The client killed it 15 s later (
cleanupResults: retired / forced / exited). daemon.logwas empty (0 bytes), so the daemon did not reach its first log line. The process was alive but did not get enough CPU.- The same signature occurred on
refactor/host-environment-root(run 39008970059) andfix/provider-not-registered(run 38993655494), which do not contain that PR's commits.
Required behavior
-
Wait for a live daemon. While the spawned daemon process is alive and has not exited, the client continues to wait for registration. A slow start is not a failure.
-
Fail fast on a real failure. If the daemon process exits before it registers, the client reports the failure immediately, as it does now (
early_exit,unproven). -
Keep a hard ceiling. A daemon that stays alive but never registers must not hang the client. The client stops at a ceiling. The default ceiling must be large enough for an overloaded CI host (proposal: 120 s). Measure the slowest successful startup in CI logs before you choose the number.
-
Show progress. The daemon writes startup phase markers (for example
spawned,modules-loaded,lock-acquired,listening,registered) with timestamps, to the place the client already reads (daemon.logtail or the startup metadata). The client can then tell "slow but progressing" from "stuck". If a marker shows progress, the client keeps waiting up to the ceiling. If no marker appears for a long time, the client can stop earlier than the ceiling. Put the stall window next to the ceiling, as one constant. -
Make the budget configurable. An environment variable sets the ceiling, for example
AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS. It applies to the CLI, MCP, and the Node client, because all three usestartLocalDaemon(viaensureDaemon(), #3765 and #3766). Document it with the other daemon environment variables. Do not add CI auto-detection. Rule 1 makes the default safe on every host. -
Use typed failure reasons.
details.kindstaysdaemon_startup_failed. A newdetails.reasontells the caller what happened:startup-exited: the process exited before it registered.startup-stalled: the process is alive, but no progress marker appeared within the stall window.startup-ceiling: the process made progress, but did not register before the ceiling.
Each reason has its own hint. For
startup-stalledandstartup-ceiling, the hint says that the host can be overloaded, and names the environment variable. Callers branch ondetails.reason, never on the message. -
Record timings. The failure details include the time of each phase marker that the client saw, and
startupTimeoutMsshows the effective ceiling.
Example failure payload:
{
"code": "COMMAND_FAILED",
"message": "Failed to start daemon",
"details": {
"kind": "daemon_startup_failed",
"reason": "startup-stalled",
"startupTimeoutMs": 120000,
"phases": { "spawned": 0, "modules-loaded": 41250 },
"hint": "The daemon is alive but made no startup progress for 60 s. The host can be overloaded. Retry, or raise AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS."
}
}
Completion conditions
- A test starts a daemon that is alive but slow (for example a test-only startup delay of 20 s, longer than the old 15 s budget). Startup succeeds, and the client does not kill the daemon.
- A test starts a daemon that exits during startup. The client reports
startup-exitedwithin 1 s after the exit. - A test starts a daemon that stays alive and writes no phase marker. The client reports
startup-stalledat the stall window, not at the ceiling. - A test sets the environment variable to a small value and sees
startup-ceilingwith the newstartupTimeoutMs. - The existing lifecycle and startup-race tests pass without change in meaning.
- The
daemon-clienthelp or user docs name the environment variable and the three reasons. - After the change merges, #3342 gets a
Current state:comment. Then the iOS Smoke preflight step is observed for one week. The issue closes if nodaemon_startup_failedwith reasonstartup-stalledorstartup-ceilingappears below the new ceiling.
Out of scope
- Re-running CI lanes to hide the failure.
- The slow
pnpm clean:daemonstep in.github/workflows/ios.yml(70 s on an overloaded runner). That is a separate CI cost. Report it in #3342 if it repeats.
Dependencies
- #3342: failure-class log and evidence.
- #3765 and #3766 (merged):
ensureDaemon()and attach mode. They callstartLocalDaemon, so the change applies to all clients.
- Ngôn ngữ chính
- TypeScript
- Star
- 5k
- Fork
- 334
- Merge trung bình
- 12 giờ 13 phút
- Pull request đã merge (30 ngày)
- 723
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của callstack/agent-device
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 87/100
callstack/agent-device#3819 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
macOS helper audio-probe always reports -90 dBFS: AVAudioPCMBuffer frameLength set after the copyCó thể đã có người làm @jipeng6036-del đã nhận hôm nay. Đang mởbug ready-for-agent
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
callstack/agent-device#3771 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
callstack/agent-device#1869 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
callstack/agent-device#3832 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Android smoke: first fixture capture stalls before any readable snapshotCó thể đã có người làm @thymikee đã nhận hôm nay. Đang mởbug needs-triage
callstack/agent-device#3831 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của callstack/agent-device
Issue tương tự
-
Edit: Travel Mix (RO)Đang mởcheck:failed streams:edit
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
iptv-org/iptv#55901 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 2 ngày
-
package:ios ships XCFrameworks with absolute symlinks, which SwiftPM refuses to extractCó thể đã có người làm @cusnirvladislav đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
callstackincubator/rock#740 ·
-
S: triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 2 ngày
-
RED ladder stopped @ 4db4ed91Đang mởarea:workflow bug ready-for-human
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
fil-donadoni/tolaria#6108 ·
Maintainer thường phản hồi trong vòng 1 ngày