Senpuki
Distributed durable functions for Python. Write reliable, stateful workflows using async/await.
pip install senpuki
Quick Example
import asyncio
from senpuki import Senpuki, Result
@Senpuki.durable()
async def process_order(order_id: str) -> dict:
await asyncio.sleep(1) # Simulate work
return {"order_id": order_id, "status": "processed"}
@Senpuki.durable()
async def order_workflow(order_ids: list[str]) -> Result[list, Exception]:
results = []
for order_id in order_ids:
result = await process_order(order_id)
results.append(result)
return Result.Ok(results)
async def main():
backend = Senpuki.backends.SQLiteBackend("workflow.db")
await backend.init_db()
executor = Senpuki(backend=backend)
worker = asyncio.create_task(executor.serve())
exec_id = await executor.dispatch(order_workflow, ["ORD-001", "ORD-002"])
result = await executor.wait_for(exec_id)
print(result.value)
asyncio.run(main())
Why Senpuki?
| Feature | Temporal | Celery | Prefect | Airflow | Senpuki |
|---|---|---|---|---|---|
| Durable Execution | Yes | No | Partial | No | Yes |
| Setup Complexity | High | Medium | Medium | High | Very Low |
| Infrastructure | Server cluster | Broker | Server | Multi-component | SQLite/Postgres |
| Native Async | Yes | No | Yes | Limited | Yes |
Senpuki fills the gap between simple task queues (Celery) and enterprise platforms (Temporal):
- vs Temporal: Same durability guarantees, fraction of the infrastructure
- vs Celery/Dramatiq: True workflow durability, not just task retries
- vs Prefect/Airflow: Application workflows, not batch data pipelines
See full comparison for details.
Features
- Durable Execution - Workflow state survives crashes and restarts
- Automatic Retries - Configurable retry policies with exponential backoff
- Distributed Workers - Scale horizontally across multiple processes
- Parallel Execution - Fan-out/fan-in with
asyncio.gatherandSenpuki.map - Rate Limiting - Control concurrent executions per function
- External Signals - Coordinate workflows with external events
- Dead Letter Queue - Inspect and replay failed tasks
- Idempotency & Caching - Prevent duplicate work
- Multiple Backends - SQLite (dev) or PostgreSQL (production)
- OpenTelemetry - Distributed tracing support
Key Concepts
from senpuki import Senpuki, RetryPolicy
# Configurable retry policies
@Senpuki.durable(
retry_policy=RetryPolicy(max_attempts=5, initial_delay=1.0),
queue="high_priority",
max_concurrent=10, # Rate limiting
idempotent=True, # Prevent duplicate execution
)
async def my_activity(data: dict) -> dict:
...
# Durable sleep (doesn't block workers)
await Senpuki.sleep("30m")
# Parallel execution
results = await asyncio.gather(*[process(item) for item in items])
# Or optimized for large batches:
results = await Senpuki.map(process, items)
# External signals
payload = await Senpuki.wait_for_signal("approval")
await executor.send_signal(exec_id, "approval", {"approved": True})
Backends
# SQLite (development)
backend = Senpuki.backends.SQLiteBackend("senpuki.db")
# PostgreSQL (production)
backend = Senpuki.backends.PostgresBackend("postgresql://user:pass@host/db")
# Optional: Redis for low-latency notifications
executor = Senpuki(
backend=backend,
notification_backend=Senpuki.notifications.RedisBackend("redis://localhost")
)
CLI
senpuki list # List executions
senpuki show <exec_id> # Show execution details
senpuki dlq list # List dead-lettered tasks
senpuki dlq replay <task_id> # Replay failed task
Documentation
Full documentation available in docs/:
- Getting Started | Core Concepts | Comparison
- Guides: Durable Functions | Orchestration | Error Handling | Parallel Execution | Signals | Workers | Monitoring
- Patterns: Saga | Batch Processing
- Reference: API | Configuration | Deployment
Examples
See examples/ for complete workflows:
simple_flow.py- Basic workflowsaga_trip_booking.py- Saga pattern with compensationbatch_processing.py- Fan-out/fan-inmedia_pipeline.py- Complex multi-stage pipeline
Requirements
- Python 3.12+
aiosqliteorasyncpg(backend)redis(optional, for notifications)
License
MIT
Release files for senpuki 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| senpuki-0.3.0.tar.gz | 79.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| senpuki-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 177.3 kB
Release files / senpuki-0.3.0.tar.gz
| Download URL | senpuki-0.3.0.tar.gz |
|---|---|
| Size | 79.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
462a68074add7b066906af5fba030362015e10323b5f75bfdac801defea1ddf4
|
|
BLAKE2b-256 checksum How to use checksums |
512b678e3309c79777ca09ea9899bf1d40ebec7de51a3eab641149cfa8234e54
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / senpuki-0.3.0-py3-none-any.whl
| Download URL | senpuki-0.3.0-py3-none-any.whl |
|---|---|
| Size | 98.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
591f4f9b96864f4a7e23bbd5806ca2881f44a4225cae70d25fb8eaafecec74a9
|
|
BLAKE2b-256 checksum How to use checksums |
d0714daf7f8d3f78fbe58f9ded29e766ac6a427d8a5ab55c3955c1c7c259a4e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|