Circuit Breaker
NORA includes a circuit breaker that tracks upstream failures and short-circuits requests when an upstream is known to be down. This avoids slow timeouts cascading into your build pipelines.
Docker, PyPI, npm and Maven keep one breaker per configured upstream, so a dead upstream does not cut off a healthy one (Maven after 1.4.3; before, one breaker covered all of maven.proxies); their keys are <format>:<upstream URL> (for example pypi:https://pypi.org/simple), with any user:pass@ removed. Every other format keeps one breaker per format, keyed by its name.
The circuit breaker is disabled by default and must be explicitly enabled.
Environment Variables
Section titled “Environment Variables”| Variable | Default | Description |
|---|---|---|
NORA_CB_ENABLED | false | Enable upstream circuit breaker |
NORA_CB_THRESHOLD | 5 | Consecutive failures before opening the circuit |
NORA_CB_RESET_TIMEOUT | 30 | Seconds to wait before probing a failed upstream |
How It Works
Section titled “How It Works”The circuit breaker operates as a state machine with three states per upstream registry:
success ┌─────────────────────┐ │ │ ▼ N failures │Closed ──────────► Open ──(reset_timeout)──► HalfOpen ▲ │ │ │ │ reject (503 + │ probe │ │ Retry-After) │ succeeds │ ▼ │ │ caller gets 503 │ └────────────────────────────────────────────┘ probe fails → back to OpenClosed — Normal operation. All requests pass through to the upstream. Each failure increments a counter.
Open — The upstream has failed failure_threshold consecutive times. No request is sent to it. Where the format has another upstream to ask — the next entry of maven.proxies, the next Docker upstream in the fallback chain, the next PyPI index — NORA asks that one instead (Maven and Docker after 1.4.3; before, the request ended with 503). When no upstream serves the request, a copy in local storage that could not be revalidated is served stale (x-nora-stale: true); otherwise Maven and Docker answer 404 if another upstream said the artifact is not there, and 503 Service Unavailable with a Retry-After header if not. PyPI answers 503 whenever an upstream was skipped and none served. A Docker name bound to one upstream through namespaces has no other upstream to ask and gets 503.
HalfOpen — After reset_timeout seconds, a single probe request is allowed through. If it succeeds, the breaker closes. If it fails, the breaker re-opens.
config.toml
Section titled “config.toml”[circuit_breaker]enabled = truefailure_threshold = 5reset_timeout = 30Per-Registry Overrides
Section titled “Per-Registry Overrides”Override the threshold or timeout for one upstream with its breaker key, "<format>:<url>" — the configured URL, without a trailing slash or credentials — or for a whole format with its name ("pypi"). Each value is looked up per upstream first, then per format, then falls back to the global setting:
[circuit_breaker]enabled = truefailure_threshold = 5reset_timeout = 30
[circuit_breaker.overrides."docker:https://registry-1.docker.io"]failure_threshold = 10reset_timeout = 120
[circuit_breaker.overrides."npm:https://registry.npmjs.org"]failure_threshold = 3reset_timeout = 60This lets you be more tolerant of occasional Docker Hub failures while cutting off flaky npm upstreams faster.
Prometheus Metrics
Section titled “Prometheus Metrics”| Metric | Type | Labels | Description |
|---|---|---|---|
nora_circuit_breaker_state | Gauge | registry | Current state: 0 = Closed, 1 = Open, 2 = HalfOpen |
nora_circuit_breaker_rejections_total | Counter | registry | Total requests rejected by an open breaker |
registry is the breaker key: the format name, or <format>:<upstream URL> for Docker, PyPI, npm and Maven (Maven after 1.4.3; before, registry="maven"). Match a whole format with a regex, registry=~"pypi(:.*)?", not registry="pypi". /health reports, per format, the worst breaker of its upstreams.
Example alert (Prometheus):
- alert: NoraCircuitBreakerOpen expr: nora_circuit_breaker_state == 1 for: 5m labels: severity: warning annotations: summary: "NORA circuit breaker open for {{ $labels.registry }}"Example: Docker Compose
Section titled “Example: Docker Compose”services: nora: image: getnora/nora:latest environment: NORA_CB_ENABLED: "true" NORA_CB_THRESHOLD: "5" NORA_CB_RESET_TIMEOUT: "30" ports: - "4000:4000"See Also
Section titled “See Also”- Settings — complete environment variable reference
- Docker Proxy — upstream proxy configuration
- Production Deployment — production deployment guide