feat(ops): size the bot event stream from evidence, not a constant (#415) #465
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/415-bot-stream-capacity"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #415 (LOW).
The defect
BOT_EVENTS_MAXLENwas a hardcoded 10,000 — chosen for a single self-hosted group and never revisited for multi-tenant volume, where every tenant's events share this one stream.XADD MAXLENdrops the oldest entries whether or not anyone read them, and the stream is the durable delivery path. A trimmed event has no catch-up; it is simply gone.What ships
settings.bot_events_maxlen, read at call time so a deployment can raise it without a code change. Documented in.env.examplewith the reason it might need raising.The third acceptance criterion is the substance here. A configurable number nobody can size is still a guess.
detect_unread_trimcompares the consumer group'slast-delivered-idagainst the stream's oldest surviving entry: if the group never reached what is now the first entry, everything between it and the cursor was trimmed unread. An hourly Beat task publishes that asbot_events_trimmed_unread_total.Two details that are load-bearing
Stream ids are
<ms>-<seq>and must be compared numerically."9-0"sorts after"10-0"as text, which inverts the exact comparison this makes and would report loss on a perfectly healthy stream. There is a test for both directions, and it fails against a lexical-comparison mutant."Nothing to compare" returns
None, not0, and leaves the gauge untouched. No stream, no consumer group, or an empty stream are all "we cannot tell yet" — and a zero the detector has not earned is indistinguishable from a genuine all-clear. That is the more dangerous of the two answers, so it is never published. Two tests pin it.Similarly, a gauge nobody writes reads as zero forever, so there is a test asserting the Beat task is actually scheduled — a detector nobody runs detects nothing.
Verification
Mutation-checked on the id comparison, which is the subtle part. 15 new tests. 1,503 backend tests pass (was 1,488). Lint clean at pinned ruff 0.4.4.
BOT_EVENTS_MAXLENthe module constant is kept for any caller that imported it, but the publish paths read the setting — so overriding the setting actually takes effect, which is what the old constant would have quietly prevented.Note on criterion 2
Left at the 10,000 default rather than inventing a number. There is no measured volume to size against yet — that is precisely what the new metric is for. Once an instance has run with real traffic, the gauge says whether the default is short and by how much. Picking a bigger number now would just be a differently-arbitrary constant.
🤖 Generated with Claude Code