Durable async runtime for Python
Project description
Duron
Duron is a lightweight durable execution runtime for Python async workflows. It provides replayable execution primitives that work standalone or as building blocks for complex workflow engines.
Why Duron?
- 🪶 Zero extra deps — Lightweight library that layers on top of asyncio; add Duron without bloating your stack.
- 🧩 Pluggable architecture — Bring your own storage or infra components and swap them without changing orchestration code.
- 🔄 Streams & signals — Model long-running conversations, live data feeds, and feedback loops with built-in primitives.
- 🐍 Python-native & typed — Type hints make replay serialization predictable, and everything feels like idiomatic Python.
- 🔭 Built-in tracing — Detailed logs help you inspect replays and surface observability data wherever you need it.
Install
Duron requires Python 3.10+.
uv pip install duron
Quickstart
Duron wraps async orchestration (@duron.durable) and effectful steps (@duron.effect) so complex workflows stay deterministic—even when they touch the outside world.
import asyncio
import random
from pathlib import Path
import duron
from duron.contrib.storage import FileLogStorage
# Effects encapsulate side effects (I/O, randomness, API calls)
@duron.effect
async def work(name: str) -> str:
print("⚡ Preparing to greet...")
await asyncio.sleep(2)
print("⚡ Greeting...")
return f"Hello, {name}!"
@duron.effect
async def generate_lucky_number() -> int:
print("⚡ Generating lucky number...")
await asyncio.sleep(1)
return random.randint(1, 100)
# Durable functions orchestrate workflow logic via ctx.run()
# They're deterministically replayed from logs on resume
@duron.durable
async def greeting_flow(ctx: duron.Context, name: str) -> str:
# Run effects concurrently - results are logged for replay
message, lucky_number = await asyncio.gather(
ctx.run(work, name),
ctx.run(generate_lucky_number),
)
return f"{message} Your lucky number is {lucky_number}."
async def main():
# Session manages execution and log storage
async with duron.Session(FileLogStorage(Path("log.jsonl"))) as session:
# Starts new workflow or resumes from existing log
task = await session.start(greeting_flow, "Alice")
result = await task.result()
print(result)
if __name__ == "__main__":
asyncio.run(main())
Next steps
- Read the getting started guide
- Explore a more advanced example with streams and signals: examples/agent.py
Project details
Release history Release notifications | RSS feed
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 duron-0.0.2.tar.gz.
File metadata
- Download URL: duron-0.0.2.tar.gz
- Upload date:
- Size: 29.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f787a859d85743feef19551e1cb15e3609e8b3311c02d863ca1f8a4f9c0b575
|
|
| MD5 |
1428747199b0874d07bef521a3f08443
|
|
| BLAKE2b-256 |
15952aaf0a16951e320b3b95302057707e3bdc8a4b6559898eab6bbc1fb9a1e6
|
File details
Details for the file duron-0.0.2-py3-none-any.whl.
File metadata
- Download URL: duron-0.0.2-py3-none-any.whl
- Upload date:
- Size: 41.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b227e2db7fd87355ab1d70db96bc0e6463f326b3aed51e5d7dcb3c07e0fe66d9
|
|
| MD5 |
0f80006fa2badf3551f8e77974c15a84
|
|
| BLAKE2b-256 |
5282c2c2b78942fbad76a4de9cd855a4ef096b7542a2be5ce05a94d9e9d2829a
|