Deployment Modes
Two deployment modes:
Embedded
Section titled “Embedded”EMBEDDED runs execution in the same process that submits the run. Fine for local
dev, tests, and small deployments. InlineWorkflowRunner is the in-process driver:
from pyrula.workflows import InlineWorkflowRunner, MemoryStore
runner = InlineWorkflowRunner(store=MemoryStore())run_id = runner.submit("my_workflow", params={"x": 1})events = await runner.run("my_workflow", run_id)Separate
Section titled “Separate”SEPARATE splits the two halves. One tier submits and follows runs. Worker processes
claim and execute them against the same shared store. Use it when you want to scale
execution independently or isolate it from the request path.
Either way, durability comes from the run’s event stream in the shared store. The mode only changes where execution happens, not the recovery guarantees.
pyrula.workflows ships WorkflowWorker for the worker tier, with no agent
runtime required. Point it at a durable store and call run():
import asynciofrom pyrula.workflows import WorkflowWorker, ValkeyStore
worker = WorkflowWorker(store=ValkeyStore(url="redis://localhost:6379"))
asyncio.run(worker.run())The worker discovers all @workflow-decorated functions automatically. Pass
workflows=[my_workflow] to restrict it to a specific set.
Stores and the durability boundary
Section titled “Stores and the durability boundary”MemoryStore is in-process only — for dev and tests. The two production stores
differ in exactly one way that matters for durability:
-
ValkeyStoreholds the entire live run in Valkey: the event stream plus run lifecycle/owner, idempotency keys, signals, timers, and KV. Everything is Valkey-durable, and completed runs expire aftercompleted_ttl. If you lose Valkey, you lose runs — so run Valkey with persistence (AOF) and/or replication. -
PostgresStorewraps aValkeyStoreand adds one thing: when a run reaches a terminal event, its full event stream is archived to Postgres, so a completed run survives pastcompleted_ttland beyond Valkey. Everything else still lives only in Valkey. Concretely: while a run is in flight — and for all of its lifecycle/owner state, idempotency keys, signals, timers, and KV even after completion — Postgres has nothing; that state is Valkey-durable only and expires withcompleted_ttl. Postgres is a completed-run archive, not a second live copy.
So “durable” means Valkey-durable for live execution and all auxiliary state, plus a Postgres archive of completed event logs. Size Valkey’s durability (persistence/replication) for your in-flight runs accordingly; Postgres protects history, not work in progress. Archival is reconciled in the background, so a transient Postgres outage during completion is retried rather than lost.
Serving runs over HTTP is part of the Agents runtime.