work work hard work
This commit is contained in:
90
docs/router/rate-limiting-routes.md
Normal file
90
docs/router/rate-limiting-routes.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Per-Route Rate Limiting (Router)
|
||||
|
||||
This document describes **per-route** rate limiting configuration for the Router gateway (`StellaOps.Router.Gateway`).
|
||||
|
||||
## Overview
|
||||
|
||||
Per-route rate limiting lets you apply different limits to specific HTTP paths **within the same microservice**.
|
||||
|
||||
Configuration is nested as:
|
||||
|
||||
`rate_limiting.for_environment.microservices.<microservice>.routes.<route_name>`
|
||||
|
||||
## Configuration
|
||||
|
||||
### Example (rules + routes)
|
||||
|
||||
```yaml
|
||||
rate_limiting:
|
||||
for_environment:
|
||||
valkey_connection: "valkey.stellaops.local:6379"
|
||||
valkey_bucket: "stella-router-rate-limit"
|
||||
|
||||
# Default environment rules (used when no microservice override exists)
|
||||
rules:
|
||||
- per_seconds: 60
|
||||
max_requests: 600
|
||||
|
||||
microservices:
|
||||
scanner:
|
||||
# Default rules for the microservice (used when no route override exists)
|
||||
rules:
|
||||
- per_seconds: 60
|
||||
max_requests: 600
|
||||
|
||||
routes:
|
||||
scan_submit:
|
||||
pattern: "/api/scans"
|
||||
match_type: exact
|
||||
rules:
|
||||
- per_seconds: 10
|
||||
max_requests: 50
|
||||
|
||||
scan_status:
|
||||
pattern: "/api/scans/*"
|
||||
match_type: prefix
|
||||
rules:
|
||||
- per_seconds: 1
|
||||
max_requests: 100
|
||||
|
||||
scan_by_id:
|
||||
pattern: "^/api/scans/[a-f0-9-]+$"
|
||||
match_type: regex
|
||||
rules:
|
||||
- per_seconds: 1
|
||||
max_requests: 50
|
||||
```
|
||||
|
||||
### Match types
|
||||
|
||||
`match_type` supports:
|
||||
|
||||
- `exact`: exact path match (case-insensitive), ignoring a trailing `/`.
|
||||
- `prefix`: literal prefix match; patterns commonly end with `*` (e.g. `/api/scans/*`).
|
||||
- `regex`: regular expression (compiled at startup; invalid regex fails fast).
|
||||
|
||||
### Specificity rules
|
||||
|
||||
When multiple routes match a path, the most specific match wins:
|
||||
|
||||
1. `exact`
|
||||
2. `prefix` (longest prefix wins)
|
||||
3. `regex` (longest pattern wins)
|
||||
|
||||
## Inheritance (resolution)
|
||||
|
||||
Rate limiting rules resolve with **replacement** semantics:
|
||||
|
||||
- `routes.<route_name>.rules` replaces the microservice rules.
|
||||
- `microservices.<name>.rules` replaces the environment rules.
|
||||
- If a level provides no rules, the next-less-specific level applies.
|
||||
|
||||
## Notes
|
||||
|
||||
- Per-route rate limiting applies at the **environment** scope (Valkey-backed).
|
||||
- The Router returns `429 Too Many Requests` and a `Retry-After` header when a limit is exceeded.
|
||||
|
||||
## See also
|
||||
|
||||
- `docs/router/rate-limiting.md` (full configuration guide)
|
||||
- `docs/modules/router/rate-limiting.md` (module dossier)
|
||||
122
docs/router/rate-limiting.md
Normal file
122
docs/router/rate-limiting.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Router Rate Limiting
|
||||
|
||||
Router rate limiting is a **gateway-owned** control plane feature implemented in `StellaOps.Router.Gateway`. It enforces limits centrally so microservices do not implement ad-hoc HTTP throttling.
|
||||
|
||||
## Behavior
|
||||
|
||||
When a request is denied the Router returns:
|
||||
- `429 Too Many Requests`
|
||||
- `Retry-After: <seconds>`
|
||||
- `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (Unix seconds)
|
||||
- JSON body:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "rate_limit_exceeded",
|
||||
"message": "Rate limit exceeded. Try again in 12 seconds.",
|
||||
"retryAfter": 12,
|
||||
"limit": 100,
|
||||
"current": 101,
|
||||
"window": 60,
|
||||
"scope": "environment"
|
||||
}
|
||||
```
|
||||
|
||||
## Model
|
||||
|
||||
Two scopes exist:
|
||||
- **Instance (`for_instance`)**: in-memory sliding window; protects a single Router process.
|
||||
- **Environment (`for_environment`)**: Valkey-backed fixed window; protects the whole environment across Router instances.
|
||||
|
||||
Environment checks are gated by an **activation threshold** (`process_back_pressure_when_more_than_per_5min`) to avoid unnecessary Valkey calls at low traffic.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration is under the `rate_limiting` root.
|
||||
|
||||
### Minimal (instance only)
|
||||
|
||||
```yaml
|
||||
rate_limiting:
|
||||
process_back_pressure_when_more_than_per_5min: 5000
|
||||
|
||||
for_instance:
|
||||
rules:
|
||||
- per_seconds: 60
|
||||
max_requests: 600
|
||||
```
|
||||
|
||||
### Environment (Valkey)
|
||||
|
||||
```yaml
|
||||
rate_limiting:
|
||||
process_back_pressure_when_more_than_per_5min: 0 # always check environment
|
||||
|
||||
for_environment:
|
||||
valkey_connection: "valkey.stellaops.local:6379"
|
||||
valkey_bucket: "stella-router-rate-limit"
|
||||
|
||||
circuit_breaker:
|
||||
failure_threshold: 5
|
||||
timeout_seconds: 30
|
||||
half_open_timeout: 10
|
||||
|
||||
rules:
|
||||
- per_seconds: 60
|
||||
max_requests: 600
|
||||
```
|
||||
|
||||
### Rule stacking (AND logic)
|
||||
|
||||
Multiple rules on the same target are evaluated with **AND** semantics:
|
||||
|
||||
```yaml
|
||||
rate_limiting:
|
||||
for_environment:
|
||||
rules:
|
||||
- per_seconds: 1
|
||||
max_requests: 10
|
||||
- per_seconds: 3600
|
||||
max_requests: 3000
|
||||
```
|
||||
|
||||
If any rule is exceeded the request is denied. The Router returns the **most restrictive** `Retry-After` among violated rules.
|
||||
|
||||
### Microservice overrides
|
||||
|
||||
Overrides are **replacement**, not merge:
|
||||
|
||||
```yaml
|
||||
rate_limiting:
|
||||
for_environment:
|
||||
rules:
|
||||
- per_seconds: 60
|
||||
max_requests: 600
|
||||
|
||||
microservices:
|
||||
scanner:
|
||||
rules:
|
||||
- per_seconds: 10
|
||||
max_requests: 50
|
||||
```
|
||||
|
||||
### Route overrides
|
||||
|
||||
Route-level configuration is under:
|
||||
|
||||
`rate_limiting.for_environment.microservices.<microservice>.routes.<route_name>`
|
||||
|
||||
See `docs/router/rate-limiting-routes.md` for match types and specificity rules.
|
||||
|
||||
## Notes
|
||||
|
||||
- If `rules` is present, it takes precedence over legacy single-window keys (`per_seconds`, `max_requests`, `allow_*`).
|
||||
- For allowed requests, headers represent the **smallest window** rule for deterministic, low-cardinality output (not a full multi-rule snapshot).
|
||||
- If Valkey is unavailable, environment limiting is **fail-open** (instance limits still apply).
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit tests: `dotnet test StellaOps.Router.slnx -c Release`
|
||||
- Valkey integration tests (Docker required): `STELLAOPS_INTEGRATION_TESTS=true dotnet test StellaOps.Router.slnx -c Release --filter FullyQualifiedName~ValkeyRateLimitStoreIntegrationTests`
|
||||
- k6 load tests: `tests/load/router-rate-limiting-load-test.js` (see `tests/load/README.md`)
|
||||
|
||||
Reference in New Issue
Block a user