Skip to content

Darling tier-1 field-incident response: file log + Event Log source, store conf headroom, honest bootstrap status, PG18 docs - #1552

Merged
erikdarlingdata merged 1 commit into
devfrom
feature/darling-diagnostics-and-conf
Jul 17, 2026
Merged

Darling tier-1 field-incident response: file log + Event Log source, store conf headroom, honest bootstrap status, PG18 docs#1552
erikdarlingdata merged 1 commit into
devfrom
feature/darling-diagnostics-and-conf

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Summary

Tier 1 of the 24-server field-incident response (full diagnosis in the incident thread): the sequential first sweep crawling under store pressure was indistinguishable from servers being permanently dropped, because (a) there was no service log anywhere on a by-the-book install, and (b) the viewer rendered "hasn't been reached yet" as red Offline.

Changes

  1. DarlingFileLoggerProvider (new) — rolling file log under %ProgramData%\PerformanceMonitorDarling\logs\darling-service_yyyyMMdd.log; buffered (5s flush), daily rotation, 14-day retention, never-throwing; an ILoggerProvider, so every existing log site lands there with zero call-site changes. PRIMARY diagnostic surface.
  2. Event Log fixed for real installs — source pinned to PerformanceMonitor Darling (matches service name + docs), best-effort CreateEventSource at startup, and the README install steps gain the one elevated New-EventLog line. The provider was always wired, but the recommended NT SERVICE account cannot register a source → every event silently dropped since day one (confirmed in the field report: SourceExists returned false).
  3. Managed store v4 conf block (append-and-heal like v2/v3): max_connections = 200, max_wal_size = 4GB. PG defaults (100 / 1GB) forced back-to-back spread checkpoints under the fleet-bootstrap write burst while Windows backend-spawn churn (error 487) surfaced as transient store write failures. Existing clusters heal on next service-owned start.
  4. "Awaiting first collection"ServerFreshness.NeverCollected band: amber card status + fleet Needs-Attention Warning ("Awaiting first collection") + grey sidebar dot, never the red Offline overlay. MCP get_server_status gains the additive AwaitingFirstCollection status value (existing values unchanged — contract note).
  5. PG 18 doc sweep — bundled runtime is PostgreSQL 18.4 + TimescaleDB 2.28.1 (fetch-script pins); README/darling.sample.json/workflow comments said 17; BYO guidance now "16 or newer, validated against 18".

Contracts

  • MCP get_server_status: additive status value only.
  • Conf blocks: v1-v3 byte-identical; v4 is a new independently-markered block.
  • No store schema changes; no Lite/Dashboard changes.

Testing

Tier 2 (bounded-parallel sweep + cadence jitter) follows as its own PR.

🤖 Generated with Claude Code

…onest bootstrap status

From the 24-server report (sequential first sweep crawling under store
pressure looked like servers being permanently dropped, with no log
anywhere to say otherwise):

- DarlingFileLoggerProvider (new): rolling file log under
  %ProgramData%\PerformanceMonitorDarling\logs, buffered, daily-rotated,
  14-day retention, never-throwing - the PRIMARY diagnostic surface.
  Every existing ILogger call site lands there unchanged.
- Event Log: source pinned to "PerformanceMonitor Darling", best-effort
  registration at startup, and the README install steps gain the one
  elevated New-EventLog line - the provider was always wired but the
  NT SERVICE account can't register a source, so a by-the-book install
  has silently dropped every event since day one.
- Managed store v4 conf block (append-and-heal like v2/v3):
  max_connections = 200, max_wal_size = 4GB. PG defaults (100/1GB) are
  toy-sized; the fleet bootstrap burst forced back-to-back spread
  checkpoints and backend-spawn churn (Windows error 487).
- "Awaiting first collection": never-collected is a distinct freshness
  band (amber card + fleet Warning + grey sidebar dot) instead of the
  red Offline overlay - "queued, not reached yet" is the truth during
  bootstrap. MCP get_server_status gains the additive
  AwaitingFirstCollection value.
- PostgreSQL 18 doc sweep: the bundled runtime has been PG 18.4 +
  TimescaleDB 2.28.1 since the runtime bump; README/sample/comments
  said 17.

Tests: Darling suite 2151 passed / 0 failed (Release); new pins for
the v4 block, the NeverCollected band (cards, fleet, sidebar), and
updated freshness pins.

Tier 2 (bounded-parallel sweep + cadence jitter) follows separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@erikdarlingdata
erikdarlingdata merged commit bfdb300 into dev Jul 17, 2026
2 checks passed
@erikdarlingdata
erikdarlingdata deleted the feature/darling-diagnostics-and-conf branch July 17, 2026 17:31
pull Bot pushed a commit to ehtick/PerformanceMonitor that referenced this pull request Jul 22, 2026
…itter (erikdarlingdata#1553)

Tier 2 of the 24-server field-incident response (tier 1 was erikdarlingdata#1552). The service
swept the fleet strictly sequentially -- one foreach over every server, every step
awaited inline -- so under store distress one server's 3+ minute first-connect work
left the alphabetical tail unreached for tens of minutes (indistinguishable from a
permanent drop), and every 15s cadence boundary re-herded all servers at once.

Fire-and-track sweep (D2/D3): the loop now LAUNCHES each server's collection body
(new ProcessServerSweepAsync, tracked per-server in InFlightSweep) without awaiting
it, falling straight through to the fleet-level reload/purge/disk-check steps, so one
slow or hung server can no longer head-of-line-block the fleet. Concurrency is bounded
to N=4 (MaxConcurrentServerSweeps, hardcoded) by a shared SemaphoreSlim acquired inside
each body; collectors stay sequential within a server (Lite's RemoteCollectorService
shape). Deliberately not await-all-per-sweep -- that recreates the incident in miniature.

Cadence jitter: CadencePhaseOffset ((uint)serverId % periodSeconds; the serverId is
already an FNV-1a hash) gives a deterministic, restart-stable per-server phase applied
only at initial cadence stamps -- each collector's first post-connect due time, a
reload's newly-enabled collectors, and the first scheduled analysis (fixed 2.5-minute
window, not the full interval). The steady-state advance is never jittered.

Per-server exception containment (D3, Design Goal 4): the extracted body has a catch-all
(the gap the sweep loop previously had no cover for), so one server's throw is logged and
isolated and a faulted fire-and-track task never surfaces unobserved.

Concurrency-supporting invariants: per-server NextDue becomes a ConcurrentDictionary (D1)
since a reload's recompute can now touch it while a body reads it (indexed only by static
catalog keys -- a drop-in); disabling a server marks its state Retired (checked as the
first statement inside each body after it acquires the gate, plus a connect-path re-check
before any durable side-effect) so an in-flight/queued body for a removed server no-ops
(never connects, never runs XE DDL, never re-writes self-alert edge state after Forget);
and shutdown drains in-flight bodies (up to 15s, inside the host's 30s ShutdownTimeout)
before the command loop, with the gate deliberately never disposed.

Hang observability (D2b): because the incident was hangs, not throws, the skip branch logs
Debug each sweep and one Warning per episode once a body crosses 60s continuous (queue time
counts), with an Info on eventual completion; all skip-log state is outer-thread-owned.

Contracts unchanged: collection_log write semantics, MCP surfaces, and alert dedup/edge
semantics preserved; the per-server CollectionGate behavior is unchanged.

New DarlingSweepSchedulingTests pins the jitter offset (deterministic, unsigned-modulo
including negative FNV ids, bounded [0, period), not-all-identical across ids, non-positive
period -> zero) and the N=4 cap. Full Darling.Tests (2157 passed / 134 gated-live skipped)
and Lite.Tests (1352 passed) green.

Darling service only -- no store schema change, no Lite/Dashboard/viewer changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant