How are you coordinating resilience patterns (retry + circuit breaker + timeout) in Python?

I’ve been working on a few services where I need retry, circuit breaker, and timeout to work together — not just stacked independently.

The problem I keep running into: tenacity handles retries well, pybreaker handles circuit breaking, but they don’t share state. Retries keep firing even when the circuit breaker should have opened. Timeouts don’t account for retry attempts already spent.

In Java, Resilience4j solves this by coordinating all patterns in one system. I couldn’t find a Python equivalent.

But I’m curious, how are others handling this?

Specifically:

  • Are you combining multiple resilience libraries, and if so, how do you coordinate them?
  • Do you use any patterns for shared circuit breaker state across multiple functions calling the same service?
  • Is anyone using retry budgets to prevent retry storms across a service?

Would love to hear what’s working (or not working) for people.

Update for anyone finding this thread later: I ended up consolidating the patterns into
pyresilience, and the 0.4.0 release just landed with the pieces this discussion convinced me
mattered most for day-to-day HTTP/LLM work:

  • Retry-After-aware retrying — retry_after_delay() parses the header (delta-seconds and
    HTTP-date) and falls back to exponential backoff when it’s absent
  • retry_on_status(429, 503) — retry on response status codes without raising
  • ignore_on — exception types that are never retried and never trip the circuit breaker
    (auth/quota/validation errors fail fast), same semantics as Resilience4j’s ignoreExceptions
  • llm_policy() — preset combining client-side rate limiting + 429-aware retry + timeout +
    circuit breaker

Still zero runtime dependencies, one decorator for sync and async. Docs:
https://pyresilience.readthedocs.io — and I’m very interested in counter-arguments to the
unified-executor approach if anyone here has run a different architecture in production.