Skip to content

Implement rate limiting#25

Open
tishun wants to merge 1 commit into
mainfrom
feat/rate-limiting
Open

Implement rate limiting#25
tishun wants to merge 1 commit into
mainfrom
feat/rate-limiting

Conversation

@tishun

@tishun tishun commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

(This PR is co-authored by @MSC72m as part of his PR #20)

Add Redis-backed rate limiting

Adds a rate-limiting feature to the SDK, mirroring the existing caching design (DI-first, async-only, OpenTelemetry-aware).

What's new

  • rate_limit() DI dependency — per-route limits via Depends(), keyed by a pluggable identifier (default: client IP). Scope defaults to the matched route template so path params share one bucket.
  • RateLimitMiddleware — optional app-wide global limit + *-RateLimit-* / IETF RateLimit header injection. Wired via FastAPIRedis(app).rate_limiting().
  • RateLimitBackend — fixed-window counter with two atomic tiers: INCREX (Redis 8.8+) → Lua EVAL fallback (Redis 2.6+). No non-atomic degrade; a scripting-less server takes the fail-open/closed path instead. Capability detection is memoized once per process on the shared pool state.
  • Fluent rate specs (rate.py): "100/minute", Rate(100, 60), or (100, 60).
  • Fail-open / fail-closed, cost weighting, skip_when bypass, custom 429 builder, sync facade (SyncRateLimitBackend), and OTel spans/metrics.
  • Config settings (REDIS_RATE_LIMIT_*), docs, and unit + integration tests.

Where to focus review

  1. ratelimit_backend.py — correctness core. The Lua window-counter script, tier selection/memoization, and fail-open vs fail-closed semantics. This is the only place atomicity matters (counter read-modify-write).
  2. ratelimit.py::_apply_limit — shared helper extracted from the per-route dependency and the global middleware. The one intentional difference between the two callers is raise-RateLimitExceeded vs. return-Response; everything else (skip → identify → hit → stash state → metric → 429) is unified. Confirm the two call sites stay behaviorally identical.
  3. Cluster key layout (_build_key) — deliberately flat, no hash-tag, unlike the cache backend (which hash-tags eviction groups). Rationale: rate limiting only does single-key ops, so spreading counters across slots avoids a hot shard.
  4. Header handling — middleware dedups against headers already present; 429s carry Retry-After + limit headers.

Linked issues

@codecov-commenter

codecov-commenter commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.87379% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.41%. Comparing base (d98446c) to head (c0e46c3).

Files with missing lines Patch % Lines
src/redis_fastapi/ratelimit.py 95.93% 7 Missing ⚠️
src/redis_fastapi/telemetry.py 80.64% 6 Missing ⚠️
src/redis_fastapi/setup.py 70.00% 3 Missing ⚠️
src/redis_fastapi/deps.py 94.44% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #25      +/-   ##
==========================================
- Coverage   98.29%   96.41%   -1.89%     
==========================================
  Files           9       12       +3     
  Lines         764     1170     +406     
==========================================
+ Hits          751     1128     +377     
- Misses         13       42      +29     
Flag Coverage Δ
unittests 96.41% <95.87%> (-1.89%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-authored-by: MSC72m <msc72m@gmail.com>
@tishun
tishun force-pushed the feat/rate-limiting branch from 6c19a09 to c0e46c3 Compare July 21, 2026 09:30
@tishun
tishun marked this pull request as ready for review July 21, 2026 10:13
@MSC72m

MSC72m commented Jul 21, 2026

Copy link
Copy Markdown

Thanks a lot for including me and incorporating parts of my work into the new implementation. I really appreciate it!

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.

Add Redis-backed rate limiting for FastAPI endpoints (INCREX-based window counter)

3 participants