Skip to content

Hourly event-loop stalls: bursts of directory events trigger overlapping synchronous resyncs, /health unresponsive up to ~90s #20

Description

@thenotoriousllama

Observed (2026-07-03 production soak, Windows)

A health watchdog polling /health every 60s recorded, over ~7 hours of an otherwise healthy soak:

  • 14:51 local: poll timeout (15s); daemon log shows 8 directory events between 14:51:19 and 14:51:44 each logging "directory event: requesting resync" (test/telemetry, src, scripts, and five library/knowledge dirs)
  • 16:22: /health response took 12.9s
  • 17:52: response took 20.2s
  • 19:52: response took 13.1s
  • 21:23 and 21:24: two consecutive poll timeouts (25s each); healthy again by 21:25

Pattern is roughly hourly, consistent with an external scanner (search indexer, AV, backup) touching directories and emitting directory-level watch events.

Root cause chain

  1. An external hourly scan generates directory-change events across many directories at once.
  2. Each directory event triggers a resync request (the PRD-018c directory-event rule).
  3. The resync's work is synchronous on the event loop: git ls-files spawn for the shared ignore predicate refresh, statSync walk over the tree, and hashing where needed.
  4. Multiple back-to-back resyncs monopolize the event loop; the HTTP server cannot answer /health for 13-90s.

Why it matters

Self-recovering on a dev box, but under fleet supervision a doctor probing /health with a 10-15s timeout would classify the daemon unhealthy during every stall window and could start restart remediation against a healthy process (compounding with the single-instance lock).

Fix directions

  • Coalesce resync requests: at most one queued resync; a burst of N directory events becomes one pass (cheap, biggest win).
  • Let the resync breathe: yield to the event loop between per-file steps (setImmediate batching) or move the walk/hash work off-thread.
  • Consider filtering directory events whose children show no content change before requesting a full resync.

Evidence

Watchdog log excerpts and the daemon log burst are preserved in the 2026-07-03 soak session; the resync trigger timestamps above are from the daemon's registration.cycle log lines.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions