Skip to main content

Baldur

CI Python 3.11+ License: Apache 2.0 PyPI Docs OpenSSF Best Practices

English | 한국어

Baldur keeps the Python calls that fail while a dependency is down, and replays them when it comes back. Wrap a call in one decorator: if the payment gateway dies mid-traffic, every charge that fails is captured with its arguments, a circuit breaker stops your service from piling onto the dying dependency, and the moment the gateway recovers the captured charges are replayed. Nothing is silently lost. Around that loop it ships what you need to run it in production — health checks, Prometheus and OpenTelemetry metrics, graceful shutdown, a built-in web console — with adapters for Django, FastAPI, Flask, and Celery.

Terminal demo: the payment gateway becomes unreachable mid-traffic — five charges fail after their retries and the breaker trips, two more are rejected on the spot, all seven are captured, and on recovery Baldur replays all seven. Zero lost.

Real run of the shipped demo: the gateway goes unreachable mid-traffic — an infrastructure failure, not a declined card — so five charges fail after their retries and are captured with their arguments, the circuit breaker opens and shields the dying dependency (the two charges it rejects never run, and are captured too), and the moment it closes again Baldur replays all seven for real. Zero lost. (Replay is for work that failed on the way out, never for a business rejection, and never for a checkout the customer already walked away from — where that line sits.) Reproduce it yourself:

pip install "baldur-framework[celery]"
python -m baldur.scripts.demo_self_healing

(The breaker states and DLQ tallies in the recording are read live from the running framework. In your own service the same story surfaces as Baldur's structured log events, live breaker state in the built-in web console, and the Prometheus/OpenTelemetry metrics.)

Why Baldur?

  • The call that failed for good is not gone. dlq=True captures it with its arguments; the breaker's recovery replays it, through a handler you register and only for the failure types you opt in. Retry is a policy; capture-and-replay-on-recovery is the part no retry library gives you.
  • Around that loop, one decorator composes the whole pipeline. @baldur.protected("name") orders a circuit breaker, a wall-clock budget, fallback, idempotency, and dead-letter capture into one pipeline — the parts your HTTP client or vendor SDK leaves to you. Retry composes in too, for calls that don't retry themselves; where your SDK already retries, keep it and let Baldur surround it.
  • Zero-config start, production path built in. Out of the box everything runs on an in-memory backend — no Redis, no env vars, no Docker. When you move to multiple workers, add Redis and the same code shares state across the fleet. Call sites never change.
  • Operate it, don't just import it. A built-in web console shows every breaker's live state and gives you runtime on/off controls; health checks tell your load balancer the truth; metrics come standard.
  • Framework-native. Django, FastAPI, Flask, and Celery adapters wire the cache, metrics, and lifecycle hooks at startup, so protection works with your framework's idioms rather than around them.

Install

The Python package is baldur (you import baldur); the PyPI distribution is baldur-framework.

pip install baldur-framework                 # framework-agnostic core
pip install baldur-framework[django]         # Django integration
pip install baldur-framework[fastapi]        # FastAPI integration
pip install baldur-framework[flask]          # Flask integration
pip install baldur-framework[celery]         # Celery task protection
pip install baldur-framework[redis]          # Redis-backed shared state
pip install baldur-framework[prometheus]     # Prometheus metrics

Quick example

import baldur


@baldur.protected("charge-customer", dlq=True)
def charge(order_id: str, amount_cents: int) -> dict:
    # Circuit breaker by default; dlq=True parks the call if it fails for
    # good, with its arguments, and replays it once the gateway recovers.
    # Zero configuration runs on an in-memory backend — no Redis, no env
    # vars, no Docker.
    return payment_gateway.charge(order_id, amount_cents)

When the gateway dies, the breaker opens and your service answers fast instead of stacking up timeouts; the charges that failed on the way out wait in the dead-letter queue and come back when it closes. The same decorator protects any dependency — your database, a model provider mid-incident:

@baldur.protected("llm-summarize")
def summarize(doc_id: str) -> str:
    return llm_api.summarize(doc_id)

Need more than the default? Compose the pipeline declaratively:

@baldur.protected(
    "llm-summarize",
    timeout=30.0,                            # one bound on what the caller waits
    fallback=lambda: last_good_summary(),    # graceful answer while OPEN
    idempotency_key="doc_id",                # a redelivered job pays once
)
def summarize(doc_id: str) -> str:
    return llm_api.summarize(doc_id)

Notice what isn't there: retry=. Your SDK almost certainly retries already — anthropic and openai default to two attempts with backoff, boto3 has an adaptive mode — and it retries better than a generic wrapper can, because it knows which status codes are worth another attempt and honours retry-after. Keep it. What no SDK gives you is the rest: a breaker, so a provider incident doesn't mean every request pays its retries before failing; one wall-clock bound on what your caller waits, retries included (an SDK's own worst case is timeout × (max_retries + 1) — 30 minutes at anthropic's defaults); a fallback; and a dedup key that survives a job redelivery the SDK never sees. retry=True is there for the calls that don't retry themselves.

Sync and async callables are both supported — the decorator auto-detects coroutine functions.

What's in the box (OSS, Apache-2.0)

Capability What it gives you
Circuit breaker Stops cascading failure; bounded half-open probes on recovery
Retry with backoff Exponential backoff with jitter and bounded attempts
Fallback & composition One ordered pipeline for all resilience patterns
Idempotency Concurrent duplicate calls execute the side effect exactly once
Bulkhead isolation Each dependency gets a fixed slice of concurrency, so one slow dependency can't drain every worker
Dead-letter queue + replay A call that fails for good is captured with its context and replayed once the dependency recovers
Health checks Liveness/readiness that reflect real dependency state
Graceful shutdown Drain in-flight work cleanly on restart and deploy
Metrics Prometheus and OpenTelemetry, emitted by default
System control Instant kill switch and dry-run mode for Baldur's automation — no redeploy
Web console Built-in operations console: live breaker state, controls, recovery
Precomputed cache Health/status endpoints answer from a warm cache, so constant probing stays cheap

The read path heals the same way. Here a Django app under live HTTP traffic (recorded from a demo harness driving it) loses its network path to Redis for 21 seconds — every request keeps returning 200 off the in-memory cache tier, and the Redis tier resyncs itself on recovery:

Terminal demo: a Django app keeps serving 200s through a 21-second Redis outage

Baldur PRO

PRO adds the durable, fleet-level machinery on top of the same API — nothing in the core gets relicensed or replaced. Highlights: DLQ at scale (batch replay from the console, success-rate-driven pacing, a disk-durable outbox, and archive/purge retention), hash-chained audit trail, unified notifications, emergency mode, bulkhead thread-pool isolation, adaptive throttling, canary recovery, governance gates, and a meta-watchdog that watches Baldur itself.

See the full OSS vs PRO capability matrix and pricing.

Documentation

Full documentation lives at https://baldur.sh.

Using Baldur with AI assistants

Building with an AI coding assistant (Claude Code, Cursor, Copilot, Codex)? Run baldur init-ai in your repo to drop an AGENTS.md (read by Cursor, Copilot, and Codex) plus a CLAUDE.md that imports it for Claude Code — together they teach the assistant to reach for @baldur.protected("name") instead of hand-rolling a circuit breaker. See Using Baldur with AI assistants.

Compatibility

Component Minimum Tested in CI
Python 3.11 3.11 · 3.12 · 3.13
Django 4.2 4.2 LTS · 5.2 LTS · 6.0
FastAPI 0.100 latest ≥ floor (smoke)
Flask 2.3 latest ≥ floor (smoke)
Celery 5.3 5.4
Redis server — 7.x

See Compatibility for the full matrix, the Python × Django test grid, and the version support policy.

Early access

Baldur is in early access: the API is stable and the core is tested under sustained load with Sentinel failover, but the project is young — minor releases may still ship breaking changes, always with a changelog entry. It is looking for a small number of teams already running a Python service in production to work with directly. If that is you, the details and how to reach me are in Discussions.

License

Baldur is released under the Apache License 2.0 — see LICENSE and NOTICE.

Contributing

Contributions are welcome under the Apache License 2.0. Pull requests are accepted through a sign-off-based DCO flow — see CONTRIBUTING.md for the full model.

  • Ideas, or showing what you built → Discussions.
  • Bugs / feature requests / docs → open an issue or a pull request.
  • Security → see SECURITY.md (no public issues for vulnerabilities).
  • Usage questions / commercial → support@baldur.sh.

Metadata

Release files for baldur-framework 1.15.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for baldur-framework 1.15.0
File Size Uploaded
baldur_framework-1.15.0.tar.gz 2.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for baldur-framework 1.15.0
File Interpreter ABI Platform
baldur_framework-1.15.0-py3-none-any.whl Python 3 none any Details

Total release size: 6.1 MB

Release files / baldur_framework-1.15.0.tar.gz

Download URL baldur_framework-1.15.0.tar.gz
Size 2.7 MB
Tags Source
SHA-256 checksum
How to use checksums
fa307655185b962275d6a013e20ad75c2a9d2d2807d9f3e951757491ebd9f86d
BLAKE2b-256 checksum
How to use checksums
91ffb0f0f95fa0e833b1324c2d160b8984944e12f5ea8daf06882bb15dda3187
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release files / baldur_framework-1.15.0-py3-none-any.whl

Download URL baldur_framework-1.15.0-py3-none-any.whl
Size 3.4 MB
Tags Python 3
SHA-256 checksum
How to use checksums
58500b7c06c17f9189ba94ed8035f4c78ed341a574355f90c2d22d3c44596081
BLAKE2b-256 checksum
How to use checksums
de1887c3cdf312af319d7e3521388a9c4f9f1cb276206d0b28977cacd2386a87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release history Release notifications | RSS feed

1.16.0

2 release files

1.15.1

2 release files

This release

1.15.0 This release

2 release files

1.14.1

2 release files

1.14.0

2 release files

1.13.1

2 release files

1.13.0

2 release files

1.9.0

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page