fix(vloer): keep health probes constant-cost and page event replay #147

Merged
ryangr0 merged 1 commit from ryangr0/vloer-bounded-health-and-replay into development 2026-10-03 00:22:07 +00:00 AGit
Owner

/healthz and /readyz called store.listSessions(), which parsed every
session and decrypted its workspace secret on each probe. Probe cost grew
with history, blocked the event loop, and one corrupt old session made
liveness fail. /healthz now answers without touching storage and /readyz
runs a single SELECT 1 through Store.ping(); both keep their {status,
version} response and GET-only method check.

The live event stream read every event after the client's cursor in one
unbounded query, so a client reconnecting from an old cursor loaded the
whole remainder before backpressure applied. It now reads through
Store.eventPage() in batches of eventReplayBatch (200) rows, continuing
from the last sent id until a short page or a buffered-output limit,
and resumes on the next tick. Store.events() keeps returning the full
remainder for the history endpoint, the engine and the AHP host, so no
caller is truncated.

Store.events() still returns full history for /history, the engine and the AHP host; only the live SSE stream reads in pages of 200. Engine background loops still call listSessions(), so a corrupt session row can still break them (follow-up).

Verified with mise run verify on the pinned toolchain (all gates passed).

Ticket: https://vikunja.webgrip.dev/tasks/1724

🤖 Generated with Claude Code

/healthz and /readyz called store.listSessions(), which parsed every session and decrypted its workspace secret on each probe. Probe cost grew with history, blocked the event loop, and one corrupt old session made liveness fail. /healthz now answers without touching storage and /readyz runs a single SELECT 1 through Store.ping(); both keep their {status, version} response and GET-only method check. The live event stream read every event after the client's cursor in one unbounded query, so a client reconnecting from an old cursor loaded the whole remainder before backpressure applied. It now reads through Store.eventPage() in batches of eventReplayBatch (200) rows, continuing from the last sent id until a short page or a buffered-output limit, and resumes on the next tick. Store.events() keeps returning the full remainder for the history endpoint, the engine and the AHP host, so no caller is truncated. Store.events() still returns full history for /history, the engine and the AHP host; only the live SSE stream reads in pages of 200. Engine background loops still call listSessions(), so a corrupt session row can still break them (follow-up). Verified with `mise run verify` on the pinned toolchain (all gates passed). Ticket: https://vikunja.webgrip.dev/tasks/1724 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(vloer): keep health probes constant-cost and page event replay
Some checks failed
[Workflow] On Pull Request / checks (pull_request) Has been cancelled
[Workflow] On Pull Request / warnings (pull_request) Has been cancelled
[Workflow] On Pull Request / release-policy (pull_request) Has been cancelled
850c3fbba7
/healthz and /readyz called store.listSessions(), which parsed every
session and decrypted its workspace secret on each probe. Probe cost grew
with history, blocked the event loop, and one corrupt old session made
liveness fail. /healthz now answers without touching storage and /readyz
runs a single SELECT 1 through Store.ping(); both keep their {status,
version} response and GET-only method check.

The live event stream read every event after the client's cursor in one
unbounded query, so a client reconnecting from an old cursor loaded the
whole remainder before backpressure applied. It now reads through
Store.eventPage() in batches of eventReplayBatch (200) rows, continuing
from the last sent id until a short page or a buffered-output limit,
and resumes on the next tick. Store.events() keeps returning the full
remainder for the history endpoint, the engine and the AHP host, so no
caller is truncated.

VIK-1724

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ryangr0 merged commit 9f8d272402 into development 2026-10-03 00:22:07 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
webgrip/unfold!147
No description provided.