Skip to content
RelPrim docs

Documentation

RelPrim

Reliability primitives for operations that cross process, network or provider boundaries. Retries, timeouts, fallbacks, circuit breakers, validation, idempotency and rate-limit recovery for Python asyncio, with execution reports and structured events.

RelPrim is a small, fully typed Python library that wraps an async call to something you do not control (a model provider, a payment gateway, an internal service) in explicit reliability behavior. Every execution produces an execution report, returned with the value on success and attached to the exception on failure, and can emit structured events that describe what happened: which attempts ran, why they failed, whether a fallback was used.

pip install relprim

A first example

from relprim import resilient


async def call_backup(prompt: str) -> str:
    return await backup_client.generate(prompt)


@resilient(retries=3, timeout=10, fallback=call_backup)
async def generate(prompt: str) -> str:
    return await primary_client.generate(prompt)


result = await generate("Summarize this ticket")

result.value                  # the string returned by primary_client or call_backup
result.report.attempt_count   # how many attempts ran, including the fallback
result.report.to_dict()       # a JSON-ready description of the execution

retries=3 allows three retries after the first attempt, timeout=10 bounds each attempt to ten seconds, and the fallback runs once the retries are exhausted. If everything fails, OperationExecutionError is raised with the execution report attached. The decorated function keeps its signature, and type checkers see the result as OperationResult[str].

The primitives

Primitive What it does
Retry Retries selected exceptions with exponential backoff and jitter.
Timeouts Bounds each attempt with an asyncio deadline.
Fallbacks Tries named backup operations, in order, after the primary fails.
Circuit breakers Stops calling a dependency that keeps failing, then probes it.
Rate limits Waits for a provider’s retry-after hint, within a maximum wait.
Validation Rejects results that are well-formed calls but unusable values.
Idempotency Coordinates duplicate calls and replays successful results.
Structured events Describes each execution step to sinks you choose.

Each primitive is a plain object you construct and pass in. Policies are immutable; circuit breakers and idempotency stores hold state that you share deliberately between operations. You can use one primitive on its own or compose several into a single operation, and RelPrim always applies them in the same documented execution order.

Two ways to configure an operation

The @resilient decorator is the fastest way to adopt RelPrim. Simple options such as retries=3 or timeout=10 cover most integrations, and each one has an advanced counterpart that accepts a full policy object.

The builder API composes the same policies explicitly. It suits operations assembled at runtime and gives the strongest static type checking:

from relprim import RetryPolicy, TimeoutPolicy, async_operation, fallback_chain

result = await (
    async_operation("generate", primary_client.generate)
    .with_retry(RetryPolicy(max_attempts=4))
    .with_timeout(TimeoutPolicy(seconds=10))
    .with_fallbacks(fallback_chain(("backup", backup_client.generate)))
    .run("Summarize this ticket")
)

Both produce the same behavior. Core concepts explains the model they share.

Optional integrations

The core package has no dependencies. Integrations are installed as extras and imported from their own modules, so import relprim never loads them.

Extra Module Provides
relprim[otel] relprim.opentelemetry OpenTelemetryEventSink, which adds events to the active span
relprim[jsonschema] relprim.jsonschema json_schema_validator
relprim[pydantic] relprim.pydantic pydantic_validator
(none) relprim SQLiteEventStore, built on the standard library

What RelPrim is not

RelPrim is a reliability layer inside your application, worker or service. It is not an HTTP client or provider SDK, a workflow engine, a task queue or an observability backend, and it does not replace Temporal, Celery or OpenTelemetry. It does not hide side effects behind guarantees it cannot keep: for example, idempotency coordinates duplicate calls but is not an exactly-once guarantee for external side effects.

Where to go next

  • Getting started

    Install RelPrim and wrap a flaky call with retry, timeout and fallback.

  • Core concepts

    Operations, attempts, reports and the fixed execution order.

  • Examples

    Complete, runnable scenarios: failover, invalid responses, duplicate payments and more.

  • Structured events

    The event and metadata contract, and how to consume it.

  • API reference

    Every public name, grouped by domain.

Project