Skip to content

Resilience

grelmicro.resilience

Resilience.

Pick the front door first, the algorithm second, the backend third.

Front doors (start here):

  • RateLimiter.token_bucket(...) or RateLimiter.sliding_window(...) for rate limiting.
  • CircuitBreaker("name") or CircuitBreaker.consecutive_count(...) for circuit breaking.
  • Retry("name", backoff, when=...) or the @retry(...) / retrying(...) decorator and block form.
  • Fallback("name", when=..., default=...) or the @fallback(...) / falling_back(...) decorator and block form.
  • Timeout("name", seconds=...) for deadlines.
  • Bulkhead("name", max_concurrent=...) or the @bulkhead decorator to cap concurrent in-flight calls.
  • Shield("name") or the @shield(...) decorator for the bundled timeout + retry + adaptive rate-limit + cache + fallback profile.

Components (wire the front doors into Grelmicro(uses=[...])):

  • RateLimiterRegistry(backend) and CircuitBreakerRegistry(backend). They register the shared storage. Without them, pass backend= on the primitive (a memory adapter is fine for tests and single-replica services).

Adapters / backends (one per storage choice, used inside RateLimiterRegistry / CircuitBreakerRegistry): MemoryRateLimiterAdapter, RedisRateLimiterAdapter, PostgresRateLimiterAdapter, SQLiteRateLimiterAdapter, MemoryCircuitBreakerAdapter, RedisCircuitBreakerAdapter, PostgresCircuitBreakerAdapter. End users rarely name these directly. The Components do.

Configs (frozen Pydantic models, accept env vars): TokenBucketConfig, SlidingWindowConfig, CircuitBreakerConfig, RetryConfig, FallbackConfig, TimeoutConfig, BulkheadConfig, ShieldConfig. One per pattern, plus backoff configs (ExponentialBackoff, LinearBackoff, ...).

Loading: top-level re-exports are PEP 562 lazy. Importing this package loads _components, _match, _outcome, _protocol, and errors plus the eager exports listed below. Every other pattern, its algorithm configs, and the memory/redis adapters load on first attribute access. from grelmicro.resilience import CircuitBreaker does not import anything related to RateLimiter.

Eager exports (loaded at package import because the function name shadows a submodule of the same name): retry, retrying, fallback, falling_back, shield. The shield import pulls the full grelmicro.resilience.shield subpackage.

CircuitBreakerConfig module-attribute

CircuitBreakerConfig = ConsecutiveCountConfig

Discriminated union of supported circuit-breaker algorithm configurations.

Single-arm today. Future algorithms (failure-rate, slow-call) join the union via the kind discriminator without breaking existing serialized configs.

Matcher module-attribute

Matcher = Callable[[Outcome[Any]], bool]

Callable signature every Match resolves to.

Returns True when the outcome should engage the strategy.

RateLimiterConfig module-attribute

RateLimiterConfig = TokenBucketConfig | SlidingWindowConfig

Discriminated union of supported rate-limiter algorithm configurations.

RetryBackoffConfig module-attribute

Discriminated union of supported retry backoff configurations.

ShieldConfig module-attribute

Discriminated union over the three Shield profile configs.

retrying module-attribute

retrying = _RetryingFactory()

Bulkhead

Bulkhead(
    name: str,
    *,
    max_concurrent: PositiveInt | None = None,
    max_wait: NonNegativeFloat | None = None,
    max_workers: PositiveInt | None = None,
    uses: Iterable[
        AbstractAsyncContextManager[object]
    ] = (),
    config: BulkheadConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[BulkheadConfig]

Bulkhead policy.

A named, reusable concurrency limiter with three-paths configuration and live reconfiguration. Use it as an async context manager or as a decorator on async functions to bound the number of in-flight calls, and to_thread to run blocking work on a bounded private thread pool.

When the bulkhead is full, a caller waits up to max_wait seconds for a permit, then is rejected with BulkheadFullError. The default fails fast (no wait).

Read more in the Bulkhead docs.

Initialize the bulkhead.

PARAMETER DESCRIPTION
name

The name of the bulkhead. Used as the env namespace, the rejection error label, and the thread-name prefix.

TYPE: str

max_concurrent

Maximum concurrent calls. None leaves it unbounded.

TYPE: PositiveInt | None DEFAULT: None

max_wait

Seconds to wait for a permit before rejecting. None or 0 fails fast.

TYPE: NonNegativeFloat | None DEFAULT: None

max_workers

Private thread-pool size for to_thread.

TYPE: PositiveInt | None DEFAULT: None

uses

Providers and Components, in the same shape as Grelmicro(uses=[...]), scoped to this bulkhead. Inside the scope, a Pattern that resolves its default backend (a bare Lock("k"), cache.get(...), ...) picks up the matching Component here instead of the app's. A Pattern with an explicit backend= is unaffected. The bulkhead opens these on first entry and closes them when the app shuts down, so an active Grelmicro app is required.

TYPE: Iterable[AbstractAsyncContextManager[object]] DEFAULT: ()

config

A pre-built BulkheadConfig. Mutually exclusive with the per-field kwargs.

TYPE: BulkheadConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property

name: str

Return the bulkhead identity.

from_config classmethod

from_config(name: str, config: BulkheadConfig) -> Self

Construct a Bulkhead from a name and a pre-built BulkheadConfig.

PARAMETER DESCRIPTION
name

The name of the bulkhead.

TYPE: str

config

The pre-built bulkhead configuration.

TYPE: BulkheadConfig

to_thread async

to_thread(
    func: Callable[..., Any], /, *args: Any, **kwargs: Any
) -> Any

Run func in a worker thread, bounded by max_workers.

Routes through the bulkhead's private ThreadPoolExecutor when max_workers is set, otherwise the event loop's shared executor (asyncio.to_thread).

PARAMETER DESCRIPTION
func

Blocking callable to run off the event loop.

TYPE: Callable[..., Any]

BulkheadConfig

Bases: BaseModel

Bulkhead policy configuration.

Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Bulkhead docs.

max_concurrent class-attribute instance-attribute

max_concurrent: PositiveInt | None = None

Maximum concurrent calls admitted to the bulkhead. None (the default) leaves concurrency unbounded.

max_wait class-attribute instance-attribute

max_wait: NonNegativeFloat | None = None

Seconds a caller waits for a free permit before the bulkhead rejects it with BulkheadFullError. None (the default) and 0 reject immediately (fail fast). Ignored when max_concurrent is None.

max_workers class-attribute instance-attribute

max_workers: PositiveInt | None = None

Size of the private thread pool backing to_thread. None (the default) uses the event loop's shared executor.

BulkheadFullError

BulkheadFullError(*, name: str, max_concurrent: int)

Bases: ResilienceError, AdmissionError

Bulkhead full error.

Raised when a bulkhead has no free permit and the caller's max_wait elapsed (or was zero, the fail-fast default).

Initialize the error.

name instance-attribute

name = name

max_concurrent instance-attribute

max_concurrent = max_concurrent

CircuitBreakerRegistry

CircuitBreakerRegistry(
    source: Provider
    | CircuitBreakerBackend
    | type[Provider | CircuitBreakerBackend],
    *,
    name: str = "default",
)

CircuitBreakerBackend wrapper exposing (circuitbreaker, name) registration.

Registered on a Grelmicro app via Grelmicro(uses=[CircuitBreakerRegistry(redis)]). The active app resolves CircuitBreaker patterns to this Component's backend on every call.

Accepts a Provider or a CircuitBreakerBackend. When given a Provider, the component calls provider.circuitbreaker() to build the matching adapter.

Example
from grelmicro import Grelmicro
from grelmicro.providers.redis import RedisProvider
from grelmicro.resilience import CircuitBreaker, CircuitBreakerRegistry

redis = RedisProvider("redis://localhost:6379/0")
micro = Grelmicro(uses=[redis, CircuitBreakerRegistry(redis)])
payment = CircuitBreaker("payment")

async with micro:
    async with payment:
        ...

Initialize the Component with the wrapped backend.

PARAMETER DESCRIPTION
source

A Provider or a CircuitBreakerBackend instance. When a Provider is given, the component calls provider.circuitbreaker() to build the matching adapter.

TYPE: Provider | CircuitBreakerBackend | type[Provider | CircuitBreakerBackend]

name

Registration name. Multiple CircuitBreakerRegistry Components may coexist on one Grelmicro under different names.

TYPE: str DEFAULT: 'default'

kind class-attribute

kind: str = 'circuitbreaker'

name property

name: str

Return the registration name.

backend property

The underlying CircuitBreakerBackend.

CircuitBreaker

CircuitBreaker(
    name: str,
    config: CircuitBreakerConfig | None = None,
    *,
    backend: CircuitBreakerBackend | str | None = None,
)

Bases: Reconfigurable['CircuitBreakerConfig']

Circuit Breaker.

Implements the circuit breaker pattern. It watches calls to a protected service and blocks them when the service is failing, to avoid cascading errors.

Supports live reconfiguration via reconfigure(new_config). A swap takes effect on the next call. In-flight calls keep the config they entered with. The current state, counters, and last_error are kept. A new log_level is applied to the logger. See Live reconfiguration.

Initialize the circuit breaker, defaulting the algorithm to consecutive-count.

PARAMETER DESCRIPTION
name

Name of the circuit breaker instance.

Acts as the instance identity, exposed via the name property.

TYPE: str

config

The algorithm configuration.

Defaults to ConsecutiveCountConfig() with library defaults when omitted. Most callers should prefer the CircuitBreaker.consecutive_count factory classmethod to tweak the defaults. Pass a config directly when it is already assembled elsewhere, for example from YAML or a pydantic-settings tree.

Today the discriminated union has a single arm: ConsecutiveCountConfig. Future algorithms (failure_rate, slow_call) join the union via the same kind discriminator.

TYPE: CircuitBreakerConfig | None DEFAULT: None

backend

The circuit breaker backend that owns the lifespan and (with a shared adapter) the cross-replica state.

Accepts a backend instance, the name of a registered backend (e.g. "analytics"), or None to fall back to the registered "default" Component.

TYPE: CircuitBreakerBackend | str | None DEFAULT: None

backend property

Bound circuit breaker backend, resolved on each call.

Resolution order: 1. An explicit backend= passed at construction wins. 2. The active Grelmicro app is consulted via Grelmicro.current() so that micro.override(...) blocks take effect.

RAISES DESCRIPTION
OutOfContextError

No backend resolved in this scope. Pass backend= (a MemoryCircuitBreakerAdapter() for a per-replica breaker), register a CircuitBreakerRegistry Component, or run the call inside async with micro: or after micro.install(app).

from_thread property

from_thread: _ThreadAdapter

Sync adapter for use from a worker thread.

Use it from a synchronous handler that the host framework runs in a worker thread. The adapter signals the intent explicitly so the async API stays the documented default.

name property

name: str

Return the name of the circuit breaker.

state property

Return the current cached state of the circuit breaker.

last_error property

last_error: Exception | None

Return the last error recorded by the circuit breaker.

last_error_time property

last_error_time: datetime | None

Return the time of the last error recorded by the circuit breaker.

from_config classmethod

from_config(
    name: str,
    config: CircuitBreakerConfig,
    *,
    backend: CircuitBreakerBackend | str | None = None,
) -> Self

Construct a CircuitBreaker from a name and a pre-built CircuitBreakerConfig.

PARAMETER DESCRIPTION
name

Name of the circuit breaker instance.

TYPE: str

config

The pre-built circuit breaker configuration.

Use this path when the configuration is assembled at startup from a settings tree. The environment path is bypassed and the config is used as-is.

TYPE: CircuitBreakerConfig

backend

The circuit breaker backend.

TYPE: CircuitBreakerBackend | str | None DEFAULT: None

consecutive_count classmethod

consecutive_count(
    name: str,
    *,
    ignore_exceptions: type[Exception]
    | str
    | tuple[type[Exception] | str, ...]
    | None = None,
    error_threshold: PositiveInt | None = None,
    success_threshold: PositiveInt | None = None,
    reset_timeout: PositiveFloat | None = None,
    half_open_capacity: PositiveInt | None = None,
    log_level: LogLevel | None = None,
    backend: CircuitBreakerBackend | str | None = None,
) -> Self

Construct a CircuitBreaker running the consecutive-count algorithm.

Sibling of from_config and the bare constructor: the bare constructor reads env vars for unset fields, this factory does not.

PARAMETER DESCRIPTION
name

Name of the circuit breaker instance.

TYPE: str

ignore_exceptions

Exceptions ignored by the breaker.

TYPE: type[Exception] | str | tuple[type[Exception] | str, ...] | None DEFAULT: None

error_threshold

Consecutive errors before the breaker opens. Default: 5.

TYPE: PositiveInt | None DEFAULT: None

success_threshold

Consecutive successes in HALF_OPEN before the breaker closes. Default: 2.

TYPE: PositiveInt | None DEFAULT: None

reset_timeout

Seconds the breaker stays OPEN before transitioning to HALF_OPEN. Default: 30.0.

TYPE: PositiveFloat | None DEFAULT: None

half_open_capacity

Maximum concurrent calls allowed in the HALF_OPEN state. Default: 1.

TYPE: PositiveInt | None DEFAULT: None

log_level

Logging level for state-change messages. Default: WARNING.

TYPE: LogLevel | None DEFAULT: None

backend

The circuit breaker backend.

TYPE: CircuitBreakerBackend | str | None DEFAULT: None

metrics

metrics() -> CircuitBreakerMetrics

Return current metrics for this circuit breaker.

isolate async

isolate() -> None

Force the breaker open and keep it open until reset.

The manual "big red button". Moves the breaker to FORCED_OPEN, so every call is blocked with CircuitBreakerError regardless of outcomes, until reset returns it to automatic operation.

reset async

reset() -> None

Return the breaker to normal automatic operation.

Clears all counters and the last recorded error, then moves the breaker to CLOSED. Use it to release an isolate hold or to start fresh from a known state.

CircuitBreakerBackend

Bases: Protocol

Protocol for circuit-breaker storage backends.

A backend owns the lifespan boundary and the storage for every circuit breaker bound to it. It turns a name and a config into a strategy through bind. The returned CircuitBreakerStrategy is what a CircuitBreaker calls on each try_acquire, record_outcome, transition, or get_snapshot. No extra algorithm lookup happens at call time.

Implementations capture the running event loop on __aenter__ in a _loop attribute so the sync from_thread adapter can dispatch coroutines back into it.

is_shared class-attribute

is_shared: bool

Whether the backend stores state outside the local process.

True for distributed backends (e.g. Redis), False for process-local backends (e.g. memory). User code can read this to decide whether last_error is per-replica or fleet-wide.

bind

bind(
    *, name: str, config: CircuitBreakerConfig
) -> CircuitBreakerStrategy

Build a strategy for the named breaker and algorithm config.

Called once per CircuitBreaker when it is created, and again whenever the breaker's config changes through live reconfiguration.

PARAMETER DESCRIPTION
name

Breaker name, used as the storage key in shared backends.

TYPE: str

config

Algorithm configuration for the breaker.

TYPE: CircuitBreakerConfig

CircuitBreakerError

CircuitBreakerError(
    *,
    name: str,
    last_error_time: datetime | None = None,
    last_error: Exception | None = None,
)

Bases: ResilienceError, AdmissionError

Circuit breaker error.

Raised when calls are not permitted by the circuit breaker.

Initialize the error.

name instance-attribute

name = name

last_error instance-attribute

last_error = last_error

last_error_time instance-attribute

last_error_time = last_error_time

CircuitBreakerMetrics dataclass

CircuitBreakerMetrics(
    name: str,
    state: CircuitBreakerState,
    active_calls: int,
    total_error_count: int,
    total_success_count: int,
    consecutive_error_count: int,
    consecutive_success_count: int,
    last_error: ErrorDetails | None,
)

Circuit breaker metrics.

name instance-attribute

name: str

state instance-attribute

active_calls instance-attribute

active_calls: int

total_error_count instance-attribute

total_error_count: int

total_success_count instance-attribute

total_success_count: int

consecutive_error_count instance-attribute

consecutive_error_count: int

consecutive_success_count instance-attribute

consecutive_success_count: int

last_error instance-attribute

last_error: ErrorDetails | None

CircuitBreakerSnapshot

Bases: NamedTuple

Snapshot of circuit breaker state returned by a strategy.

Returned by every CircuitBreakerStrategy method that mutates or reads state. The breaker uses it to refresh its local cache so reads of cb.state and cb.metrics() reflect the latest truth from the strategy.

Algorithm-specific counters (consecutive_error_count, consecutive_success_count) are populated by the consecutive-count algorithm. Future algorithms may populate additional fields.

state instance-attribute

Authoritative state for the breaker.

opened_at instance-attribute

opened_at: float

Strategy-clock seconds when the breaker entered OPEN. 0.0 when not OPEN.

Each strategy picks its own clock. Treat this as a relative value: only compare with timestamps emitted by the same strategy.

consecutive_error_count class-attribute instance-attribute

consecutive_error_count: int = 0

Consecutive errors recorded by the strategy. Consecutive-count algorithm only.

consecutive_success_count class-attribute instance-attribute

consecutive_success_count: int = 0

Consecutive successes recorded by the strategy. Consecutive-count algorithm only.

CircuitBreakerState

Bases: StrEnum

Circuit breaker state.

State machine diagram:

┌────────┐ errors >= threshold  ┌────────┐
│ CLOSED │────────────────────> │  OPEN  │ <─┐
└────────┘                      └────────┘   │
    ▲                       timeout │        │ errors >= threshold
    │                               ▼        │
    │                         ┌───────────┐  │
    └─────────────────────────│ HALF_OPEN │──┘
      success >= threshold    └───────────┘

CLOSED class-attribute instance-attribute

CLOSED = 'CLOSED'

Circuit is closed, calls are allowed.

OPEN class-attribute instance-attribute

OPEN = 'OPEN'

Circuit is open, calls are not allowed.

HALF_OPEN class-attribute instance-attribute

HALF_OPEN = 'HALF_OPEN'

Circuit is half-open, calls are limited.

FORCED_OPEN class-attribute instance-attribute

FORCED_OPEN = 'FORCED_OPEN'

Circuit is open for an indefinite time, calls are not allowed.

FORCED_CLOSED class-attribute instance-attribute

FORCED_CLOSED = 'FORCED_CLOSED'

Circuit is forced closed for an indefinite time, calls are allowed.

CircuitBreakerStrategy

Bases: Protocol

A circuit-breaker strategy for a specific algorithm and backend.

Returned by CircuitBreakerBackend.bind. The breaker name and algorithm settings are already stored in the strategy, so the methods take no extra arguments beyond the call's own data (outcome, manual transition target).

try_acquire async

try_acquire() -> bool

Attempt to admit a call.

Returns True when the call is admitted. Returns False when the breaker is OPEN or FORCED_OPEN, or when HALF_OPEN has no remaining capacity.

record_outcome async

record_outcome(
    *, success: bool, duration: float = 0.0
) -> CircuitBreakerSnapshot

Record a call outcome and return the resulting snapshot.

PARAMETER DESCRIPTION
success

Whether the call completed without an error that counts against the breaker.

TYPE: bool

duration

Wall-clock seconds the call took. Consumed by algorithms that classify slow calls. Ignored by the consecutive-count algorithm.

TYPE: float DEFAULT: 0.0

transition async

transition(
    *,
    desired: CircuitBreakerState,
    cool_down: float | None = None,
) -> None

Force the breaker into desired.

PARAMETER DESCRIPTION
desired

Target state to force the breaker into.

TYPE: CircuitBreakerState

cool_down

Seconds the breaker stays OPEN before moving to HALF_OPEN. None uses the configured reset_timeout. Ignored when desired is not OPEN.

TYPE: float | None DEFAULT: None

get_snapshot async

get_snapshot() -> CircuitBreakerSnapshot

Return the current snapshot without mutating state.

ConsecutiveCountConfig

Bases: BaseModel

Consecutive-count circuit breaker algorithm.

Opens after error_threshold consecutive failures. Closes from HALF_OPEN after success_threshold consecutive successes. A single success in CLOSED resets the running error count.

Use this when failures cluster, for example transient downstream outages where the first N errors in a row are a strong signal. For failure-rate or slow-call detection, plug in a future algorithm config through the same kind discriminator.

Example:

from grelmicro.resilience import CircuitBreaker, ConsecutiveCountConfig

cb = CircuitBreaker.from_config(
    "payments",
    ConsecutiveCountConfig(error_threshold=5, reset_timeout=30.0),
)

Read more in the Circuit Breaker docs.

kind class-attribute instance-attribute

kind: Literal['consecutive_count'] = 'consecutive_count'

Discriminator for the algorithm Pydantic union.

ignore_exceptions class-attribute instance-attribute

ignore_exceptions: tuple[
    ImportString[type[Exception]], ...
] = ()

Exceptions ignored by the breaker.

Errors of these types do not count toward error_threshold. Accepts a single exception class, a tuple, or fully-qualified import strings such as "builtins.ValueError" or "my_app.errors.PaymentError" for YAML and env loading.

Env vars accept comma-separated values or JSON arrays.

error_threshold class-attribute instance-attribute

error_threshold: PositiveInt = 5

Consecutive errors before the breaker opens.

success_threshold class-attribute instance-attribute

success_threshold: PositiveInt = 2

Consecutive successes in HALF_OPEN state before the breaker closes.

reset_timeout class-attribute instance-attribute

reset_timeout: PositiveFloat = 30.0

Seconds the breaker stays OPEN before transitioning to HALF_OPEN.

half_open_capacity class-attribute instance-attribute

half_open_capacity: PositiveInt = 1

Maximum concurrent calls allowed in the HALF_OPEN state.

log_level class-attribute instance-attribute

log_level: LogLevel = 'WARNING'

Logging level for state-change messages.

ConstantBackoff

Bases: BaseModel

Constant delay between retries.

Use this for polling-style retries where you wait a fixed interval. For network and HTTP calls, prefer ExponentialBackoff to avoid synchronized retry storms.

Example:

from grelmicro.resilience import ConstantBackoff, Retry

policy = Retry(
    "wait_job",
    ConstantBackoff(delay=1.0),
    when=NotReady,
    attempts=20,
)

Read more in the Retry docs.

kind class-attribute instance-attribute

kind: Literal['constant'] = 'constant'

Discriminator for the backoff Pydantic union.

delay class-attribute instance-attribute

delay: PositiveFloat = 1.0

Fixed delay in seconds between retries.

ErrorDetails dataclass

ErrorDetails(time: datetime, type: str, msg: str)

Details about an error recorded by the circuit breaker.

time instance-attribute

time: datetime

type instance-attribute

type: str

msg instance-attribute

msg: str

ExponentialBackoff

Bases: BaseModel

Exponential backoff with optional jitter.

The raw delay before retry N is min(base_delay * 2 ** (N - 1), max_delay): it doubles each attempt until it reaches the cap. jitter then transforms that raw delay so concurrent callers do not retry in lockstep (the actual sleep may be smaller than the raw value).

Example:

from grelmicro.resilience import ExponentialBackoff, Retry

policy = Retry(
    "payments",
    ExponentialBackoff(base_delay=0.2, max_delay=10.0),
    when=httpx.HTTPError,
)

Read more in the Retry docs.

kind class-attribute instance-attribute

kind: Literal['exponential'] = 'exponential'

Discriminator for the backoff Pydantic union.

base_delay class-attribute instance-attribute

base_delay: PositiveFloat = 0.1

Initial delay in seconds before the first retry.

max_delay class-attribute instance-attribute

max_delay: PositiveFloat = 30.0

Maximum delay in seconds. Caps the exponential growth.

jitter class-attribute instance-attribute

jitter: Literal["none", "full", "equal", "decorrelated"] = (
    "full"
)

Jitter mode. full (default) samples from [0, raw] and is the safest choice against retry storms. equal samples from [raw/2, raw] and keeps timing more predictable. decorrelated chains samples across attempts and is best for many clients hitting the same recovering dependency. none disables jitter.

Fallback

Fallback(
    name: str,
    *,
    when: WhenInput | None = None,
    default: Any = _UNSET,
    factory: Callable[[BaseException], Any] | None = None,
    config: FallbackConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[FallbackConfig]

Fallback policy.

A named, reusable fallback policy with three-paths configuration and live reconfiguration. Use the constructor for the common case and Fallback.from_config when configuration is assembled elsewhere.

Read more in the Fallback docs.

Initialize the fallback policy.

PARAMETER DESCRIPTION
name

The name of the fallback policy. Used as the env namespace and exposed via the name property.

TYPE: str

when

Exception filter that engages the fallback. Pass a Match or a shorthand (class, tuple of classes, callable). Required unless config= is given or the value comes from env.

TYPE: WhenInput | None DEFAULT: None

default

Static fallback value. Mutually exclusive with factory. None is a valid value.

TYPE: Any DEFAULT: _UNSET

factory

Callable that produces the fallback value from the matched exception. Mutually exclusive with default.

TYPE: Callable[[BaseException], Any] | None DEFAULT: None

config

A pre-built FallbackConfig. Mutually exclusive with the per-field kwargs.

TYPE: FallbackConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property

name: str

Return the fallback policy identity.

from_config classmethod

from_config(name: str, config: FallbackConfig) -> Self

Construct a Fallback from a name and a pre-built FallbackConfig.

PARAMETER DESCRIPTION
name

The name of the fallback policy.

TYPE: str

config

The pre-built fallback configuration.

TYPE: FallbackConfig

FallbackConfig

Bases: BaseModel

Fallback policy configuration.

Holds the exception filter plus exactly one of default or factory. Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Fallback docs.

when instance-attribute

when: Match

Exception filter that engages the fallback. Pass a Match or a shorthand: an exception class, a tuple of classes, or a predicate on the exception. BaseException subclasses outside Exception are never caught.

default class-attribute instance-attribute

default: Any = _UNSET

Static value returned when when matches. Mutually exclusive with factory. Exactly one must be set.

factory class-attribute instance-attribute

factory: Callable[[BaseException], Any] | None = None

Callable that produces the fallback value from the exception. Mutually exclusive with default.

model_config class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True}

FallbackResult

FallbackResult()

Holder for the value produced inside a falling_back block.

Call set(value) on success. When the block raises an exception matching when=, the exception is suppressed and the holder is filled with the configured default (or the factory output). Access the resulting value with the value property after the block exits.

Initialize an empty result holder.

value property

value: T

Return the recorded value (success or fallback).

RAISES DESCRIPTION
RuntimeError

When accessed before any value was set.

set

set(value: T) -> None

Record the success value for the block.

FibonacciBackoff

Bases: BaseModel

Fibonacci backoff: delays follow the Fibonacci sequence scaled by base_delay.

The delay before retry N is min(base_delay * fib(N), max_delay), where fib(1) = 1, fib(2) = 1, fib(3) = 2, fib(4) = 3, ...

Sits between linear and exponential. Slower than exponential but eventually outpaces linear. Used historically in TCP congestion control and in retry strategies generally.

For most retries, prefer ExponentialBackoff. Reach for Fibonacci when exponential's growth is too aggressive and linear's is too slow.

Example:

from grelmicro.resilience import FibonacciBackoff, Retry

# 1s, 1s, 2s, 3s, 5s, 8s, ...
policy = Retry(
    "deferred",
    FibonacciBackoff(base_delay=1.0, max_delay=60.0),
    when=ServiceError,
    attempts=8,
)

Read more in the Retry docs.

kind class-attribute instance-attribute

kind: Literal['fibonacci'] = 'fibonacci'

Discriminator for the backoff Pydantic union.

base_delay class-attribute instance-attribute

base_delay: PositiveFloat = 1.0

Multiplier in seconds applied to each Fibonacci term.

max_delay class-attribute instance-attribute

max_delay: PositiveFloat = 30.0

Maximum delay in seconds. Caps the Fibonacci growth.

LinearBackoff

Bases: BaseModel

Linear backoff: delay grows by base_delay each attempt.

The delay before retry N is min(base_delay * N, max_delay). Use this for predictable progression when you have a rough idea of the recovery time and want a smooth ramp without exponential blow-up. Common for polling that escalates over time.

For network and HTTP calls, prefer ExponentialBackoff to avoid synchronized retry storms.

Example:

from grelmicro.resilience import LinearBackoff, Retry

# 1s, 2s, 3s, 4s, ...
policy = Retry(
    "ramp",
    LinearBackoff(base_delay=1.0, max_delay=10.0),
    when=ServiceError,
    attempts=5,
)

Read more in the Retry docs.

kind class-attribute instance-attribute

kind: Literal['linear'] = 'linear'

Discriminator for the backoff Pydantic union.

base_delay class-attribute instance-attribute

base_delay: PositiveFloat = 1.0

Increment in seconds added per attempt.

max_delay class-attribute instance-attribute

max_delay: PositiveFloat = 30.0

Maximum delay in seconds. Caps the linear growth.

Match

Match(matcher: Matcher, repr_: str)

Outcome filter that resilience strategies consume.

Build instances through the classmethods, never the constructor. Compose with the | and & operators. Each primitive matcher has a symmetric not_* twin for the negated form.

Read more in the Retry filtering docs.

explain

explain() -> str

Return the human-readable matcher tree for debugging.

exception classmethod

exception(
    *exception_types_or_predicate: type[Exception]
    | Callable[[Exception], bool],
) -> Match

Engage when the call raised a matching exception.

Pass one or more exception classes, or a single callable predicate (Exception) -> bool. When mixed forms are passed (some classes, some callables), the result raises TypeError at construction.

result classmethod

result(
    value_or_predicate: Any | Callable[[Any], bool],
) -> Match

Engage when the call returned a matching value.

Pass a literal value (compared with ==) or a callable predicate (result) -> bool. Functions are always treated as predicates: to match a function literal, wrap it in a predicate (lambda r: r is my_fn).

exception_message classmethod

exception_message(
    *,
    contains: str | None = None,
    regex: str | Pattern[str] | None = None,
) -> Match

Engage when the exception's message matches the predicate.

Pass exactly one of contains= (substring) or regex= (compiled or string regex).

exception_cause classmethod

exception_cause(
    *exception_types_or_predicate: type[Exception]
    | Callable[[BaseException | None], bool],
) -> Match

Engage when the exception's __cause__ matches.

Same shorthand as Match.exception: one or more classes, or a single callable predicate on exc.__cause__.

always classmethod

always() -> Match

Engage on every outcome.

Useful as the explicit "always retry" policy. Note: BaseException subclasses outside Exception are still never retried by the strategy itself, regardless of the matcher.

never classmethod

never() -> Match

Engage on no outcome. Effectively disables the strategy.

predicate classmethod

predicate(fn: Callable[[Outcome[Any]], bool]) -> Match

Engage when the predicate returns true for the outcome.

Use this when the filter must observe both the exception and the result together. Most call sites should reach for Match.exception or Match.result instead.

not_exception classmethod

not_exception(
    *exception_types_or_predicate: type[Exception]
    | Callable[[Exception], bool],
) -> Match

Engage when the call raised an exception that does NOT match.

Scoped to raised outcomes: returns False for any returned outcome. Same arguments as Match.exception.

not_result classmethod

not_result(
    value_or_predicate: Any | Callable[[Any], bool],
) -> Match

Engage when the call returned a value that does NOT match.

Scoped to returned outcomes: returns False for any raised outcome. Same argument as Match.result.

not_exception_message classmethod

not_exception_message(
    *,
    contains: str | None = None,
    regex: str | Pattern[str] | None = None,
) -> Match

Engage when the exception's message does NOT match.

Scoped to raised outcomes: returns False for any returned outcome.

not_exception_cause classmethod

not_exception_cause(
    *exception_types_or_predicate: type[Exception]
    | Callable[[BaseException | None], bool],
) -> Match

Engage when the exception's __cause__ does NOT match.

Scoped to raised outcomes: returns False for any returned outcome.

MemoryCircuitBreakerAdapter

MemoryCircuitBreakerAdapter()

Bases: CircuitBreakerBackend

In-memory circuit breaker adapter.

State for every breaker bound to this adapter is held in process, keyed by breaker name. Closing the adapter clears every breaker's state so the next start begins on a clean slate.

Use it for tests and single-process deployments. Use RedisCircuitBreakerAdapter for fleet-wide shared state.

Initialize the circuit breaker adapter.

is_shared class-attribute

is_shared: bool = False

bind

bind(
    *, name: str, config: ConsecutiveCountConfig
) -> CircuitBreakerStrategy

Build a strategy bound to this adapter's per-name state.

Two breakers constructed with the same name against the same adapter share the same _BreakerState entry, mirroring the Redis adapter's per-name keying.

MemoryRateLimiterAdapter

MemoryRateLimiterAdapter()

Bases: RateLimiterBackend

In-memory rate limiter adapter.

Supports both TokenBucketConfig and SlidingWindowConfig algorithm configs. State is held in separate per-algorithm maps so two rate limiters with the same name but different algorithms cannot collide. Thread-safe.

Use it for tests and single-process deployments. For distributed coordination, use RedisRateLimiterAdapter.

Example:

from grelmicro.resilience import RateLimiterRegistry, RateLimiter
from grelmicro.resilience.ratelimiter.memory import MemoryRateLimiterAdapter

micro = Grelmicro(uses=[RateLimiterRegistry(MemoryRateLimiterAdapter())])
rl = RateLimiter.token_bucket("api", capacity=10, refill_rate=1)

Read more in the Rate Limiter docs.

Initialize the rate limiter adapter.

bind

Build a strategy for the given algorithm config.

Called once by RateLimiter when the rate limiter is created. This is the only place that picks which algorithm to run. Later calls to acquire, peek, and reset use the returned strategy directly.

MemoryTokenBucket

MemoryTokenBucket(*, capacity: int, refill_rate: float)

Standalone in-memory token bucket.

Public, synchronous, thread-safe, and keyed. Use this class directly when you need fast, in-process, burst-friendly rate limiting in synchronous code. A typical use is inside a logging.Filter.

For async workflows, distributed coordination, or alternative algorithms, use RateLimiter with a backend instead.

Example:

from grelmicro.resilience.ratelimiter.memory import MemoryTokenBucket

bucket = MemoryTokenBucket(capacity=5, refill_rate=1)


def handle(key: str) -> bool:
    return bucket.try_acquire(key=key)

Read more in the Rate Limiter docs.

Initialize the token bucket.

PARAMETER DESCRIPTION
capacity

Maximum burst size. The bucket never holds more than capacity tokens.

TYPE: int

refill_rate

Tokens replenished per second, up to capacity.

TYPE: float

capacity property

capacity: int

Configured bucket capacity.

refill_rate property

refill_rate: float

Configured refill rate (tokens per second).

try_acquire

try_acquire(key: str = '', *, cost: float = 1.0) -> bool

Try to consume cost tokens for key.

Returns True and deducts the cost when the bucket has enough tokens, otherwise False (nothing deducted).

PARAMETER DESCRIPTION
key

Identifier of the bucket (e.g. logger name, user id).

TYPE: str DEFAULT: ''

cost

Tokens to consume. Must be > 0 and <= capacity.

TYPE: float DEFAULT: 1.0

peek

peek(key: str = '') -> float

Return the current token count without consuming any.

PARAMETER DESCRIPTION
key

Identifier of the bucket.

TYPE: str DEFAULT: ''

reset

reset(key: str = '') -> None

Delete state for key, restoring full capacity.

PARAMETER DESCRIPTION
key

Identifier of the bucket to reset.

TYPE: str DEFAULT: ''

Outcome dataclass

Outcome(
    exception: Exception | None,
    result: T | None,
    raised: bool,
)

Result of a protected call: an exception or a return value.

Exactly one of exception and result is meaningful per instance, signalled by raised. The T type parameter is the function's return type.

Read more in the Retry filtering docs.

exception instance-attribute

exception: Exception | None

The exception raised by the call, or None when it returned.

result instance-attribute

result: T | None

The value returned by the call, or None when it raised.

raised instance-attribute

raised: bool

True when the call raised, False when it returned.

from_exception classmethod

from_exception(exception: Exception) -> Outcome[T]

Build an Outcome for a raised call.

from_result classmethod

from_result(result: T) -> Outcome[T]

Build an Outcome for a returned call.

PostgresCircuitBreakerAdapter

PostgresCircuitBreakerAdapter(
    *,
    provider: PostgresProvider | None = None,
    env_prefix: str = "POSTGRES_",
    prefix: str = "",
    table_name: str = "grelmicro_circuit_breaker",
    auto_migrate: bool = True,
)

Bases: CircuitBreakerBackend

Postgres circuit breaker adapter.

Builds a per-breaker CircuitBreakerStrategy that stores state in a row of {table_name} keyed by breaker name. Every admission and counter update runs inside a PL/pgSQL function that holds pg_advisory_xact_lock for the breaker, so concurrent replicas converge to the same state without coordination locks.

Today the consecutive-count algorithm is the only strategy. Future algorithm configs plug in through the same bind entry point.

last_error and last_error_time stay per-replica.

Example:

from grelmicro import Grelmicro
from grelmicro.providers.postgres import PostgresProvider
from grelmicro.resilience import CircuitBreakerRegistry, CircuitBreaker
from grelmicro.resilience.circuitbreaker.postgres import (
    PostgresCircuitBreakerAdapter,
)

postgres = PostgresProvider("postgresql://localhost:5432/app")
micro = Grelmicro(
    uses=[
        postgres,
        CircuitBreakerRegistry(PostgresCircuitBreakerAdapter(provider=postgres)),
    ]
)
payments = CircuitBreaker("payments")

Read more in the Circuit Breaker docs.

Initialize the circuit breaker adapter.

PARAMETER DESCRIPTION
provider

A pre-built PostgresProvider. When set, the adapter borrows the provider's pool and does not manage its lifecycle.

TYPE: PostgresProvider | None DEFAULT: None

env_prefix

Environment variable prefix used by the implicit PostgresProvider when provider is not set. Defaults to POSTGRES_. Use a custom prefix to split pools.

TYPE: str DEFAULT: 'POSTGRES_'

prefix

Prefix prepended to every breaker name the adapter writes. Use it to avoid collisions with other consumers of the same Postgres table.

TYPE: str DEFAULT: ''

table_name

Table that stores circuit-breaker state. Auto-created on first connect (set auto_migrate=False to opt out).

TYPE: str DEFAULT: 'grelmicro_circuit_breaker'

auto_migrate

When True (the default), the adapter creates the table and SQL functions on __aenter__. Set to False when the schema is managed by your own migration tool.

TYPE: bool DEFAULT: True

is_shared class-attribute

is_shared: bool = True

provider property

provider: PostgresProvider

The bound PostgresProvider.

bind

bind(
    *, name: str, config: ConsecutiveCountConfig
) -> CircuitBreakerStrategy

Build a strategy for the named breaker and config.

Dispatches on the config.kind discriminator. Today only consecutive_count is supported.

PostgresRateLimiterAdapter

PostgresRateLimiterAdapter(
    *,
    provider: PostgresProvider | None = None,
    env_prefix: str = "POSTGRES_",
    prefix: str = "",
    table_name: str = "grelmicro_rate_limiter",
    auto_migrate: bool = True,
)

Bases: RateLimiterBackend

Postgres rate limiter adapter.

Wraps a PostgresProvider and supports both TokenBucketConfig and SlidingWindowConfig algorithm configs via PL/pgSQL functions. Concurrent writes for the same key are serialized with pg_advisory_xact_lock. Safe across processes and machines.

Example:

from grelmicro.providers.postgres import PostgresProvider
from grelmicro.resilience import RateLimiter
from grelmicro.resilience.ratelimiter.postgres import (
    PostgresRateLimiterAdapter,
)


async def main() -> None:
    provider = PostgresProvider("postgresql://localhost:5432/app")
    async with provider, PostgresRateLimiterAdapter(provider=provider):
        rl = RateLimiter.token_bucket("api", capacity=10, refill_rate=1)
        await rl.acquire(key="u1")

Read more in the Rate Limiter docs.

Initialize the rate limiter adapter.

PARAMETER DESCRIPTION
provider

A pre-built PostgresProvider. When set, the adapter borrows the provider's pool and does not manage its lifecycle.

TYPE: PostgresProvider | None DEFAULT: None

env_prefix

Environment variable prefix used by the implicit PostgresProvider when provider is not set. Defaults to POSTGRES_. Use a custom prefix to split pools.

TYPE: str DEFAULT: 'POSTGRES_'

prefix

Prefix prepended to every key the adapter writes. Use it to avoid collisions with other consumers of the same Postgres table.

TYPE: str DEFAULT: ''

table_name

Table that stores rate-limit state. Auto-created on first connect (set auto_migrate=False to opt out).

TYPE: str DEFAULT: 'grelmicro_rate_limiter'

auto_migrate

When True (the default), the adapter creates the table and SQL functions on __aenter__. Set to False when the schema is managed by your own migration tool.

TYPE: bool DEFAULT: True

provider property

provider: PostgresProvider

The bound PostgresProvider.

bind

Build a strategy for the given algorithm config.

Each strategy targets a pair of PL/pgSQL functions installed on __aenter__. Functions read and write a single row of {table_name} per key.

RandomBackoff

Bases: BaseModel

Random backoff: each delay is uniform random in [min_delay, max_delay].

Use this when you want bounded random spread without progressive growth. Common for cache-stampede protection (many clients miss the cache simultaneously: each waits a random short interval to avoid hammering the origin together).

For HTTP retries, prefer ExponentialBackoff with jitter. Random alone does not back off, so a persistent failure retries at the same average rate forever.

Example:

from grelmicro.resilience import RandomBackoff, Retry

# Each retry waits a random 0.5-2.0 seconds
policy = Retry(
    "stampede",
    RandomBackoff(min_delay=0.5, max_delay=2.0),
    when=CacheMissError,
    attempts=3,
)

Read more in the Retry docs.

kind class-attribute instance-attribute

kind: Literal['random'] = 'random'

Discriminator for the backoff Pydantic union.

min_delay class-attribute instance-attribute

min_delay: PositiveFloat = 0.5

Minimum delay in seconds (inclusive).

max_delay class-attribute instance-attribute

max_delay: PositiveFloat = 2.0

Maximum delay in seconds (inclusive).

RateLimiterRegistry

RateLimiterRegistry(
    source: Provider
    | RateLimiterBackend
    | type[Provider | RateLimiterBackend],
    *,
    name: str = "default",
)

RateLimiterBackend wrapper exposing (ratelimiter, name) registration.

Registered on a Grelmicro app via Grelmicro(uses=[RateLimiterRegistry(redis)]). The active app resolves RateLimiter patterns to this Component's backend on every call.

Accepts a Provider or a RateLimiterBackend. When given a Provider, the component calls provider.ratelimiter() to build the matching adapter.

Example
from grelmicro import Grelmicro
from grelmicro.providers.redis import RedisProvider
from grelmicro.resilience import RateLimiter, RateLimiterRegistry

redis = RedisProvider("redis://localhost:6379/0")
micro = Grelmicro(uses=[redis, RateLimiterRegistry(redis)])
api = RateLimiter.token_bucket("api", capacity=10, refill_rate=1)

async with micro:
    await api.acquire(key="user-1")

Initialize the Component with the wrapped backend.

PARAMETER DESCRIPTION
source

A Provider (e.g. RedisProvider) or a RateLimiterBackend instance. When a Provider is given, the component calls provider.ratelimiter() to build the matching adapter.

TYPE: Provider | RateLimiterBackend | type[Provider | RateLimiterBackend]

name

Registration name. Multiple RateLimiterRegistry Components may coexist on one Grelmicro under different names.

TYPE: str DEFAULT: 'default'

kind class-attribute

kind: str = 'ratelimiter'

name property

name: str

Return the registration name.

backend property

The underlying RateLimiterBackend.

RateLimiter

RateLimiter(
    name: str,
    config: RateLimiterConfig,
    *,
    backend: RateLimiterBackend | str | None = None,
)

Bases: Reconfigurable['RateLimiterConfig']

Rate limiter with a pluggable algorithm.

Most Python call sites should use the factory classmethods: RateLimiter.token_bucket for burst-friendly semantics or RateLimiter.sliding_window for precise sliding-window semantics.

Construct it directly with the instance name and a discriminated algorithm configuration when a config object already exists: TokenBucketConfig for burst-friendly semantics, or SlidingWindowConfig for precise sliding-window semantics.

The algorithm is bound to the backend once at construction via RateLimiterBackend.bind. Each call to acquire, peek, or reset then runs the bound strategy directly. There is no extra algorithm lookup on each call.

Read more in the Rate Limiter docs.

Initialize the rate limiter.

PARAMETER DESCRIPTION
name

The name of the rate limiter instance.

Acts as the instance identity. Used as the key prefix on the backend and exposed via the name property.

TYPE: str

config

The algorithm configuration.

Most callers should prefer the RateLimiter.token_bucket or RateLimiter.sliding_window factory classmethods. Pass a config directly when it is already assembled elsewhere, for example from YAML or a pydantic-settings tree.

Pass a TokenBucketConfig or a SlidingWindowConfig. Both carry algorithm parameters plus the shared fail_open setting. The classes share a discriminated kind field so serialization round-trips and pydantic-settings composition both work.

TYPE: RateLimiterConfig

backend

An explicit backend instance. When None (the default), the registered backend is used.

Set this to skip the global registry, for example in tests or when running several backends at the same time.

TYPE: RateLimiterBackend | str | None DEFAULT: None

name property

name: str

Return the rate limiter identity.

backend property

Bound rate-limiter backend, resolved on each call.

Resolution order: 1. An explicit backend= passed at construction wins. 2. The active Grelmicro app is consulted via Grelmicro.current() so that micro.override(...) blocks take effect.

RAISES DESCRIPTION
OutOfContextError

No backend resolved in this scope. Pass backend= (a MemoryRateLimiterAdapter() for a per-process limiter), register a RateLimiterRegistry Component, or run the call inside async with micro: or after micro.install(app).

from_config classmethod

from_config(
    name: str,
    config: RateLimiterConfig,
    *,
    backend: RateLimiterBackend | str | None = None,
) -> Self

Construct a RateLimiter from a name and a pre-built config.

Use this when configuration is assembled declaratively at startup and the simple factory classmethods are not the right fit. This declarative path opts out of live reload: the instance is not addressable by ExternalConfig and stays on the config it was built with.

PARAMETER DESCRIPTION
name

The name of the rate limiter instance.

TYPE: str

config

The pre-built algorithm configuration.

TYPE: RateLimiterConfig

backend

An explicit backend instance. When None (the default), the registered backend is used.

TYPE: RateLimiterBackend | str | None DEFAULT: None

token_bucket classmethod

token_bucket(
    name: str,
    *,
    capacity: PositiveInt,
    refill_rate: PositiveFloat,
    fail_open: bool = False,
    backend: RateLimiterBackend | str | None = None,
) -> Self

Construct a token-bucket rate limiter.

Convenience factory for the common case. Builds a TokenBucketConfig internally and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the rate limiter instance.

TYPE: str

capacity

Maximum burst size. The bucket holds at most capacity tokens.

TYPE: PositiveInt

refill_rate

Tokens replenished per second, up to capacity.

TYPE: PositiveFloat

fail_open

When True, the rate limiter returns an allowed result if the backend raises an error.

TYPE: bool DEFAULT: False

backend

An explicit backend instance. When None (the default), the registered backend is used.

TYPE: RateLimiterBackend | str | None DEFAULT: None

sliding_window classmethod

sliding_window(
    name: str,
    *,
    limit: PositiveInt,
    window: PositiveFloat,
    fail_open: bool = False,
    backend: RateLimiterBackend | str | None = None,
) -> Self

Construct a sliding-window rate limiter.

Convenience factory for the common case. Builds a SlidingWindowConfig internally and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the rate limiter instance.

TYPE: str

limit

Maximum number of requests allowed per window.

TYPE: PositiveInt

window

Window duration in seconds.

TYPE: PositiveFloat

fail_open

When True, the rate limiter returns an allowed result if the backend raises an error.

TYPE: bool DEFAULT: False

backend

An explicit backend instance. When None (the default), the registered backend is used.

TYPE: RateLimiterBackend | str | None DEFAULT: None

acquire async

acquire(
    *, key: str = "default", cost: int = 1
) -> RateLimitResult

Check rate limit and consume tokens if allowed.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

cost

Number of tokens to consume.

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
RateLimitResult

RateLimitResult with allowed, limit, remaining,

RateLimitResult

retry_after, and reset_after fields.

RAISES DESCRIPTION
ValueError

If cost is not between 1 and the algorithm's limit/capacity.

acquire_or_raise async

acquire_or_raise(
    *, key: str = "default", cost: int = 1
) -> RateLimitResult

Check rate limit, raise if exceeded.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

cost

Number of tokens to consume.

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
RateLimitResult

RateLimitResult if allowed.

RAISES DESCRIPTION
RateLimitExceededError

If the rate limit is exceeded.

allow async

allow(*, key: str = 'default', cost: int = 1) -> bool

Consume tokens and return whether the request is within the limit.

The boolean shortcut over acquire, for the common branch:

if await limiter.allow(key="user-1"):
    ...  # served
else:
    ...  # throttled

Use acquire instead when you need the retry_after or remaining metadata on the deny branch.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

cost

Number of tokens to consume.

TYPE: int DEFAULT: 1

peek async

peek(*, key: str = 'default') -> RateLimitResult

Check rate limit state without consuming tokens.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

RETURNS DESCRIPTION
RateLimitResult

RateLimitResult reflecting the current state.

RateLimitResult

allowed indicates whether the next acquire would

RateLimitResult

succeed.

reset async

reset(*, key: str = 'default') -> None

Delete rate limit state for a key, restoring full quota.

Idempotent: resetting a nonexistent key is a no-op.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

wait async

wait(
    *,
    key: str = "default",
    cost: int = 1,
    max_wait: float | None = None,
) -> RateLimitResult

Wait until tokens are available, then consume them.

Polls acquire on the clock seam, sleeping retry_after between attempts, until the request is admitted. A denied acquire consumes nothing, so retrying is safe.

With max_wait set, gives up once the budget would be exceeded and raises RateLimitExceededError. The default waits forever:

await limiter.wait(key="user-1")
result = await limiter.wait(key="user-1", cost=3, max_wait=2.0)

The wait runs on the clock seam, so VirtualClock drives it in tests without real sleeping.

PARAMETER DESCRIPTION
key

Identifier for rate limiting (e.g. IP address, user ID, session). Defaults to default for the single-bucket case. The limiter's name already namespaces the backend key, so the default bucket is name:default.

TYPE: str DEFAULT: 'default'

cost

Number of tokens to consume.

TYPE: int DEFAULT: 1

max_wait

Maximum number of seconds to wait before giving up. None (the default) waits indefinitely.

TYPE: float | None DEFAULT: None

RETURNS DESCRIPTION
RateLimitResult

The allowed RateLimitResult once tokens are consumed.

RAISES DESCRIPTION
ValueError

If cost is not between 1 and the algorithm's limit/capacity. Guards the otherwise unsatisfiable wait when cost exceeds capacity.

RateLimitExceededError

If max_wait elapses before the request is admitted.

RateLimiterBackend

Bases: Protocol

Protocol for rate-limiter storage backends.

A backend holds the storage for every rate limiter that uses it. It turns an algorithm into a strategy through bind. The returned RateLimiterStrategy is what a RateLimiter calls on each acquire, peek, or reset. No extra algorithm lookup happens at call time.

bind

Build a strategy for the given algorithm config.

Called exactly once per RateLimiter when it is created. The returned strategy shares storage with the backend. Later requests call the strategy methods directly, with no extra algorithm lookup.

PARAMETER DESCRIPTION
config

Algorithm configuration. TokenBucketConfig or SlidingWindowConfig.

TYPE: RateLimiterConfig

RateLimiterStrategy

Bases: Protocol

A rate-limiter strategy for a specific algorithm and backend.

Returned by RateLimiterBackend.bind. The algorithm settings are already stored in the strategy, so the methods only need key and cost. No extra algorithm lookup happens at call time.

acquire async

acquire(*, key: str, cost: int) -> RateLimitResult

Try to acquire rate-limit tokens for key.

Returns a RateLimitResult with allowed, limit, remaining, retry_after, and reset_after.

PARAMETER DESCRIPTION
key

Rate-limit key (e.g. IP, user ID, session).

TYPE: str

cost

Number of tokens to consume on this request.

TYPE: int

peek async

peek(*, key: str) -> RateLimitResult

Return the current state for key without consuming tokens.

PARAMETER DESCRIPTION
key

Rate-limit key to inspect.

TYPE: str

reset async

reset(*, key: str) -> None

Delete rate-limit state for key, restoring full quota.

PARAMETER DESCRIPTION
key

Rate-limit key to reset to full quota.

TYPE: str

RateLimitExceededError

RateLimitExceededError(*, key: str, retry_after: float)

Bases: ResilienceError, AdmissionError

Rate limit exceeded error.

Raised when a rate limit check fails (too many requests).

Initialize the error.

key instance-attribute

key = key

retry_after instance-attribute

retry_after = retry_after

RateLimitResult

Bases: NamedTuple

Result of a rate limit check.

Fields map to HTTP rate limit headers: - allowed -> 200 vs 429 status - limit -> X-RateLimit-Limit / RateLimit-Policy: ;q= - remaining -> X-RateLimit-Remaining / RateLimit: ;r= - retry_after -> Retry-After header - reset_after -> X-RateLimit-Reset / RateLimit: ;t=

allowed instance-attribute

allowed: bool

Whether the request is permitted.

limit instance-attribute

limit: int

Total quota (capacity for TokenBucketConfig, limit for SlidingWindowConfig).

remaining instance-attribute

remaining: int

Remaining tokens or requests.

For algorithms with continuous state (SlidingWindowConfig, GCRA-based strategies) this is an estimate rounded to the nearest whole request. Enforcement still uses the exact internal state, so the next acquire may be denied even when remaining > 0.

retry_after instance-attribute

retry_after: float

Seconds until the next request is allowed (0.0 if allowed).

reset_after instance-attribute

reset_after: float

Seconds until the full quota resets.

RedisCircuitBreakerAdapter

RedisCircuitBreakerAdapter(
    *,
    provider: RedisProvider | None = None,
    env_prefix: str = "REDIS_",
    prefix: str = "",
)

Bases: CircuitBreakerBackend

Redis circuit breaker adapter.

Builds a per-breaker CircuitBreakerStrategy that stores state in a Redis hash keyed {prefix}cb:{name}. All admission and counter updates run as atomic Lua scripts so concurrent replicas converge to the same state without coordination locks.

Today the consecutive-count algorithm is the only strategy. Future algorithm configs plug in through the same bind entry point.

last_error and last_error_time stay per-replica.

Example:

from grelmicro import Grelmicro
from grelmicro.providers.redis import RedisProvider
from grelmicro.resilience import CircuitBreakerRegistry, CircuitBreaker

redis = RedisProvider("redis://localhost:6379/0")
micro = Grelmicro(uses=[redis, CircuitBreakerRegistry(redis)])
payments = CircuitBreaker("payments")

Read more in the Circuit Breaker docs.

Initialize the circuit breaker adapter.

PARAMETER DESCRIPTION
provider

A pre-built RedisProvider. When set, the adapter borrows the provider's client and does not manage its lifecycle.

TYPE: RedisProvider | None DEFAULT: None

env_prefix

Environment variable prefix used by the implicit RedisProvider when provider is not set. Defaults to REDIS_.

TYPE: str DEFAULT: 'REDIS_'

prefix

Prefix prepended to every Redis key the adapter writes. Use it to avoid collisions with other consumers of the same Redis database.

TYPE: str DEFAULT: ''

is_shared class-attribute

is_shared: bool = True

provider property

provider: RedisProvider

The bound RedisProvider.

bind

bind(
    *, name: str, config: ConsecutiveCountConfig
) -> CircuitBreakerStrategy

Build a strategy for the named breaker and config.

Dispatches on the config.kind discriminator. Today only consecutive_count is supported.

RedisRateLimiterAdapter

RedisRateLimiterAdapter(
    *,
    provider: RedisProvider | None = None,
    env_prefix: str = "REDIS_",
    prefix: str = "",
)

Bases: RateLimiterBackend

Redis rate limiter adapter.

Wraps a RedisProvider and supports both TokenBucketConfig and SlidingWindowConfig algorithm configs via atomic Lua scripts. Safe across processes and machines.

Example:

from grelmicro.providers.redis import RedisProvider
from grelmicro.resilience import RateLimiter
from grelmicro.resilience.ratelimiter.redis import RedisRateLimiterAdapter


async def main() -> None:
    provider = RedisProvider("redis://localhost:6379/0")
    async with RedisRateLimiterAdapter(provider=provider):
        rl = RateLimiter.token_bucket("api", capacity=10, refill_rate=1)
        await rl.acquire(key="u1")

Read more in the Rate Limiter docs.

Initialize the rate limiter adapter.

PARAMETER DESCRIPTION
provider

A pre-built RedisProvider. When set, the adapter borrows the provider's client and does not manage its lifecycle.

TYPE: RedisProvider | None DEFAULT: None

env_prefix

Environment variable prefix used by the implicit RedisProvider when provider is not set. Defaults to REDIS_. Use a custom prefix to split pools.

TYPE: str DEFAULT: 'REDIS_'

prefix

Prefix prepended to every Redis key the adapter writes. Use it to avoid collisions with other consumers of the same Redis database.

TYPE: str DEFAULT: ''

provider property

provider: RedisProvider

The bound RedisProvider.

bind

Build a strategy for the given algorithm config.

Each strategy has its own Lua scripts. It registers them with the Redis client when the strategy is created.

SQLiteRateLimiterAdapter

SQLiteRateLimiterAdapter(
    *,
    provider: SQLiteProvider | None = None,
    env_prefix: str = "SQLITE_",
    prefix: str = "",
    table_name: str = "grelmicro_rate_limiter",
    auto_migrate: bool = True,
)

Bases: RateLimiterBackend

SQLite rate limiter adapter.

Internal machinery. Most code should reach SQLite rate limiting through a SQLiteProvider and RateLimiterRegistry(provider), not by constructing this adapter directly. The adapter exists for expert wiring and for the provider to build.

Borrows the connection and a shared lock from a SQLiteProvider and supports both TokenBucketConfig and SlidingWindowConfig algorithm configs. Each acquire runs a read-modify-write inside a BEGIN IMMEDIATE transaction. The provider's lock serializes the single connection within the process, and the transaction's write lock serializes across processes sharing the same file. State survives process restarts. For multi-replica coordination, use RedisRateLimiterAdapter or PostgresRateLimiterAdapter.

Read more in the Rate Limiter docs.

Initialize the rate limiter adapter.

PARAMETER DESCRIPTION
provider

A pre-built SQLiteProvider. When set, the adapter borrows the provider's connection and does not manage its lifecycle.

TYPE: SQLiteProvider | None DEFAULT: None

env_prefix

Environment variable prefix used by the implicit SQLiteProvider when provider is not set. Resolves the path from SQLITE_PATH by default.

TYPE: str DEFAULT: 'SQLITE_'

prefix

Prefix prepended to every key the adapter writes. Use it to avoid collisions with other consumers of the same SQLite table.

TYPE: str DEFAULT: ''

table_name

Table that stores rate-limit state. Auto-created on first connect (set auto_migrate=False to opt out).

TYPE: str DEFAULT: 'grelmicro_rate_limiter'

auto_migrate

When True (the default), the adapter creates the table on __aenter__. Set to False when the schema is managed by your own migration tool.

TYPE: bool DEFAULT: True

provider property

provider: SQLiteProvider

The bound SQLiteProvider.

bind

Build a strategy for the given algorithm config.

ApiShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the api profile (the default).

Tuned for external HTTP APIs. Modest initial rate, generous timeouts, broad clamps. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute

kind: Literal['api'] = 'api'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute

max_consecutive_failures: int = 20

initial_max_rate class-attribute

initial_max_rate: float = 2.0

adaptive_burst_capacity class-attribute

adaptive_burst_capacity: float = 5.0

min_rate_floor class-attribute

min_rate_floor: float = 0.25

initial_timeout class-attribute

initial_timeout: float = 10.0

timeout_clamp_min class-attribute

timeout_clamp_min: float = 0.5

timeout_clamp_max class-attribute

timeout_clamp_max: float = 60.0

backoff_scale class-attribute

backoff_scale: float = 1.0

backoff_cap class-attribute

backoff_cap: float = 30.0

max_rate_cap_default class-attribute

max_rate_cap_default: float | None = None

profile_name class-attribute

profile_name: str = 'api'

InternalShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the internal profile.

Tuned for in-cluster RPC. High initial rate, short timeouts, tight budgets. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute

kind: Literal['internal'] = 'internal'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute

max_consecutive_failures: int = 10

initial_max_rate class-attribute

initial_max_rate: float = 100.0

adaptive_burst_capacity class-attribute

adaptive_burst_capacity: float = 200.0

min_rate_floor class-attribute

min_rate_floor: float = 1.0

initial_timeout class-attribute

initial_timeout: float = 1.0

timeout_clamp_min class-attribute

timeout_clamp_min: float = 0.05

timeout_clamp_max class-attribute

timeout_clamp_max: float = 5.0

backoff_scale class-attribute

backoff_scale: float = 0.5

backoff_cap class-attribute

backoff_cap: float = 5.0

max_rate_cap_default class-attribute

max_rate_cap_default: float | None = None

profile_name class-attribute

profile_name: str = 'internal'

ResilienceError

Bases: GrelmicroError

Base class for all resilience-related errors.

This class serves as the base for all errors related to resilience mechanisms such as circuit breakers, retries, etc.

ResilienceSettingsValidationError

ResilienceSettingsValidationError(
    error: ValidationError | str,
)

Bases: ResilienceError, SettingsValidationError

Resilience Settings Validation Error.

Retry

Retry(
    name: str,
    backoff: RetryBackoffConfig | None = None,
    *,
    when: WhenInput | None = None,
    attempts: PositiveInt | None = None,
    max_seconds: PositiveFloat | None = None,
    config: RetryConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[RetryConfig]

Retry policy.

A named, reusable retry policy with three-paths configuration and live reconfiguration. Use the Retry.exponential or Retry.constant factory classmethods for the common case. Pass a pre-built backoff config to the constructor when configuration is assembled elsewhere.

Read more in the Retry docs.

Initialize the retry policy.

PARAMETER DESCRIPTION
name

The name of the retry policy. Used as the env namespace and exposed via the name property.

TYPE: str

backoff

The backoff algorithm config. Pass any RetryBackoffConfig variant or omit for the default exponential + full jitter.

TYPE: RetryBackoffConfig | None DEFAULT: None

when

Outcome filter that engages the retry. Pass a Match or one of the shorthand forms (exception class, tuple, callable). Required unless config= is given.

TYPE: WhenInput | None DEFAULT: None

attempts

Total calls including the first. Default 3.

TYPE: PositiveInt | None DEFAULT: None

max_seconds

Optional wall-clock budget in seconds. Retrying stops when either attempts or this budget is reached, whichever comes first. Default no time limit.

TYPE: PositiveFloat | None DEFAULT: None

config

A pre-built RetryConfig. Mutually exclusive with the per-field kwargs.

TYPE: RetryConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property

name: str

Return the retry policy identity.

from_config classmethod

from_config(name: str, config: RetryConfig) -> Self

Construct a Retry from a name and a pre-built RetryConfig.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

config

The pre-built retry configuration.

Use this path when the configuration is assembled at startup from a settings tree. The environment path is bypassed and the config is used as-is.

TYPE: RetryConfig

exponential classmethod

exponential(
    name: str,
    *,
    when: WhenInput,
    attempts: PositiveInt = 3,
    max_seconds: PositiveFloat | None = None,
    base_delay: PositiveFloat = 0.1,
    max_delay: PositiveFloat = 30.0,
    jitter: Literal[
        "none", "full", "decorrelated"
    ] = "full",
    env_load: bool | None = None,
) -> Self

Construct a retry policy with exponential backoff.

Convenience factory for the common case. Builds an ExponentialBackoff and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

when

Outcome filter that engages the retry.

TYPE: WhenInput

attempts

Total calls including the first.

TYPE: PositiveInt DEFAULT: 3

max_seconds

Optional wall-clock budget in seconds, whichever comes first with attempts.

TYPE: PositiveFloat | None DEFAULT: None

base_delay

Initial delay in seconds before the first retry.

TYPE: PositiveFloat DEFAULT: 0.1

max_delay

Maximum delay in seconds. Caps exponential growth.

TYPE: PositiveFloat DEFAULT: 30.0

jitter

Jitter mode.

TYPE: Literal['none', 'full', 'decorrelated'] DEFAULT: 'full'

env_load

Whether to read environment variables.

TYPE: bool | None DEFAULT: None

constant classmethod

constant(
    name: str,
    *,
    when: WhenInput,
    attempts: PositiveInt = 3,
    max_seconds: PositiveFloat | None = None,
    delay: PositiveFloat = 1.0,
    env_load: bool | None = None,
) -> Self

Construct a retry policy with constant delay.

Convenience factory for polling-style retries. Builds a ConstantBackoff and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

when

Outcome filter that engages the retry.

TYPE: WhenInput

attempts

Total calls including the first.

TYPE: PositiveInt DEFAULT: 3

max_seconds

Optional wall-clock budget in seconds, whichever comes first with attempts.

TYPE: PositiveFloat | None DEFAULT: None

delay

Fixed delay in seconds between retries.

TYPE: PositiveFloat DEFAULT: 1.0

env_load

Whether to read environment variables.

TYPE: bool | None DEFAULT: None

RetryAttempt

RetryAttempt(
    *,
    number: int,
    delay_before: float,
    attempts: int,
    matcher: Matcher,
    loop: _AttemptLoop,
    started_at: float,
    max_seconds: float | None,
)

One iteration of a retry loop.

Yielded by Retry iteration and by retrying. Used as an async (or sync) context manager. Suppresses retryable exceptions until attempts are exhausted, then re-raises the underlying error with a PEP 678 note.

The block form sees only exceptions, not return values. Use the decorator form (@retry or policy(fn)) for result-based retry.

Initialize one retry attempt.

number instance-attribute

number = number

1-indexed attempt number. The first call is 1.

delay_before instance-attribute

delay_before = delay_before

Seconds slept before this attempt (0.0 for the first).

RetryConfig

Bases: BaseModel

Retry policy configuration.

Holds the top-level retry fields plus a discriminated backoff sub-config. Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Retry docs.

attempts class-attribute instance-attribute

attempts: PositiveInt = 3

Total calls including the first. attempts=1 means no retry. The default 3 allows two retries.

max_seconds class-attribute instance-attribute

max_seconds: PositiveFloat | None = None

Optional wall-clock budget in seconds, measured from the first attempt. Retrying stops as soon as either attempts is reached or this budget elapses, whichever comes first. The budget is checked between attempts, so one backoff may run slightly past it. None (default) means no time limit.

when instance-attribute

when: Match

Outcome filter that engages the retry. Pass a Match (e.g. Match.exception(httpx.HTTPError) | Match.result(None)) or a shorthand: an exception class, a tuple of classes, or a predicate on the exception. BaseException subclasses outside Exception are never retried.

backoff instance-attribute

Backoff algorithm config. Discriminated union over ExponentialBackoff, ConstantBackoff, LinearBackoff, FibonacciBackoff, and RandomBackoff. Default: exponential with full jitter.

model_config class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True}

RetryStrategy

Bases: Protocol

A retry strategy for a specific backoff algorithm.

Built once per retry loop from a backoff config. The strategy holds any state the algorithm needs (for example the previous delay for decorrelated jitter) and computes one delay per upcoming attempt.

delay

delay(attempt: int) -> float

Return the delay in seconds before retry attempt.

The strategy may apply jitter and clamp to its configured maximum.

PARAMETER DESCRIPTION
attempt

Upcoming retry number. attempt=1 is the delay before the first retry, after the initial call failed.

TYPE: int

Shield

Shield(
    name: str,
    config: _BaseShieldConfig | None = None,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
    env_load: bool | None = None,
    time_source: Callable[[], float] | None = None,
    random_source: Callable[[], float] | None = None,
)

Bases: Reconfigurable[_BaseShieldConfig]

Shield resilience pattern.

Wraps a single async callable with:

  • A per-attempt timeout estimated from the rolling p95 of the last 32 successful latencies.
  • Exponential-jittered retries gated by a consecutive-failure budget.
  • A CUBIC-style adaptive rate limiter that engages on the first slow-down and ramps back gradually.
  • Optional cache and fallback recovery paths on give-up.

One Shield instance covers one logical dependency. Multiple functions hitting the same dependency share one Shield and therefore one retry budget and one CUBIC controller.

Read more in the Shield docs.

Initialize the Shield instance with the api profile by default.

PARAMETER DESCRIPTION
name

Registration name of the Shield instance. Appears in logs, metrics, and PEP 678 notes attached on give-up.

TYPE: str

config

A pre-built profile config (InternalShieldConfig, ApiShieldConfig, SlowShieldConfig). Mutually exclusive with the per-field kwargs.

TYPE: _BaseShieldConfig | None DEFAULT: None

timeout_errors

Exception classes treated as transient slow-downs. TimeoutError is always appended. Default (TimeoutError,).

TYPE: tuple[type[BaseException], ...] | None DEFAULT: None

max_rate

Optional hard ceiling on the adaptive bucket's rate in tokens per second.

TYPE: PositiveFloat | None DEFAULT: None

cache

Optional cache instance read on give-up and written fire-and-forget on success.

TYPE: Any DEFAULT: None

cache_key

Optional callable returning the cache key for a call. Defaults to f"{name}:{stable_hash(args, kwargs)}".

TYPE: Callable[..., str] | None DEFAULT: None

fallback

Optional callable invoked on give-up when the cache path returns nothing. Receives the underlying exception.

TYPE: Callable[[BaseException], Any] | Callable[[BaseException], Awaitable[Any]] | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

time_source

Monotonic clock for tests. Defaults to time.monotonic.

TYPE: Callable[[], float] | None DEFAULT: None

random_source

Uniform [0, 1) random function for backoff jitter. Defaults to random.random.

TYPE: Callable[[], float] | None DEFAULT: None

name property

name: str

Return the Shield instance name.

from_config classmethod

from_config(name: str, config: _BaseShieldConfig) -> Self

Construct a Shield from a name and a pre-built profile config.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

config

The pre-built Shield profile configuration.

TYPE: _BaseShieldConfig

internal classmethod

internal(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the internal profile.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

api classmethod

api(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the api profile (the default).

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

slow classmethod

slow(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the slow profile.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

run async

run(
    fn: Callable[..., Awaitable[Any]],
    *args: Any,
    **kwargs: Any,
) -> Any

Run fn(*args, **kwargs) through this Shield instance.

PARAMETER DESCRIPTION
fn

Async callable to invoke under this Shield.

TYPE: Callable[..., Awaitable[Any]]

SlidingWindowConfig

Bases: _BaseRateLimiterConfig

Precise sliding-window rate limiting.

Stores a single timestamp per key (about 72 bytes).

Use this when you need a precise sliding window, such as for HTTP API throttling with RFC 9211 RateLimit-* headers or legacy X-RateLimit-* headers. For the pattern "allow a burst of N, then 1 per second", use TokenBucketConfig instead.

Example:

from grelmicro.resilience import RateLimiter, SlidingWindowConfig

# 5 requests per 60-second sliding window.
rl = RateLimiter("auth", SlidingWindowConfig(limit=5, window=60))

Read more in the Rate Limiter docs.

kind class-attribute instance-attribute

kind: Literal['sliding_window'] = 'sliding_window'

Discriminator for the algorithm Pydantic union.

limit instance-attribute

limit: PositiveInt

Maximum number of requests allowed per window.

window instance-attribute

window: PositiveFloat

Window duration in seconds.

SlowShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the slow profile.

Tuned for long-running calls: LLM inference, batch jobs, large queries. Low initial rate, large timeouts, tight failure budget. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute

kind: Literal['slow'] = 'slow'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute

max_consecutive_failures: int = 5

initial_max_rate class-attribute

initial_max_rate: float = 0.5

adaptive_burst_capacity class-attribute

adaptive_burst_capacity: float = 1.0

min_rate_floor class-attribute

min_rate_floor: float = 0.05

initial_timeout class-attribute

initial_timeout: float = 120.0

timeout_clamp_min class-attribute

timeout_clamp_min: float = 5.0

timeout_clamp_max class-attribute

timeout_clamp_max: float = 600.0

backoff_scale class-attribute

backoff_scale: float = 2.0

backoff_cap class-attribute

backoff_cap: float = 60.0

max_rate_cap_default class-attribute

max_rate_cap_default: float | None = None

profile_name class-attribute

profile_name: str = 'slow'

Timeout

Timeout(
    name: str,
    *,
    seconds: PositiveFloat | None = None,
    config: TimeoutConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[TimeoutConfig]

Timeout policy.

A named, reusable async deadline with three-paths configuration and live reconfiguration. Use as an async context manager or as a decorator on async functions.

Read more in the Timeout docs.

Initialize the timeout policy.

PARAMETER DESCRIPTION
name

The name of the timeout policy. Used as the env namespace and exposed via the name property.

TYPE: str

seconds

Deadline in seconds. Required unless config= is given or the value comes from env.

TYPE: PositiveFloat | None DEFAULT: None

config

A pre-built TimeoutConfig. Mutually exclusive with the per-field kwargs.

TYPE: TimeoutConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property

name: str

Return the timeout policy identity.

from_config classmethod

from_config(name: str, config: TimeoutConfig) -> Self

Construct a Timeout from a name and a pre-built TimeoutConfig.

PARAMETER DESCRIPTION
name

The name of the timeout policy.

TYPE: str

config

The pre-built timeout configuration.

TYPE: TimeoutConfig

TimeoutConfig

Bases: BaseModel

Timeout policy configuration.

Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Timeout docs.

seconds instance-attribute

seconds: PositiveFloat

Deadline in seconds. The inner block is cancelled and TimeoutError is raised when the deadline elapses.

TokenBucketConfig

Bases: _BaseRateLimiterConfig

Classic token bucket rate-limiting algorithm.

The bucket starts full and refills continuously at refill_rate tokens per second, capped at capacity. Each request consumes tokens. If the bucket has enough, the request is allowed, otherwise it is rejected with a retry_after hint.

Use this when you want the pattern "allow a burst of N requests, then a steady rate of 1 request per second". The token bucket is a common choice for bursty rate limiting.

Example:

from grelmicro.resilience import RateLimiter, TokenBucketConfig

# Allow 10 in a burst, then 1/sec sustained.
rl = RateLimiter("api", TokenBucketConfig(capacity=10, refill_rate=1))

Read more in the Rate Limiter docs.

kind class-attribute instance-attribute

kind: Literal['token_bucket'] = 'token_bucket'

Discriminator for the algorithm Pydantic union.

capacity instance-attribute

capacity: PositiveInt

Maximum burst size. The bucket never holds more than capacity tokens.

refill_rate instance-attribute

refill_rate: PositiveFloat

Tokens replenished per second, up to capacity.

falling_back

falling_back(
    *,
    when: WhenInput,
    default: Any = _UNSET,
    factory: Callable[[BaseException], Any] | None = None,
) -> _FallbackBlock[Any]

Build a fallback context manager for the block form.

Use async with falling_back(...) as result: (or the sync with form) to wrap a block of statements. Call result.set(value) on the success path. On a matched exception, the exception is suppressed and result.value holds the configured default or factory output.

Exactly one of default= or factory= must be set.

PARAMETER DESCRIPTION
when

Exception filter that engages the fallback.

TYPE: WhenInput

default

Static fallback value. Mutually exclusive with factory.

TYPE: Any DEFAULT: _UNSET

factory

Callable producing the fallback value from the exception.

TYPE: Callable[[BaseException], Any] | None DEFAULT: None

fallback

Fallback.

F module-attribute

F = TypeVar('F', bound=Callable[..., Any])

FallbackConfig

Bases: BaseModel

Fallback policy configuration.

Holds the exception filter plus exactly one of default or factory. Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Fallback docs.

when instance-attribute
when: Match

Exception filter that engages the fallback. Pass a Match or a shorthand: an exception class, a tuple of classes, or a predicate on the exception. BaseException subclasses outside Exception are never caught.

default class-attribute instance-attribute
default: Any = _UNSET

Static value returned when when matches. Mutually exclusive with factory. Exactly one must be set.

factory class-attribute instance-attribute
factory: Callable[[BaseException], Any] | None = None

Callable that produces the fallback value from the exception. Mutually exclusive with default.

model_config class-attribute instance-attribute
model_config = {'arbitrary_types_allowed': True}

FallbackResult

FallbackResult()

Holder for the value produced inside a falling_back block.

Call set(value) on success. When the block raises an exception matching when=, the exception is suppressed and the holder is filled with the configured default (or the factory output). Access the resulting value with the value property after the block exits.

Initialize an empty result holder.

value property
value: T

Return the recorded value (success or fallback).

RAISES DESCRIPTION
RuntimeError

When accessed before any value was set.

set
set(value: T) -> None

Record the success value for the block.

Fallback

Fallback(
    name: str,
    *,
    when: WhenInput | None = None,
    default: Any = _UNSET,
    factory: Callable[[BaseException], Any] | None = None,
    config: FallbackConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[FallbackConfig]

Fallback policy.

A named, reusable fallback policy with three-paths configuration and live reconfiguration. Use the constructor for the common case and Fallback.from_config when configuration is assembled elsewhere.

Read more in the Fallback docs.

Initialize the fallback policy.

PARAMETER DESCRIPTION
name

The name of the fallback policy. Used as the env namespace and exposed via the name property.

TYPE: str

when

Exception filter that engages the fallback. Pass a Match or a shorthand (class, tuple of classes, callable). Required unless config= is given or the value comes from env.

TYPE: WhenInput | None DEFAULT: None

default

Static fallback value. Mutually exclusive with factory. None is a valid value.

TYPE: Any DEFAULT: _UNSET

factory

Callable that produces the fallback value from the matched exception. Mutually exclusive with default.

TYPE: Callable[[BaseException], Any] | None DEFAULT: None

config

A pre-built FallbackConfig. Mutually exclusive with the per-field kwargs.

TYPE: FallbackConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property
name: str

Return the fallback policy identity.

from_config classmethod
from_config(name: str, config: FallbackConfig) -> Self

Construct a Fallback from a name and a pre-built FallbackConfig.

PARAMETER DESCRIPTION
name

The name of the fallback policy.

TYPE: str

config

The pre-built fallback configuration.

TYPE: FallbackConfig

fallback

fallback(
    *,
    when: WhenInput,
    default: Any = _UNSET,
    factory: Callable[[BaseException], Any] | None = None,
) -> Callable[[F], F]

Build an anonymous fallback decorator.

Exactly one of default= or factory= must be set.

PARAMETER DESCRIPTION
when

Exception filter that engages the fallback.

TYPE: WhenInput

default

Static fallback value. Mutually exclusive with factory.

TYPE: Any DEFAULT: _UNSET

factory

Callable producing the fallback value from the exception.

TYPE: Callable[[BaseException], Any] | None DEFAULT: None

falling_back

falling_back(
    *,
    when: WhenInput,
    default: Any = _UNSET,
    factory: Callable[[BaseException], Any] | None = None,
) -> _FallbackBlock[Any]

Build a fallback context manager for the block form.

Use async with falling_back(...) as result: (or the sync with form) to wrap a block of statements. Call result.set(value) on the success path. On a matched exception, the exception is suppressed and result.value holds the configured default or factory output.

Exactly one of default= or factory= must be set.

PARAMETER DESCRIPTION
when

Exception filter that engages the fallback.

TYPE: WhenInput

default

Static fallback value. Mutually exclusive with factory.

TYPE: Any DEFAULT: _UNSET

factory

Callable producing the fallback value from the exception.

TYPE: Callable[[BaseException], Any] | None DEFAULT: None

retry

Retry.

logger module-attribute

logger = getLogger(__name__)

F module-attribute

F = TypeVar('F', bound=Callable[..., Any])

WhenInput module-attribute

WhenInput = (
    Match
    | type[Exception]
    | tuple[type[Exception], ...]
    | Callable[[Exception], bool]
)

User-facing shape accepted by when=.

A Match instance, or one of the shorthand forms a Match would build for you: a single exception class, a tuple of classes, or a callable predicate on the exception. Bare shapes are coerced to Match.exception(...).

retry module-attribute

retry = _RetryFactory()

retrying module-attribute

retrying = _RetryingFactory()

RetryConfig

Bases: BaseModel

Retry policy configuration.

Holds the top-level retry fields plus a discriminated backoff sub-config. Frozen Pydantic data class. Three-paths configuration: kwargs, instance, or env vars.

Read more in the Retry docs.

attempts class-attribute instance-attribute
attempts: PositiveInt = 3

Total calls including the first. attempts=1 means no retry. The default 3 allows two retries.

max_seconds class-attribute instance-attribute
max_seconds: PositiveFloat | None = None

Optional wall-clock budget in seconds, measured from the first attempt. Retrying stops as soon as either attempts is reached or this budget elapses, whichever comes first. The budget is checked between attempts, so one backoff may run slightly past it. None (default) means no time limit.

when instance-attribute
when: Match

Outcome filter that engages the retry. Pass a Match (e.g. Match.exception(httpx.HTTPError) | Match.result(None)) or a shorthand: an exception class, a tuple of classes, or a predicate on the exception. BaseException subclasses outside Exception are never retried.

backoff instance-attribute

Backoff algorithm config. Discriminated union over ExponentialBackoff, ConstantBackoff, LinearBackoff, FibonacciBackoff, and RandomBackoff. Default: exponential with full jitter.

model_config class-attribute instance-attribute
model_config = {'arbitrary_types_allowed': True}

RetryAttempt

RetryAttempt(
    *,
    number: int,
    delay_before: float,
    attempts: int,
    matcher: Matcher,
    loop: _AttemptLoop,
    started_at: float,
    max_seconds: float | None,
)

One iteration of a retry loop.

Yielded by Retry iteration and by retrying. Used as an async (or sync) context manager. Suppresses retryable exceptions until attempts are exhausted, then re-raises the underlying error with a PEP 678 note.

The block form sees only exceptions, not return values. Use the decorator form (@retry or policy(fn)) for result-based retry.

Initialize one retry attempt.

number instance-attribute
number = number

1-indexed attempt number. The first call is 1.

delay_before instance-attribute
delay_before = delay_before

Seconds slept before this attempt (0.0 for the first).

Retry

Retry(
    name: str,
    backoff: RetryBackoffConfig | None = None,
    *,
    when: WhenInput | None = None,
    attempts: PositiveInt | None = None,
    max_seconds: PositiveFloat | None = None,
    config: RetryConfig | None = None,
    env_load: bool | None = None,
)

Bases: Reconfigurable[RetryConfig]

Retry policy.

A named, reusable retry policy with three-paths configuration and live reconfiguration. Use the Retry.exponential or Retry.constant factory classmethods for the common case. Pass a pre-built backoff config to the constructor when configuration is assembled elsewhere.

Read more in the Retry docs.

Initialize the retry policy.

PARAMETER DESCRIPTION
name

The name of the retry policy. Used as the env namespace and exposed via the name property.

TYPE: str

backoff

The backoff algorithm config. Pass any RetryBackoffConfig variant or omit for the default exponential + full jitter.

TYPE: RetryBackoffConfig | None DEFAULT: None

when

Outcome filter that engages the retry. Pass a Match or one of the shorthand forms (exception class, tuple, callable). Required unless config= is given.

TYPE: WhenInput | None DEFAULT: None

attempts

Total calls including the first. Default 3.

TYPE: PositiveInt | None DEFAULT: None

max_seconds

Optional wall-clock budget in seconds. Retrying stops when either attempts or this budget is reached, whichever comes first. Default no time limit.

TYPE: PositiveFloat | None DEFAULT: None

config

A pre-built RetryConfig. Mutually exclusive with the per-field kwargs.

TYPE: RetryConfig | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

name property
name: str

Return the retry policy identity.

from_config classmethod
from_config(name: str, config: RetryConfig) -> Self

Construct a Retry from a name and a pre-built RetryConfig.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

config

The pre-built retry configuration.

Use this path when the configuration is assembled at startup from a settings tree. The environment path is bypassed and the config is used as-is.

TYPE: RetryConfig

exponential classmethod
exponential(
    name: str,
    *,
    when: WhenInput,
    attempts: PositiveInt = 3,
    max_seconds: PositiveFloat | None = None,
    base_delay: PositiveFloat = 0.1,
    max_delay: PositiveFloat = 30.0,
    jitter: Literal[
        "none", "full", "decorrelated"
    ] = "full",
    env_load: bool | None = None,
) -> Self

Construct a retry policy with exponential backoff.

Convenience factory for the common case. Builds an ExponentialBackoff and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

when

Outcome filter that engages the retry.

TYPE: WhenInput

attempts

Total calls including the first.

TYPE: PositiveInt DEFAULT: 3

max_seconds

Optional wall-clock budget in seconds, whichever comes first with attempts.

TYPE: PositiveFloat | None DEFAULT: None

base_delay

Initial delay in seconds before the first retry.

TYPE: PositiveFloat DEFAULT: 0.1

max_delay

Maximum delay in seconds. Caps exponential growth.

TYPE: PositiveFloat DEFAULT: 30.0

jitter

Jitter mode.

TYPE: Literal['none', 'full', 'decorrelated'] DEFAULT: 'full'

env_load

Whether to read environment variables.

TYPE: bool | None DEFAULT: None

constant classmethod
constant(
    name: str,
    *,
    when: WhenInput,
    attempts: PositiveInt = 3,
    max_seconds: PositiveFloat | None = None,
    delay: PositiveFloat = 1.0,
    env_load: bool | None = None,
) -> Self

Construct a retry policy with constant delay.

Convenience factory for polling-style retries. Builds a ConstantBackoff and forwards to the constructor.

PARAMETER DESCRIPTION
name

The name of the retry policy.

TYPE: str

when

Outcome filter that engages the retry.

TYPE: WhenInput

attempts

Total calls including the first.

TYPE: PositiveInt DEFAULT: 3

max_seconds

Optional wall-clock budget in seconds, whichever comes first with attempts.

TYPE: PositiveFloat | None DEFAULT: None

delay

Fixed delay in seconds between retries.

TYPE: PositiveFloat DEFAULT: 1.0

env_load

Whether to read environment variables.

TYPE: bool | None DEFAULT: None

shield

Shield resilience pattern.

shield module-attribute

shield = _ShieldDecorator()

ShieldConfig module-attribute

Discriminated union over the three Shield profile configs.

ApiShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the api profile (the default).

Tuned for external HTTP APIs. Modest initial rate, generous timeouts, broad clamps. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute
kind: Literal['api'] = 'api'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute
max_consecutive_failures: int = 20
initial_max_rate class-attribute
initial_max_rate: float = 2.0
adaptive_burst_capacity class-attribute
adaptive_burst_capacity: float = 5.0
min_rate_floor class-attribute
min_rate_floor: float = 0.25
initial_timeout class-attribute
initial_timeout: float = 10.0
timeout_clamp_min class-attribute
timeout_clamp_min: float = 0.5
timeout_clamp_max class-attribute
timeout_clamp_max: float = 60.0
backoff_scale class-attribute
backoff_scale: float = 1.0
backoff_cap class-attribute
backoff_cap: float = 30.0
max_rate_cap_default class-attribute
max_rate_cap_default: float | None = None
profile_name class-attribute
profile_name: str = 'api'

InternalShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the internal profile.

Tuned for in-cluster RPC. High initial rate, short timeouts, tight budgets. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute
kind: Literal['internal'] = 'internal'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute
max_consecutive_failures: int = 10
initial_max_rate class-attribute
initial_max_rate: float = 100.0
adaptive_burst_capacity class-attribute
adaptive_burst_capacity: float = 200.0
min_rate_floor class-attribute
min_rate_floor: float = 1.0
initial_timeout class-attribute
initial_timeout: float = 1.0
timeout_clamp_min class-attribute
timeout_clamp_min: float = 0.05
timeout_clamp_max class-attribute
timeout_clamp_max: float = 5.0
backoff_scale class-attribute
backoff_scale: float = 0.5
backoff_cap class-attribute
backoff_cap: float = 5.0
max_rate_cap_default class-attribute
max_rate_cap_default: float | None = None
profile_name class-attribute
profile_name: str = 'internal'

Shield

Shield(
    name: str,
    config: _BaseShieldConfig | None = None,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
    env_load: bool | None = None,
    time_source: Callable[[], float] | None = None,
    random_source: Callable[[], float] | None = None,
)

Bases: Reconfigurable[_BaseShieldConfig]

Shield resilience pattern.

Wraps a single async callable with:

  • A per-attempt timeout estimated from the rolling p95 of the last 32 successful latencies.
  • Exponential-jittered retries gated by a consecutive-failure budget.
  • A CUBIC-style adaptive rate limiter that engages on the first slow-down and ramps back gradually.
  • Optional cache and fallback recovery paths on give-up.

One Shield instance covers one logical dependency. Multiple functions hitting the same dependency share one Shield and therefore one retry budget and one CUBIC controller.

Read more in the Shield docs.

Initialize the Shield instance with the api profile by default.

PARAMETER DESCRIPTION
name

Registration name of the Shield instance. Appears in logs, metrics, and PEP 678 notes attached on give-up.

TYPE: str

config

A pre-built profile config (InternalShieldConfig, ApiShieldConfig, SlowShieldConfig). Mutually exclusive with the per-field kwargs.

TYPE: _BaseShieldConfig | None DEFAULT: None

timeout_errors

Exception classes treated as transient slow-downs. TimeoutError is always appended. Default (TimeoutError,).

TYPE: tuple[type[BaseException], ...] | None DEFAULT: None

max_rate

Optional hard ceiling on the adaptive bucket's rate in tokens per second.

TYPE: PositiveFloat | None DEFAULT: None

cache

Optional cache instance read on give-up and written fire-and-forget on success.

TYPE: Any DEFAULT: None

cache_key

Optional callable returning the cache key for a call. Defaults to f"{name}:{stable_hash(args, kwargs)}".

TYPE: Callable[..., str] | None DEFAULT: None

fallback

Optional callable invoked on give-up when the cache path returns nothing. Receives the underlying exception.

TYPE: Callable[[BaseException], Any] | Callable[[BaseException], Awaitable[Any]] | None DEFAULT: None

env_load

Whether to read environment variables. Defaults to the process-wide GREL_ENV_LOAD flag.

TYPE: bool | None DEFAULT: None

time_source

Monotonic clock for tests. Defaults to time.monotonic.

TYPE: Callable[[], float] | None DEFAULT: None

random_source

Uniform [0, 1) random function for backoff jitter. Defaults to random.random.

TYPE: Callable[[], float] | None DEFAULT: None

name property
name: str

Return the Shield instance name.

from_config classmethod
from_config(name: str, config: _BaseShieldConfig) -> Self

Construct a Shield from a name and a pre-built profile config.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

config

The pre-built Shield profile configuration.

TYPE: _BaseShieldConfig

internal classmethod
internal(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the internal profile.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

api classmethod
api(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the api profile (the default).

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

slow classmethod
slow(
    name: str,
    *,
    timeout_errors: tuple[type[BaseException], ...]
    | None = None,
    max_rate: PositiveFloat | None = None,
    cache: Any = None,
    cache_key: Callable[..., str] | None = None,
    fallback: Callable[[BaseException], Any]
    | Callable[[BaseException], Awaitable[Any]]
    | None = None,
) -> Self

Construct a Shield with the slow profile.

PARAMETER DESCRIPTION
name

Name of the Shield instance.

TYPE: str

run async
run(
    fn: Callable[..., Awaitable[Any]],
    *args: Any,
    **kwargs: Any,
) -> Any

Run fn(*args, **kwargs) through this Shield instance.

PARAMETER DESCRIPTION
fn

Async callable to invoke under this Shield.

TYPE: Callable[..., Awaitable[Any]]

SlowShieldConfig

Bases: _BaseShieldConfig

Shield configuration for the slow profile.

Tuned for long-running calls: LLM inference, batch jobs, large queries. Low initial rate, large timeouts, tight failure budget. The profile parameters are frozen.

Read more in the Shield docs.

kind class-attribute instance-attribute
kind: Literal['slow'] = 'slow'

Discriminator for the Shield profile Pydantic union.

max_consecutive_failures class-attribute
max_consecutive_failures: int = 5
initial_max_rate class-attribute
initial_max_rate: float = 0.5
adaptive_burst_capacity class-attribute
adaptive_burst_capacity: float = 1.0
min_rate_floor class-attribute
min_rate_floor: float = 0.05
initial_timeout class-attribute
initial_timeout: float = 120.0
timeout_clamp_min class-attribute
timeout_clamp_min: float = 5.0
timeout_clamp_max class-attribute
timeout_clamp_max: float = 600.0
backoff_scale class-attribute
backoff_scale: float = 2.0
backoff_cap class-attribute
backoff_cap: float = 60.0
max_rate_cap_default class-attribute
max_rate_cap_default: float | None = None
profile_name class-attribute
profile_name: str = 'slow'