Skip to main content

cubiczan-resilience (Python)

Battle-tested resilience primitives, lifted and generalised from production services (CFO resilience matrix, Strata AWS-native, Hermes Pi factory guardian, Valiron advisory AI):

  • @resilient(...) — mandatory timeout + exponential backoff with full jitter
    • pluggable circuit breaker, for sync and async callables.
  • CircuitBreaker — standalone CLOSED / OPEN / HALF_OPEN breaker.
  • IdempotencyStore — protocol + in-memory and file-backed impls to guard money/state operations against double-execution on retry.
  • atomic_write(path, data) — write-to-temp + os.replace, never a partial file.
  • AuditLedger / verify_ledger — signed, append-only JSONL audit ledger with HMAC-SHA256 signature chaining (see the Audit Ledger section for the shared scheme).
  • FastAPI helpers — fail-closed require_auth bearer dependency and a cors_allowlist factory that forbids wildcard-origin + credentials.

Pure stdlib core. httpx and fastapi are optional extras.

Install

pip install cubiczan-resilience            # core only
pip install 'cubiczan-resilience[fastapi]' # + FastAPI helpers
pip install 'cubiczan-resilience[http]'    # + httpx

Requires Python >= 3.10.

@resilient

from cubiczan_resilience import resilient, CircuitBreaker

breaker = CircuitBreaker("payments-api", failure_threshold=5, cooldown_seconds=30)

@resilient(
    timeout=2.0,              # mandatory per-attempt deadline (seconds)
    max_attempts=4,
    base_delay=0.1,           # full-jitter backoff: U(0, base * 2**attempt)
    max_delay=10.0,
    retryable_exceptions=(ConnectionError, TimeoutError),
    circuit_breaker=breaker,  # optional; gates + records outcomes
)
def call_api() -> dict:
    ...

# Async works the same way; the timeout is hard-enforced via asyncio.wait_for.
@resilient(timeout=5.0, max_attempts=3)
async def call_api_async() -> dict:
    ...

Retry decisions: if the raised exception exposes an HTTP status (httpx/requests style .response.status_code or a bare .status_code), it is retried only when the code is in retryable_status (default {408, 425, 429, 500, 502, 503, 504}). Otherwise the exception type is matched against retryable_exceptions. CircuitOpenError is never retried.

CircuitBreaker (standalone)

from cubiczan_resilience import CircuitBreaker, CircuitOpenError

cb = CircuitBreaker("db", failure_threshold=3, cooldown_seconds=15)

if cb.allow():
    try:
        result = do_query()
    except Exception:
        cb.record_failure()
        raise
    else:
        cb.record_success()
else:
    raise CircuitOpenError(cb.name, cb.retry_after())

Idempotency

from cubiczan_resilience import FileIdempotencyStore

store = FileIdempotencyStore("/var/lib/app/idempotency.json")

def charge(order_id: str, amount: int) -> str:
    if store.already_done(order_id):
        return store.get_result(order_id)          # replay prior result
    if not store.mark_done(order_id, "charged"):    # atomic first-writer-wins claim
        return store.get_result(order_id)
    provider.charge(amount)                          # runs exactly once
    return "charged"

InMemoryIdempotencyStore has the same interface for tests / single-process use.

Atomic writes

from cubiczan_resilience import atomic_write

atomic_write("/var/lib/app/state.json", json_payload)   # str or bytes
atomic_write("/var/lib/app/secret", token, mode=0o600)  # set perms atomically

A crash before the rename leaves the previous file fully intact — never a half-written file.

FastAPI helpers

from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from cubiczan_resilience.fastapi_helpers import require_auth, cors_allowlist

app = FastAPI()
app.add_middleware(CORSMiddleware, **cors_allowlist(["https://app.example.com"]))

auth = require_auth(env_var="API_TOKEN")  # fail-closed: 503 if env var unset

@app.get("/secure")
def secure(_: str = Depends(auth)):
    return {"ok": True}

Development

pip install -e '.[dev]'
pytest
mypy src

License

MIT

Metadata

Release files for cubiczan-resilience 0.1.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 cubiczan-resilience 0.1.0
File Size Uploaded
cubiczan_resilience-0.1.0.tar.gz 21.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cubiczan-resilience 0.1.0
File Interpreter ABI Platform
cubiczan_resilience-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.5 kB

Release files / cubiczan_resilience-0.1.0.tar.gz

Download URL cubiczan_resilience-0.1.0.tar.gz
Size 21.5 kB
Tags Source
SHA-256 checksum
How to use checksums
badf8bcefef5a492d74908874b3ada7fc03e8d2257e827a53cd0b132adee5f96
BLAKE2b-256 checksum
How to use checksums
bc9fcc1126e90cf71ff92b1cb9116ca88f8e7a1af96b2c7b4466df660a2580c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / cubiczan_resilience-0.1.0-py3-none-any.whl

Download URL cubiczan_resilience-0.1.0-py3-none-any.whl
Size 20.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7f2960543ca3d165d3ce780b3d4887f08c78586d86f6ad65f4c0372246f7d128
BLAKE2b-256 checksum
How to use checksums
8fe4e45886a091082219a551017536cb52e48452b3123f7302ce266e056dbd1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

0.1.0 This release

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