@@ -17,6 +17,43 @@ shutdown_timeout_secs: # Optional. Graceful drain time (default: 30).
1717insecure_options : # Optional. Dev/test overrides. See development.md.
1818` ` `
1919
20+ ## Dynamic Configuration Reload
21+
22+ Praxis watches the config file for changes and
23+ automatically reloads filter pipelines without restart
24+ or disruption. When the file is modified, the server
25+ validates the new config, rebuilds pipelines, and swaps
26+ them atomically. In-flight requests complete on the old
27+ pipeline; new requests pick up the new config.
28+
29+ If the new config is invalid (bad YAML, unknown filter,
30+ validation failure), the server logs the error and
31+ continues serving with the old config.
32+
33+ **Dynamically reloadable:**
34+
35+ - Filter pipeline configuration
36+ - Router routes and path mappings
37+ - Load balancer endpoints and weights
38+ - Rate limit and circuit breaker settings
39+ - Health check configuration
40+
41+ **Requires restart (logged as warning):**
42+
43+ - Listener add, remove, or address rebind
44+ - Protocol changes (HTTP to TCP)
45+ - Compression module addition
46+ - TLS enable/disable
47+
48+ Stateful filters (rate limiter, circuit breaker) reset
49+ their state on reload. Operators should expect a brief
50+ burst window for rate limiters and a closed circuit for
51+ circuit breakers immediately after reload.
52+
53+ See [hot-reload.yaml] for an example.
54+
55+ [hot-reload.yaml]: ../examples/configs/operations/hot-reload.yaml
56+
2057## Admin
2158
2259` admin.address` binds a separate HTTP listener that serves
@@ -268,13 +305,15 @@ supports TCP-level filters too.
268305| `timeout` | Traffic Management | HTTP |
269306| `static_response` | Traffic Management | HTTP |
270307| `rate_limit` | Traffic Management | HTTP |
308+ | `circuit_breaker` | Traffic Management | HTTP |
271309| `headers` | Transformation | HTTP |
272310| `request_id` | Observability | HTTP |
273311| `access_log` | Observability | HTTP |
274312| `tcp_access_log` | Observability | TCP |
275313| `forwarded_headers` | Security | HTTP |
276314| `guardrails` | Security | HTTP |
277315| `ip_acl` | Security | HTTP |
316+ | `credential_injection` | Security | HTTP |
278317| `json_body_field` | Payload Processing | HTTP |
279318| `compression` | Payload Processing | HTTP |
280319| `cors` | Security | HTTP |
@@ -347,12 +386,24 @@ recover. See [health-checks.yaml].
347386| `timeout_ms` | integer | 2000 | Per-probe timeout in ms |
348387| `healthy_threshold` | integer | 2 | Consecutive successes to mark healthy |
349388| `unhealthy_threshold` | integer | 3 | Consecutive failures to mark unhealthy |
389+ | `passive_unhealthy_threshold` | integer | none | Consecutive upstream failures (5xx or connect error) to mark unhealthy without probes |
390+ | `passive_healthy_threshold` | integer | none | Consecutive upstream successes to recover a passively-marked endpoint |
350391
351392TCP health checks only verify a TCP connection can be
352393established; `path` and `expected_status` are ignored.
353394When active health checks are configured, the admin
354395` /ready` endpoint reports per-cluster health counts.
355396
397+ Passive health checking tracks upstream request
398+ outcomes inline. When `passive_unhealthy_threshold` is
399+ set, endpoints that return consecutive 5xx responses or
400+ connect errors are marked unhealthy without dedicated
401+ probe traffic. Set `passive_healthy_threshold` to
402+ control how many consecutive successes are required to
403+ recover. Passive and active checks can be used together;
404+ either mechanism can mark an endpoint unhealthy, and
405+ either can recover it.
406+
356407By default, health check endpoints that resolve to
357408loopback or cloud metadata addresses are rejected
358409(SSRF protection).
@@ -448,6 +499,36 @@ When `allow` is set, only matching IPs are permitted.
448499` allow` takes precedence over `deny`. Denied requests
449500receive a `403 Forbidden` response.
450501
502+ # ## Credential Injection
503+
504+ Injects per-cluster API credentials into upstream
505+ requests and strips client-provided credentials to
506+ prevent forwarding. Pair with a source discriminator
507+ (IP ACL, client authentication) to control which
508+ clients receive credential upgrades. See
509+ [credential-injection.yaml].
510+
511+ ` ` ` yaml
512+ - filter: credential_injection
513+ clusters:
514+ - name: openai
515+ header: Authorization
516+ value: "sk-example-key"
517+ header_prefix: "Bearer "
518+ strip_client_credential: true
519+ ` ` `
520+
521+ | Field | Type | Required | Description |
522+ | ----- | ---- | -------- | ----------- |
523+ | `clusters[].name` | string | yes | Cluster to inject credentials for |
524+ | `clusters[].header` | string | yes | Header name to set |
525+ | `clusters[].value` | string | one of | Inline credential value |
526+ | `clusters[].env_var` | string | one of | Environment variable containing the credential |
527+ | `clusters[].header_prefix` | string | no | Prefix prepended to the value (e.g. `"Bearer "`) |
528+ | `clusters[].strip_client_credential` | bool | no | Remove client-sent value before injection (default : true) |
529+
530+ [credential-injection.yaml] : ../examples/configs/ai/credential-injection.yaml
531+
451532# ## TCP Access Log
452533
453534Structured JSON logging of TCP connections. Works on both
@@ -515,6 +596,31 @@ successful responses.
515596| `rate` | float | yes | Tokens per second (must be > 0) |
516597| `burst` | integer | yes | Max bucket capacity (must be >= rate) |
517598
599+ # ## Circuit Breaker
600+
601+ Per-cluster circuit breaker that prevents cascading
602+ failures. When consecutive upstream failures reach the
603+ threshold, the circuit opens and subsequent requests
604+ receive 503 immediately. After the recovery window, a
605+ single probe request is forwarded; if it succeeds the
606+ circuit closes. See [circuit-breaker.yaml].
607+
608+ ` ` ` yaml
609+ - filter: circuit_breaker
610+ clusters:
611+ - name: backend
612+ consecutive_failures: 5
613+ recovery_window_secs: 30
614+ ` ` `
615+
616+ | Field | Type | Required | Description |
617+ | ----- | ---- | -------- | ----------- |
618+ | `clusters[].name` | string | yes | Cluster name to protect |
619+ | `clusters[].consecutive_failures` | integer | yes | Failures before opening |
620+ | `clusters[].recovery_window_secs` | integer | yes | Seconds before half-open probe |
621+
622+ [circuit-breaker.yaml] : ../examples/configs/traffic-management/circuit-breaker.yaml
623+
518624# ## Guardrails
519625
520626Rejects requests matching string or regex rules against
0 commit comments