Skip to content

daemon: runtime DB sidecar divergence (deleted-open -wal) refuses all connections until restart; Web GUI hot-retries failed agent loads at ~209 rps with no backoff #2951

Description

@jolestar

Summary

Two independent defects composed into a full Web GUI outage on 2026-09-13 (observed by the long-running GUI observer):

  1. daemon: a runtime DB "sidecar divergence" (deleted-open -wal) makes the connection guard refuse every new connection, so all API endpoints fast-fail 500 until the daemon is restarted — a transient sidecar state escalates into a permanent self-locked outage with no recovery path.
  2. web-gui: while the daemon returned 500, the frontend hot-retried the failed agent detail load with zero backoff at ~209 req/s for 21 minutes (263,356 requests to a single endpoint from one page), amplifying the outage into a self-DDoS.

Timeline (UTC, 2026-09-13)

Time Event
05:00:02 First ERROR holon::runtime_db::connection: runtime db sidecar divergence error=runtime db sidecar divergence detected (deleted-open sidecar); refusing a new connection: db=/home/jolestar/.holon/state/runtime.sqlite, sidecar=-wal, fd=11, open_dev=66311, open_inode=89522540, canonical_identity=None (journal, daemon PID 2427897)
05:00:03 → 05:21:10 Every API request needing a DB connection fast-fails 500 (durationMs=1). Observer recorded 263,378 × 500 + 113 × 503 (~209 rps sustained), dominated by GET /api/agents/holon-growth/skills (263,356)
05:21:10 Operator stopped the daemon (systemd: "Consumed 9h 32min 48.144s CPU time" over a 1h32m uptime ≈ 6.2 cores average)
05:30:30 Daemon restarted; /api/agents/holon-growth/skills returns 200 OK immediately

Context: the daemon was already under heavy lock pressure from #2948 (memory indexer rebuild monopolization; database is locked warnings ongoing, ~200% CPU) in the same window.

Defect A (daemon): deleted-open sidecar → total connection refusal, no self-recovery

Defect B (web-gui): zero-backoff hot retry loop on failed agent loads

  • During the 500 window one agent page issued 263,356 requests to /api/agents/{id}/skills in 21 minutes (~209 rps, no sign of any backoff), each also emitting a console.error ("Failed to load resource: the server responded with a status of 500").
  • Fetch path: client.ts getSkillCatalog(agentId) (web-gui/app/src/runtime/client.ts:995), agent-scoped loads in web-gui/app/src/runtime/runtime-store.ts:2695/2738/2783 (error stored into agentSkillCatalogErrorByAgentId).
  • Whatever the driving loop is (render-triggered refetch or catch-retry), a failing fetch must back off (exponential + jitter, capped) instead of hot-looping. The browser-side amplification contributed most of the 6-core CPU burn during the outage.

Evidence

  • Observer JSONL: events-2026-09-13.jsonl (527,636 lines; 263,491 http_error + 263,491 console, 1:1 paired).
  • journalctl --user -u holon.service excerpts 05:00:02Z–05:21Z.
  • Post-restart curl: GET /api/agents/holon-growth/skills → 200.

Fix directions

  • A: root-cause the deleted-open -wal (likely interplay with heavy WAL/checkpoint churn); consider a safe in-process recovery path (re-resolve canonical identity / reopen) for this divergence class, or at minimum degrade to a bounded refusal with explicit liveness signal instead of a silent permanent 500 wall.
  • B: add bounded exponential backoff (with jitter) for agent detail / skills loads and audit other fetch loops for the same pattern.

Related: #2948 (indexer lock convoy active in the same window), #2940 (prior indexer pacing fix, partial).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions