Skip to content

feat(vahter): /rebuild-snapshots backfills aggregate user snapshots (?scope=users) - #523

Merged
Szer merged 1 commit into
mainfrom
rebuild-aggregate-snapshots
Sep 25, 2026
Merged

Szer merged 1 commit into
mainfrom
rebuild-aggregate-snapshots

Conversation

@Szer

@Szer Szer commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Why

Aggregate snapshots (#518) are written lazily, so each heavy user's first load after a deploy still pays one full replay. That's the 4.56 s @fvnever span on the dashboard. 190 users with ≥20 events are still unsnapshotted in prod (31 with ≥100, 6 with ≥300, max 962).

What

  • EventStore.RebuildSnapshot(fold, zero, policy, streamId): replays the whole log (ignoring any stored snapshot) and force-writes the snapshot when the stream has ≥ SnapshotEvery events. It works as both a backfill and a repair, e.g. of a wrong snapshot at the same version. It uses its own eventStore.snapshotRebuild span, and a failed write is recorded and swallowed like elsewhere.
  • Vahter's existing permanent POST /rebuild-snapshots user phase already replayed every user stream; it now also writes the aggregate snapshot. No temporary endpoint, nothing to clean up.
  • New ?scope=users runs only the user phase and skips the heavy message/moderation read-model pass. An unknown scope returns 400.

Tests (red → green)

  • BotInfra: rebuild repairs a tampered snapshot at the same version (red against a stub that just called LoadState: 1000 vs 325); rebuild skips streams below SnapshotEvery.
  • Vahter integration: POST /rebuild-snapshots?scope=users writes the aggregate snapshot for a 26-event user (correct User state) and doesn't build the message snapshot (red before: no snapshot row).
  • Local: BotInfra.Tests 34/34, VahterBanBot.Unit.Tests 133/133, VahterBanBot.Tests 303/303.

After deploy

curl -X POST -H "X-Telegram-Bot-Api-Secret-Token: $BOT_AUTH_TOKEN" "https://vahter.szer.dev/rebuild-snapshots?scope=users"

🤖 Generated with Claude Code

…?scope=users

Snapshots are otherwise written lazily, so each heavy user's first load after
a deploy (or a SchemaVersion bump) still pays one full replay. The existing
admin rebuild already replays every user stream; it now also force-writes the
aggregate snapshot via the new EventStore.RebuildSnapshot (full replay that
ignores and repairs the stored snapshot). ?scope=users skips the heavy
message/moderation read-model pass; unknown scopes are rejected with 400.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Szer
Szer enabled auto-merge (squash) September 25, 2026 18:24
@Szer
Szer merged commit 38ab186 into main Sep 25, 2026
8 checks passed
@Szer
Szer deleted the rebuild-aggregate-snapshots branch September 25, 2026 18:26
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