Reliability primitives for Python applications.
Project description
RelPrim
Reliability primitives for operations that cross process, network or provider boundaries.
RelPrim helps you wrap external calls with retries, timeouts, fallbacks, validation, circuit breakers, execution reports and structured events.
Install
pip install relprim
Wrap an external call in seconds
from relprim import resilient
async def call_gemini(prompt: str) -> str:
return await gemini_client.generate(prompt)
@resilient(retries=3, timeout=10, fallback=call_gemini)
async def call_openai(prompt: str) -> str:
return await openai_client.generate(prompt)
result = await call_openai("Write a short product summary")
print(result.value)
print(result.report.to_dict())
The decorated function returns an OperationResult[T], not a raw value. This keeps the business result and the execution report explicit.
Why RelPrim?
Most external calls start simple:
response = await openai.chat.completions.create(...)
But production systems need to answer harder questions:
- What if the provider times out?
- What if the response is temporarily unavailable?
- What if the provider returns an invalid response?
- What if the primary provider is down?
- What if you need a fallback provider?
- What if you need to debug what happened after the fact?
RelPrim gives you two levels of adoption.
Beginner-friendly decorator API:
@resilient(retries=3, timeout=10)
async def call_provider(prompt: str) -> str:
return await provider.generate(prompt)
Advanced composition API:
result = await (
async_operation("generate_response", call_provider)
.with_retry(RetryPolicy(max_attempts=3))
.with_timeout(TimeoutPolicy(seconds=10))
.with_validation(validation_policy(...))
.with_fallbacks(fallback_chain(("backup_provider", call_backup)))
.run(prompt)
)
Prevent duplicate executions
RelPrim can deduplicate repeated or concurrent calls using an idempotency key.
from relprim import resilient
@resilient(
retries=2,
timeout=10,
idempotency_key=lambda request_id, amount: f"create-payment:{request_id}",
idempotency_ttl=3600,
)
async def create_payment(
request_id: str,
amount: int,
) -> str:
return await payment_gateway.create(request_id, amount)
The first call executes the operation. Concurrent callers join the same execution, and later calls replay the successful result.
The default store is in-memory and single-process. See the idempotency guide for concurrency semantics, key design and store limitations.
What RelPrim provides
Current primitives:
- Resilient decorator API
- Retry policies
- Exponential backoff with jitter
- Async timeout enforcement
- Async fallback chains
- Async circuit breakers
- Validation policies
- Callable validators
- Structured events
- Event emitters
- No-op event sink
- In-memory event sink
- Async operation builder API
- Structured execution reports
- Operation results
- Typed execution errors
- Idempotency policies
- Concurrent execution joining
- Successful result replay
- In-memory idempotency store
Planned primitives:
- SQLite event store
- OpenTelemetry exporter
- Rate limit handling
- JSON Schema validator adapter
- Pydantic validator adapter
Examples
Practical examples are available in the examples directory:
decorator_usage.py— beginner-friendly decorator APIbasic_resilience.py— retry, timeout and execution reportsfallback_chain.py— primary provider failure with fallback executioncircuit_breaker.py— circuit breaker protection with fallback behaviorvalidation.py— result validation with retry supportstructured_events.py— operation lifecycle events with retry and validationidempotency.py— duplicate execution prevention and result replay
If you run examples from a cloned repository, install RelPrim in editable mode first:
python -m pip install -e ".[dev]"
python examples/decorator_usage.py
Or run a single example without installing the package:
PYTHONPATH=src python examples/decorator_usage.py
Documentation
Design principles
RelPrim is intentionally small and explicit.
Core principles:
- Reliability behavior should be visible in code.
- Failure modes should be explicit.
- Defaults should be safe for production use.
- Primitives should be composable, not magical.
- Observability should be built into the execution model.
- Async execution should respect cancellation and timeout semantics.
- The library should not hide side effects behind fake safety guarantees.
- External integrations should be wrapped, not replaced.
RelPrim does not try to become a workflow engine. It provides the reliability layer that can be used inside your application, worker, service or orchestration system.
What RelPrim is not
RelPrim is not:
- an AI provider SDK
- an HTTP client
- a workflow engine
- a task queue
- an observability backend
- a replacement for provider-native SDKs
- a replacement for Temporal, Celery or OpenTelemetry
It is a reliability layer for external operations.
Maintainer
Created and maintained by Bart Rozycki.
License
Apache License 2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file relprim-0.8.0.tar.gz.
File metadata
- Download URL: relprim-0.8.0.tar.gz
- Upload date:
- Size: 40.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffc7d24c281664b8f7624b09ca9e3f922ebcf42451ee50147af7a953719918c2
|
|
| MD5 |
a71007ca8bb899267ed19efcdc998b5c
|
|
| BLAKE2b-256 |
74a9aaa3e2cbd4c7d9e5d5f10c5944200775305841b3a420398381bacd53f6cd
|
File details
Details for the file relprim-0.8.0-py3-none-any.whl.
File metadata
- Download URL: relprim-0.8.0-py3-none-any.whl
- Upload date:
- Size: 30.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2463728a91eeeec52ef8cd14c894dde97a4ec7ba593b0ac117cd41c6ebeda30a
|
|
| MD5 |
62ed44ddd768246da4b3437ffb207cbe
|
|
| BLAKE2b-256 |
74f5ef3e65d5eb9056b31138f2ad3d9b171f1b57eb5827cfaeb1df509f0f9ceb
|