Skip to content

feat: Redis multi-container support (Phase 1.6)#28

Merged
adamy merged 2 commits into
mainfrom
feature/phase1-6
Jun 17, 2026
Merged

feat: Redis multi-container support (Phase 1.6)#28
adamy merged 2 commits into
mainfrom
feature/phase1-6

Conversation

@adamy

@adamy adamy commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 1.6 makes BotWire correct behind a load balancer. New opt-in BotWire.Redis package moves conversation sessions and rate-limit counters out of process memory into Redis, so they're shared across instances and survive restarts. Defaults are unchanged — without .AddBotWireRedis(...) everything behaves exactly as v0.2.0.

builder.Services.AddBotWire(opts => { /* ... */ })
                .AddBotWireRedis("localhost:6379");

What's included

  • IRateLimitStore abstraction in BotWire.Core — no StackExchange.Redis dependency in Core.
  • RedisConversationStore — JSON sessions, sliding SessionTtl, dual-history round-trip, MaxHistoryMessages cap enforced identically to the in-memory store.
  • RedisRateLimitStore — atomic INCRBY + conditional EXPIRE (Lua); TTL clamped ≥1s so day-boundary token-budget keys aren't deleted.
  • RateLimiter async variants use the store when present; per-minute path waits for the fixed window to roll rather than admitting over-quota turns. MaxConcurrentSessions stays per-container by design.
  • RedisShop sample — ASP.NET API (Redis sessions + distributed limits + email escalation) + Vite/React/TS shopfront with a custom chatbox on headless botwire-js.
  • Docs: v0.3.0 release notes, README Samples section, per-package NuGet readme.

Testing

  • New Core tests: distributed per-minute (within/over quota), shared token budget. (254 pass)
  • New Redis tests (skip if no Redis): session/dual-history/flags round-trip, cross-instance sharing, TTL refresh, history-cap parity, sub-second-TTL key survival. (19 pass against Docker Redis)
  • Existing AspNetCore (27) + full solution build, 0 warnings.

Notes

  • Three findings from /code-review high were fixed in this branch (per-minute enforcement, history-cap parity, TTL clamp) with regression tests.
  • VersionPrefix left at 0.2.0 — version bump + v0.3.0 tag is the separate release cut.

🤖 Generated with Claude Code

adamy and others added 2 commits June 17, 2026 20:50
Redis-backed conversation store and distributed rate-limit counters so
sessions and limits are shared across instances behind a load balancer,
opt-in via .AddBotWireRedis(connString) after AddBotWire(). Defaults are
unchanged: without it, the in-memory stores and per-process counters are
used exactly as before.

- IRateLimitStore abstraction in BotWire.Core (no StackExchange.Redis dep)
- RedisConversationStore: JSON sessions, sliding SessionTtl, dual-history
  round-trip, MaxHistoryMessages cap enforced like the in-memory store
- RedisRateLimitStore: atomic INCRBY + conditional EXPIRE (Lua), TTL
  clamped >=1s so day-boundary token-budget keys are not deleted
- RateLimiter: async variants use the store when present; per-minute path
  waits for the fixed window to roll instead of admitting over-quota turns
- RedisShop sample: ASP.NET API (Redis sessions + distributed limits +
  email escalation) and a Vite/React/TS shopfront on headless botwire-js
- v0.3.0 release notes; README Samples section

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BotWire.Redis shipped with no PackageReadmeFile, so its NuGet listing
would have no description. Add a package-specific NUGET.md, wire it into
the csproj, and list the package in the shared root NUGET.md table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adamy adamy merged commit c9f6ec5 into main Jun 17, 2026
5 checks passed
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