Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/danielfm/pybreaker/llms.txt

Use this file to discover all available pages before exploring further.

PyBreaker gives you three distinct ways to wrap code with a circuit breaker. All three share the same underlying state machine — they differ only in how you apply them. Pick the pattern that best matches your codebase style and constraints.

Decorator Pattern

The decorator pattern is the most idiomatic PyBreaker usage. Apply @db_breaker directly to a function definition, and every subsequent call to that function automatically passes through the circuit breaker.
import pybreaker

db_breaker = pybreaker.CircuitBreaker(fail_max=5, reset_timeout=60)

@db_breaker
def update_customer(cust):
    # Do stuff here...
    pass

# Will trigger the circuit breaker
updated_customer = update_customer(my_customer)
Under the hood, @db_breaker uses functools.wraps, so the wrapped function’s __name__, __doc__, and other metadata are fully preserved. Introspection tools and logging that rely on func.__name__ will continue to see the original function name.

Direct Call Pattern

Use cb.call() when you cannot or do not want to modify the function definition — for example, with third-party functions, lambdas, or dynamically resolved callables.
def update_customer(cust):
    # Do stuff here...
    pass

# Will trigger the circuit breaker
updated_customer = db_breaker.call(update_customer, my_customer)
Signature: CircuitBreaker.call(func, *args, **kwargs) -> T All positional and keyword arguments after func are forwarded to the function as-is. The return value is whatever func returns.

Context Manager Pattern

Use cb.calling() to protect an inline block of code without extracting it into a separate function. The with statement executes the block according to the circuit breaker’s current state rules.
# Will trigger the circuit breaker
with db_breaker.calling():
    # Do stuff here...
    pass
The context manager pattern is ideal when you want to protect a short inline block — such as a series of related operations — without the overhead of defining and naming a dedicated wrapper function.

Generator Functions

The circuit breaker can guard generator functions. Failures that occur inside the generator body — including during iteration — are correctly handled and counted against the failure threshold.
@db_breaker
def fetch_records():
    for record in db.stream_query("SELECT * FROM records"):
        yield record

for record in fetch_records():
    process(record)
When a generator raises an exception mid-iteration, the circuit breaker intercepts it, increments the failure counter, and re-raises as normal. This means streaming queries and lazy pipelines are fully protected.

Choosing a Pattern

Best for: Functions you own and want permanently protected.
  • Applied once at definition time — no call-site changes needed
  • Preserves function metadata via functools.wraps
  • Works with regular functions and generator functions
  • Most readable when the same function is always called through the breaker
@db_breaker
def get_user(user_id):
    return db.query("SELECT * FROM users WHERE id = ?", user_id)

Build docs developers (and LLMs) love