Skip to content
RelPrim docsAPI reference

Reference

API reference

The public RelPrim API, grouped by domain, with signatures, defaults and links to the guides. What is covered by the stability promise and what is internal.

This page is an index of the public API: signatures and one-line purposes, with links to the guides for behavior. Durations are always in seconds.

What is public

Public, and covered by the stability policy:

  • every name in relprim.__all__, imported from the top-level relprim package;
  • every name in __all__ of the optional modules relprim.opentelemetry, relprim.jsonschema and relprim.pydantic;
  • their documented parameters, attributes, methods and properties;
  • documented runtime behavior, including the event and metadata contract.

Not public:

  • names starting with an underscore, including AsyncOperation’s dataclass fields and modules such as relprim._checks;
  • the submodule where a core name is defined (relprim.retry, relprim.operation, …): import core names from relprim;
  • module-level names not in __all__;
  • exception message text, repr() output and validation reason wording;
  • the dev extra.

Decorator

Name Purpose
resilient(...) Decorate an async def so calling it runs an operation and returns OperationResult[R]. All options are keyword-only.
ResilientDecorator[RF] The protocol resilient(...) returns, for annotating a decorator stored in a variable.

The decorated function keeps its parameters and returns Coroutine[Any, Any, OperationResult[R]], or OperationResult[R | RF] with a fallback returning RF. name defaults to the function’s __name__.

Decorator options

Each simple option and its advanced counterpart are mutually exclusive.

Simple option Advanced option Builder method Guide
retries, retry_on retry=RetryPolicy(...) with_retry Retry
timeout=<seconds> timeout=TimeoutPolicy(...) with_timeout Timeouts
fallback=<callable> fallbacks=fallback_chain(...) with_fallbacks Fallbacks
(none) circuit_breaker=CircuitBreaker(...) with_circuit_breaker Circuit breakers
(none) validation=validation_policy(...) with_validation Validation
(none) events=EventEmitter(...) with_events Structured events
idempotency_key, idempotency_store, idempotency_ttl idempotency=idempotency_policy(...) with_idempotency Idempotency
rate_limit_on, retry_after, max_rate_limit_wait rate_limit=RateLimitPolicy(...) with_rate_limit Rate limits
  • retries=N equals RetryPolicy(max_attempts=N + 1); retries=0 disables retrying.
  • retry_on defaults to (Exception,) and requires retries.
  • Invalid or conflicting options raise ValueError or TypeError when resilient(...) is called.
  • The decorator does not statically check that validation, fallback or idempotency_key match the function; the builder does.

Builder

Name Purpose
async_operation(name, operation) Create an AsyncOperation[P, R] from a name and an async callable.
AsyncOperation Immutable operation configuration. Create it with async_operation, not its constructor.
.with_retry(policy), .with_timeout(policy), .with_fallbacks(chain), .with_circuit_breaker(breaker), .with_validation(policy), .with_events(emitter), .with_idempotency(policy), .with_rate_limit(policy) Return a new operation with that policy set. Calling a method twice keeps the last policy.
await .run(*args, **kwargs) Execute; return OperationResult[R] or raise OperationExecutionError.

The order of builder calls never changes behavior; see execution order.

Retry

Signature Notes
RetryPolicy(max_attempts=3, backoff=ExponentialBackoff(), retry_on=(Exception,), sleeper=time.sleep, async_sleeper=asyncio.sleep) max_attempts includes the first attempt. retry_on takes Exception subclasses only.
RetryPolicy.run(operation, *args, **kwargs), await RetryPolicy.run_async(...) Standalone use; raise RetryError after the final attempt.
ExponentialBackoff(base_delay_seconds=0.1, max_delay_seconds=10.0, multiplier=2.0, jitter=True) delay_for_retry(n), 1-based. With jitter, uniform in [0, computed].

Timeout

Signature Notes
TimeoutPolicy(seconds) Async only. Raises OperationTimeoutError only when its own deadline expires.

Fallback

Signature Notes
fallback_chain(("name", operation), ..., policy=None) Create a FallbackChain. Same as FallbackChain.from_operations(...).
FallbackChain(candidates, policy=FallbackPolicy()), FallbackCandidate(name, operation) Ordered candidates. await chain.run(*args) returns a FallbackResult.
FallbackPolicy(fallback_on=(Exception,)) Which failures trigger a fallback, for the primary failure and between candidates.
FallbackResult value, candidate_name, candidate_index, fallback_used, failures, failure_count.

Circuit breaker

Signature Notes
CircuitBreaker(name="default", failure_threshold=5, recovery_timeout_seconds=30.0, record_failure_on=(Exception,), clock=time.monotonic) Shared, stateful; compares by identity.
await breaker.run_async(operation, *args), await breaker.snapshot(), await breaker.reset()
CircuitBreakerState closed, open, half_open.
CircuitBreakerSnapshot Immutable: state, failure_count, opened_at, half_open_probe_in_flight, …

Validation

Signature Notes
Validator[T] Protocol: read-only name, validate(value) -> ValidationResult. Contravariant.
validator(name, predicate, *, message) → CallableValidator Dependency-free validator from a predicate.
validation_policy(*validators) → ValidationPolicy Fail-fast, in order. Contravariant.
ValidationPolicy.validate(value), .validate_or_raise(value) First failing result, or the last validator’s success result. validate_or_raise raises ValidationFailedError.
ValidationResult(valid, validator_name, reason=None) ValidationResult.success(...), ValidationResult.failure(...), to_dict().
relprim.jsonschema.json_schema_validator(schema, *, name="json_schema") → JSONSchemaValidator JSON Schema.
relprim.pydantic.pydantic_validator(model, *, name=None, strict=None) → PydanticValidator Pydantic.

Idempotency

Signature Notes
idempotency_policy(key_factory, *, store=None, ttl_seconds=3600.0) → IdempotencyPolicy store=None creates an InMemoryIdempotencyStore.
IdempotencyStore Protocol for custom stores.
InMemoryIdempotencyStore(clock=time.monotonic) One process, one event loop. await purge_expired(), await entry_count().
IdempotencyResult, IdempotencyStatus executed, joined, replayed.

Rate limits

Signature Notes
RateLimitPolicy(rate_limit_on, retry_after=None, max_wait_seconds=60.0) Also rate_limit_policy(...) with keyword arguments.
RetryAfterExtractor Callable[[Exception], float | None].
RateLimitDecision Result of RateLimitPolicy.evaluate(exception): rate_limited, retry_after_seconds.

Events

Signature Notes
EventType Stable event identifiers. See event types.
StructuredEvent(event_type, operation_name, timestamp, payload={}) Immutable; timezone-aware timestamp; JSON-scalar payload. to_dict().
EventEmitter(sinks=(NoopEventSink(),), timestamp_factory=...) Awaits sinks in order.
EventSink Protocol: async emit(event).
NoopEventSink(), InMemoryEventSink() await InMemoryEventSink.events(), .clear().
SQLiteEventStore(database, busy_timeout_seconds=5.0), StoredEvent SQLite event store.
relprim.opentelemetry.OpenTelemetryEventSink() OpenTelemetry.

Reports and results

Name Members
OperationResult[T] value, report, succeeded, failed. Returned for successful executions only. Covariant.
ExecutionReport operation_name, status, started_at, duration_seconds, attempts, metadata, attempt_count, retry_count, retried, last_attempt, last_error, succeeded, failed, to_dict().
ExecutionAttempt attempt_number, status, started_at, duration_seconds, error, metadata, fallback, succeeded, failed, to_dict().
ExecutionError Serializable error summary: type, message, module, retryable, to_dict().
ExecutionStatus, AttemptStatus succeeded, failed, timed_out.

attempt_count includes the fallback attempt; retry_count counts primary attempts after the first one only.

Exceptions

Exception
└── RelPrimError
    ├── OperationExecutionError      .report, .cause
    ├── RetryError                   .attempts, .cause
    ├── OperationTimeoutError        .timeout_seconds, .cause
    ├── FallbackChainError           .failures, .cause
    ├── CircuitBreakerOpenError      .breaker_name, .state, .retry_after_seconds
    ├── ValidationFailedError        .validator_name, .reason
    ├── RetryAfterExtractionError    .rate_limit_error, .cause
    ├── IdempotencyReentryError      .key
    └── SQLiteEventStoreSchemaError

What AsyncOperation.run() and decorated functions raise:

Situation Exception
The operation failed after retries and fallbacks OperationExecutionError; .cause is the final failure, for example OperationTimeoutError, ValidationFailedError, CircuitBreakerOpenError, FallbackChainError or the operation’s own exception
The calling task was cancelled asyncio.CancelledError, never wrapped
An event sink raised The sink’s exception, unchanged
The idempotency key factory raised or returned a bad key The original exception, or TypeError / ValueError
The same idempotency key was reused recursively IdempotencyReentryError

Configuration mistakes raise ValueError or TypeError when a policy is constructed or resilient(...) is called. Optional integrations let third-party configuration errors through unchanged, such as jsonschema.exceptions.SchemaError, and SQLiteEventStore propagates sqlite3 errors unchanged. RetryError is raised only by the standalone RetryPolicy.run* methods.