Skip to content

docs: rate limiting in features, interceptor chain, config, security hardening#68

Merged
ankurs merged 5 commits intomainfrom
feat/rate-limit-docs
Apr 9, 2026
Merged

docs: rate limiting in features, interceptor chain, config, security hardening#68
ankurs merged 5 commits intomainfrom
feat/rate-limit-docs

Conversation

@ankurs
Copy link
Copy Markdown
Member

@ankurs ankurs commented Apr 9, 2026

Summary

  • Replace deprecated Resilience (Hystrix) row with Rate Limiting in homepage feature table
  • Update architecture.md interceptor chain table — was missing 3 interceptors (Default Timeout, Rate Limiting, Debug Log). Now shows all 10 in correct order.
  • Add RATE_LIMIT_PER_SECOND, RATE_LIMIT_BURST, DISABLE_RATE_LIMIT to config reference
  • Add rate limiting section to interceptors howto with per-API custom limiter example (per-method rate limits using SetRateLimiter())
  • Add rate limiting to security hardening env block (1000 rps, burst 50) and public-facing checklist
  • Update "Not built into ColdBrew" to reflect per-pod rate limiting is now built-in; cluster-wide needs custom implementation

Test plan

  • Config var names match core/config/config.go
  • Chain order matches DefaultInterceptors() in interceptors/interceptors.go
  • No broken links

Summary by CodeRabbit

  • New Features

    • Server-side rate limiting: per-pod token-bucket (disabled by default); excess requests return ResourceExhausted.
    • Default request timeout of 60s when none provided.
    • Per-request debug log override via debug field or metadata header.
  • Documentation

    • Full rate-limiting how‑to, config vars (RATE_LIMIT_PER_SECOND, RATE_LIMIT_BURST, DISABLE_RATE_LIMIT), distributed/custom limiter guidance, and updated production checklist.
    • Updated gRPC interceptor ordering and related config names.

- Replace deprecated Resilience (Hystrix) with Rate Limiting in Index.md
- Update architecture.md interceptor chain: add Default Timeout, Rate
  Limiting, Debug Log (was missing 3 interceptors)
- Add RATE_LIMIT_PER_SECOND, RATE_LIMIT_BURST, DISABLE_RATE_LIMIT to
  config-reference.md
- Add rate limiting howto with per-API custom limiter example
- Add rate limiting to security hardening env block and checklist
- Update production.md: per-pod rate limiting is now built-in
Copilot AI review requested due to automatic review settings April 9, 2026 12:40
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2026

Warning

Rate limit exceeded

@ankurs has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 27 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 1 minutes and 27 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bdf5d933-15a0-4f4f-83b7-6a54e47ce961

📥 Commits

Reviewing files that changed from the base of the PR and between e7d9b56 and 60c8bbe.

📒 Files selected for processing (1)
  • howto/interceptors.md
📝 Walkthrough

Walkthrough

Documentation introduces a per-pod, in-memory token-bucket gRPC rate limiter (disabled by default), documents env vars for configuration, adds the rate-limiting interceptor to the server interceptor chain, and describes how to plug in a custom/distributed limiter via the exported ratelimit.Limiter and interceptors.SetRateLimiter.

Changes

Cohort / File(s) Summary
Feature Intro
Index.md
Replaced "Resilience" entry with a new "Rate Limiting" feature: per-pod token-bucket limiter, default-disabled, RATE_LIMIT_PER_SECOND config, link to interceptors how-to.
Architecture & Interceptors
architecture.md
Updated gRPC server interceptor chain: added Default Timeout and Rate Limiting at start, inserted Debug Log interceptor, renumbered interceptors, and documented env var names (GRPC_SERVER_DEFAULT_TIMEOUT_IN_SECONDS, RATE_LIMIT_PER_SECOND, RATE_LIMIT_BURST, DISABLE_DEBUG_LOG_INTERCEPTOR, DEBUG_LOG_HEADER_NAME).
Config Reference
config-reference.md
Added RATE_LIMIT_PER_SECOND (float64, default 0), RATE_LIMIT_PER_BURST/RATE_LIMIT_BURST (int, default 1), and DISABLE_RATE_LIMIT (bool, default false) with per-pod behavior and disabling notes.
How-to / Production
howto/interceptors.md, howto/production.md
New Rate Limiting how-to: per-pod token-bucket behavior, RATE_LIMIT_PER_SECOND/RATE_LIMIT_BURST, interceptor returns ResourceExhausted on exceed, example ratelimit.Limiter usage and interceptors.SetRateLimiter registration, distributed-limiter guidance, and production checklist update.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant GRPC_Server as "gRPC Server\nInterceptor Chain"
participant RateLimiter as "Rate Limiter\n(ratelimit.Limiter)"
participant Handler as "Service Handler"
Client->>GRPC_Server: Unary request
GRPC_Server->>GRPC_Server: Apply Default Timeout
GRPC_Server->>RateLimiter: Check token (method-scoped)
alt token available
RateLimiter-->>GRPC_Server: Allow
GRPC_Server->>GRPC_Server: Debug Log / Proto Validate / Prometheus / Error Notification / New Relic / Panic Recovery
GRPC_Server->>Handler: Invoke service handler
Handler-->>GRPC_Server: Response
GRPC_Server-->>Client: 200 OK
else token exhausted
RateLimiter-->>GRPC_Server: Deny (ResourceExhausted)
GRPC_Server-->>Client: gRPC ResourceExhausted error
end

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 I hop through lines of docs with cheer,

Tokens clink and limits appear,
Per-pod buckets keep the flow,
Custom limiters steal the show,
Hooray — the requests can steer!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title comprehensively and accurately summarizes all major changes in the PR: documentation updates about rate limiting features, interceptor chain configuration, and security hardening guidance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rate-limit-docs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ColdBrew documentation to reflect the new built-in per-pod rate limiting feature, including how to enable/configure it, how it fits into the interceptor chain, and how it changes production/security guidance.

Changes:

  • Replace the deprecated “Resilience” homepage feature entry with “Rate Limiting”.
  • Document the full interceptor chain order (now including Default Timeout, Rate Limiting, Debug Log).
  • Add rate limiting environment variables and guidance across config reference, interceptor how-to, and production/security hardening docs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Index.md Updates the homepage feature table to highlight rate limiting instead of deprecated resilience entry.
howto/production.md Adds recommended rate limiting env vars to the security hardening example and updates “not built-in” guidance + checklist.
howto/interceptors.md Adds a new rate limiting section with enablement instructions and a per-API custom limiter example.
config-reference.md Documents RATE_LIMIT_PER_SECOND, RATE_LIMIT_BURST, and DISABLE_RATE_LIMIT.
architecture.md Corrects/expands interceptor chain table to include all interceptors in order, including rate limiting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Index.md Outdated
Comment thread howto/interceptors.md
ankurs added 2 commits April 9, 2026 21:48
…commendations

Address review: link Limiter interface to pkg.go.dev, add import and
compile-time check to example. Add table of distributed rate limiting
libraries (mennanov/limiters, go-redis/redis_rate, sethvargo/go-limiter)
and large-scale services (gubernator, Envoy ratelimit).
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
howto/interceptors.md (1)

216-221: Consider handling the case when grpc.Method returns false.

While the current code works for typical scenarios, grpc.Method(ctx) returns (method string, ok bool). When ok is false (e.g., non-gRPC requests), the method will be an empty string. Consider explicitly handling this case for robustness:

func (l *perMethodLimiter) Limit(ctx context.Context) error {
    method, ok := grpc.Method(ctx)
    if !ok {
        method = "" // explicit fallback for non-gRPC contexts
    }
    limiter, ok := l.limiters[method]
    if !ok {
        limiter = l.fallback
    }
    if !limiter.Allow() {
        return fmt.Errorf("rate limit exceeded for %s", method)
    }
    return nil
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@howto/interceptors.md` around lines 216 - 221, Handle the case where
grpc.Method(ctx) returns ok == false inside perMethodLimiter.Limit: call
grpc.Method(ctx) capturing both method and ok, and if ok is false set method to
a safe default (e.g., empty string) before looking up l.limiters[method]; then
proceed to select limiter or l.fallback and use limiter.Allow() as before so
non-gRPC contexts do not accidentally use an empty or unexpected key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@howto/interceptors.md`:
- Around line 197-237: The example uses rate.NewLimiter with plain ints which
mismatches its signature; update the calls in the init block where
interceptors.SetRateLimiter is invoked to cast the first argument to rate.Limit
(e.g., pass rate.Limit(10), rate.Limit(100), rate.Limit(50)) so the map entries
in perMethodLimiter and the fallback use rate.NewLimiter(rate.Limit(...), burst)
matching the required types.

---

Nitpick comments:
In `@howto/interceptors.md`:
- Around line 216-221: Handle the case where grpc.Method(ctx) returns ok ==
false inside perMethodLimiter.Limit: call grpc.Method(ctx) capturing both method
and ok, and if ok is false set method to a safe default (e.g., empty string)
before looking up l.limiters[method]; then proceed to select limiter or
l.fallback and use limiter.Allow() as before so non-gRPC contexts do not
accidentally use an empty or unexpected key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1eb137e7-ee32-4420-836b-df2004463e9a

📥 Commits

Reviewing files that changed from the base of the PR and between 68666bb and 2932c65.

📒 Files selected for processing (2)
  • Index.md
  • howto/interceptors.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • Index.md

Comment thread howto/interceptors.md
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Index.md
Comment thread architecture.md Outdated
Comment thread howto/interceptors.md Outdated
Comment thread howto/production.md Outdated
…n burst

- Per-API limiter example: fall back to runtime.RPCMethod for HTTP→gRPC
  calls where grpc.Method returns empty (no transport stream)
- Add enable_debug to architecture chain table
- Mention RATE_LIMIT_BURST in production checklist
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
howto/interceptors.md (1)

237-246: ⚠️ Potential issue | 🔴 Critical

Fix rate.NewLimiter type conversion in code example.

The example uses rate.NewLimiter(10, 5) but the signature requires the first parameter to be type rate.Limit, not int. Cast the values: rate.NewLimiter(rate.Limit(10), 5), rate.NewLimiter(rate.Limit(100), 50), and rate.NewLimiter(rate.Limit(50), 25).

Run this script to confirm the signature:

#!/bin/bash
# Description: Verify rate.NewLimiter signature in golang.org/x/time/rate

# Check the signature in go.dev documentation
echo "Checking rate.NewLimiter signature..."
What is the signature of rate.NewLimiter in golang.org/x/time/rate package in Go?
🔧 Corrected code snippet
 func init() {
     interceptors.SetRateLimiter(&perMethodLimiter{
         limiters: map[string]*rate.Limiter{
-            "/myservice.v1.UserService/CreateUser": rate.NewLimiter(10, 5),   // 10 rps
-            "/myservice.v1.UserService/ListUsers":  rate.NewLimiter(100, 50), // 100 rps
+            "/myservice.v1.UserService/CreateUser": rate.NewLimiter(rate.Limit(10), 5),   // 10 rps
+            "/myservice.v1.UserService/ListUsers":  rate.NewLimiter(rate.Limit(100), 50), // 100 rps
         },
-        fallback: rate.NewLimiter(50, 25), // 50 rps default
+        fallback: rate.NewLimiter(rate.Limit(50), 25), // 50 rps default
     })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@howto/interceptors.md` around lines 237 - 246, The code example using
rate.NewLimiter incorrectly passes ints for the first parameter; update each
call to cast the first argument to rate.Limit (e.g.
rate.NewLimiter(rate.Limit(10), 5), rate.NewLimiter(rate.Limit(100), 50),
rate.NewLimiter(rate.Limit(50), 25)) so the signature matches; change these
instances where perMethodLimiter.limiters and perMethodLimiter.fallback are
constructed (the calls to rate.NewLimiter referenced in the init block and
passed to interceptors.SetRateLimiter).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@howto/interceptors.md`:
- Around line 248-259: Update the "Distributed rate limiting" section to either
remove the "go-redis/redis_rate" row or add a clear maintenance warning next to
the library name; specifically edit the table entry for "go-redis/redis_rate"
under the "Distributed rate limiting" heading so it indicates that the project
is unmaintained/stale (e.g., "unmaintained — last release 2023") or delete that
row entirely, leaving the other recommendations ("mennanov/limiters" and
"sethvargo/go-limiter") intact.

---

Duplicate comments:
In `@howto/interceptors.md`:
- Around line 237-246: The code example using rate.NewLimiter incorrectly passes
ints for the first parameter; update each call to cast the first argument to
rate.Limit (e.g. rate.NewLimiter(rate.Limit(10), 5),
rate.NewLimiter(rate.Limit(100), 50), rate.NewLimiter(rate.Limit(50), 25)) so
the signature matches; change these instances where perMethodLimiter.limiters
and perMethodLimiter.fallback are constructed (the calls to rate.NewLimiter
referenced in the init block and passed to interceptors.SetRateLimiter).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4f410bc6-575c-4180-8a2b-1a3ca38b1d54

📥 Commits

Reviewing files that changed from the base of the PR and between a3bb6bd and e7d9b56.

📒 Files selected for processing (3)
  • architecture.md
  • howto/interceptors.md
  • howto/production.md
✅ Files skipped from review due to trivial changes (1)
  • howto/production.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • architecture.md

Comment thread howto/interceptors.md
@ankurs ankurs merged commit 07f0360 into main Apr 9, 2026
7 checks passed
@ankurs ankurs deleted the feat/rate-limit-docs branch April 9, 2026 14:50
@coderabbitai coderabbitai Bot mentioned this pull request Apr 11, 2026
3 tasks
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.

2 participants