Skip to content

feat: Add per-unit response headers for all descriptors via LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED#1190

Open
samay-arcana wants to merge 1 commit into
envoyproxy:mainfrom
samay-arcana:samay/ratelimit-headers
Open

feat: Add per-unit response headers for all descriptors via LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED#1190
samay-arcana wants to merge 1 commit into
envoyproxy:mainfrom
samay-arcana:samay/ratelimit-headers

Conversation

@samay-arcana

@samay-arcana samay-arcana commented Jul 13, 2026

Copy link
Copy Markdown

Summary

When LIMIT_RESPONSE_HEADERS_ENABLED is set, the ratelimit service currently returns response headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) only for the single descriptor closest to hitting the rate limit. This means when multiple descriptors with different time units (e.g., SECOND and MINUTE) are evaluated, headers for only one unit are returned.

This PR adds a new environment variable LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED that, when enabled, returns per-unit limit and remaining headers for ALL descriptors that have configured limits.

Example

Request with two descriptors (10 req/s and 1000 req/min):

{
  "domain": "envoy",
  "descriptors": [
    {
      "entries": [{ "key": "remote_address", "value": "10.0.0.1" }],
      "limit": { "requests_per_unit": 10, "unit": "SECOND" }
    },
    {
      "entries": [{ "key": "remote_address", "value": "10.0.0.1" }],
      "limit": { "requests_per_unit": 1000, "unit": "MINUTE" }
    }
  ],
  "hits_addend": 1
}

Before (with LIMIT_RESPONSE_HEADERS_ENABLED=true):
Only headers for the descriptor closest to limit are returned (e.g., only seconds).

After (with LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED=true):

{
  "overall_code": "OK",
  "statuses": [...],
  "response_headers_to_add": [
    { "key": "ratelimit-limit-seconds", "value": "10" },
    { "key": "ratelimit-remaining-seconds", "value": "9" },
    { "key": "ratelimit-limit-minutes", "value": "1000" },
    { "key": "ratelimit-remaining-minutes", "value": "999" }
  ]
}

Changes

src/settings/settings.go

  • Added RateLimitAllDescriptorsHeadersEnabled setting (LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED env var, default false)

src/service/ratelimit.go

  • Added allDescriptorsHeadersEnabled field to the service struct
  • Updated SetConfig() to read the new setting on config reload
  • Modified header generation in shouldRateLimitWorker(): when allDescriptorsHeadersEnabled is true, generates per-unit headers for all descriptors instead of the single closest-to-limit descriptor
  • Added unitToHeaderSuffix() helper: maps rate limit units to lowercase plural suffixes (SECOND→"seconds", MINUTE→"minutes", HOUR→"hours", etc.)
  • Added allDescriptorsHeaders() method: iterates all descriptor statuses, skips those without limits, and generates ratelimit-limit-{unit} and ratelimit-remaining-{unit} headers

test/service/ratelimit_test.go

  • TestServiceWithAllDescriptorsHeaders: verifies SECOND + MINUTE descriptors produce 4 per-unit headers
  • TestServiceWithAllDescriptorsHeadersOverLimit: verifies headers are returned even when OVER_LIMIT
  • TestServiceWithAllDescriptorsHeadersSkipsNilLimits: verifies descriptors without configured limits are skipped

Backward Compatibility

  • LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED defaults to false — no behavior change unless explicitly enabled
  • When disabled, the existing LIMIT_RESPONSE_HEADERS_ENABLED behavior is fully preserved
  • LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED takes precedence over LIMIT_RESPONSE_HEADERS_ENABLED when both are set

Signed-off-by: Samay Varshney samay.varshney@arcana.io

Signed-off-by: Samay Varshney <samay.varshney@arcana.io>
@samay-arcana samay-arcana force-pushed the samay/ratelimit-headers branch from cc4cc7b to 26dab87 Compare July 13, 2026 19:29
@samay-arcana samay-arcana changed the title Return all rate limit headers via env var feat: Add per-unit response headers for all descriptors via LIMIT_ALL_DESCRIPTORS_HEADERS_ENABLED Jul 13, 2026
@samay-arcana

Copy link
Copy Markdown
Author

@agrawroh can you please review this PR?

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