Skip to content

Init job duration: ~60s of every ~75s run is a telemetry du of nix-persist that times out and returns 'unknown' #5717

Closed

Description

@dezren39

Init job duration breakdown — why every init run costs ~65–97s (measured 2026-11-04)

Follow-on from #5700 (the re-run loop, fixed). The loop is fixed, but each individual run of ~/tools/init.sh still costs 68–97s (boot 6989413c runs: 71/68/73/97/79/75s). Drew asked where the time goes. Per-step timings from ~/logs/init.log + ~/logs/init.jsonl, cross-checked against ~/tools/init.sh:

Ranked breakdown (final SUCCESS run, 23:10:30→23:11:45 UTC, init_secs=75)

# Step Seconds Why it's slow What would cut it
1 du -sh /home/hatch/nix-persist (deferred-telemetry block, init.sh:207) ~60 (the full timeout 60) Recursive du over the whole persisted nix store tree (15,247 store paths) on a loaded 4-CPU box. It times out and returns unknown in every recent run — the value is never even obtained. ~80% of the entire init cost buys a telemetry field nobody reads. Delete it, or cache it (compute at most once per boot into a state file), or move it to the detached-retry pattern the sysstat restore already uses. Any of these cuts init to ~15s.
2 Quota snapshot (/opt/hatch/bin/subscription-status status, init.sh:220, timeout 30) ~2–10 (varies; budget 30) Network/API call on every init run. Cache per boot; it is telemetry, not a restore step.
3 Net check (init.sh:210–216) ~3–4 1 HEAD + 3 full GET samples to cache.nixos.org through the CONNECT proxy (net_lat alone averaged 2.2s). One sample suffices for a liveness check.
4 Snapshot counts (ls /nix/store | wc -l, profile bins, init.sh:218–219) ~1–3 Directory listing over 15k entries. Negligible alone; cache with #1 if kept.
5 All named restore steps combined (nix-ensure 1–2s, nix-profile-sync 1s, nix-wrapper/bash-wrapper/go-check/rust-check/services-verify 0s each) ~4 total — The actual restore work is already fast. Nothing to fix.
6 sysstat restore (init.sh:280–306) 0s when apt lock held (deferred instantly, post-#5700 fix); minutes when the lock is free Its apt-get runs inline under a 600s budget; the platform os-intent replay's own apt-get update fetched 41.7 MB in 10m33s at ~66 kB/s through the proxy on this boot. On a boot where init wins the lock race, init eats that cost inline. Always detach (never run apt inline in init); the deferred-retry path already converges it.

The amplifier (context, fixed by #5700 but worth restating)

While FAILURES≥1 kept the boot marker unwritten, init-ensure re-spawned this full ~65–75s init on every agent prelude, all day, every boot — the ~65s cost was paid hundreds of times per day, and the log shows overlapping invocations serializing (another init already running, exiting). Any future FAILURES≥1 cause re-arms that herd at ~75s per prelude. Shrinking the run (items 1–3) shrinks the blast radius of any recurrence; a rate-limit on init-ensure respawns would cap it independently.

Bottom line

Init's real work is ~4s. ~60s is a single telemetry du that times out and returns unknown. Removing/caching it (plus detaching the sysstat apt path unconditionally) takes a run from ~75s to ~10–15s.

Evidence: ~/logs/init.log lines 15997–16016 (two full runs, step-stamped), ~/logs/init.jsonl (424 runs), ~/tools/init.sh lines 199–306. Filed from the 2026-11-04 laptop-session coordinator run (Phase 1 addition at Drew's request).

Activity

  1. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  3. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  4. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  5. added
    queue/claimedQueue worker lifecycle state
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  6. 12 remaining items

  7. added
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  8. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  9. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triaged

  10. added
    status/triagedTriaged and routed (see agent note)
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
  11. dezren39 commented on Nov 8, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: done
    task: 12266
    worker: repo-worker-code
    lane: code-h
    issue: #5717
    summary: Re-triage (task 12266, direct lane) under the triage doctrine. Verdict: NO LONGER REPRODUCIBLE — the headline cost was removed from the live init script, verified against fresh runtime logs. Closing as an explicit verified closure with evidence.

    Evidence (fresh, 2026-11-08, sandbox host where ~/tools/init.sh actually lives — this was never a tracked file in developing-today/code, as the task 10145 triage already established):

    • ~/tools/init.sh (modified 2026-11-07) lines 205-212: "nix-persist size: NOT measured here anymore (Drew ruling 2026-11-05, code#5701). The detached cache-file measurement that replaced the in-init du was dropped entirely: the value read 'unknown' 138 times, nothing consumed the cache file, and the code#5925 telemetry rollup covers disk usage via the cache-writer pattern." The ~60s du — ranked test #1 in this issue at ~80% of run cost — is gone entirely, not just cached.
    • The net check (ranked Bump build/buck/preludes/buck2-prelude from 3a02ea3 to 6b71c24 #3) was also improved in the same script: the 3 latency samples now run in PARALLEL (comment at the snapshot block: sequential samples summed to ~22s of the 97s run on 2026-11-04).
    • Fresh ~/logs/init.jsonl, last three boots: init_secs 6 (2026-11-07 23:21Z), 19 (2026-11-08 01:24Z), 10 (2026-11-08 03:30Z) — against the 68-97s runs this issue measured. nix_persist still reports "unknown", now truthfully by design (not measured) rather than after a wasted 60s timeout.
    • Residual minor items from the breakdown, recorded for completeness, not routed as a fix packet: the quota snapshot still runs inline under timeout 30 (bounded, ~seconds), and the sysstat restore can still run its installer inline under timeout 600 on a boot where the collector units are inactive — but lock contention and mirror stalls now DEFER with a detached retry instead of counting as failures, and no recent boot shows it eating minutes. If either ever dominates a run again, the init.jsonl timings will show it and a fresh issue can be filed on that evidence.

    Disposition: issue #5717 closes with this verified evidence; task 12266 completes as no_longer_reproducible. No fix packet is created — there is no remaining real work scoped to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

status/triagedTriaged and routed (see agent note)status:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions