Skip to content
Pyrula
Pre-release: the packages are not on PyPI yet, so pip install does not resolve. Build from source to try it today.

Workers

In separate mode the API submits and streams, and worker processes do the actual execution. PyrulaWorker is that worker tier. It claims turns from the shared store, runs them, and handles timers, signals, orphan recovery, and poison turns.

from pyrula.agents import PyrulaWorker
from pyrula.agents.llm import OpenAILLM
worker = PyrulaWorker(
agents=[support], # or omit for the registry
store="redis://localhost:6379",
llm=OpenAILLM(model="gpt-4o-mini"),
concurrency=50,
)
worker.run()

store takes a Valkey or Redis URL (or a store instance). The worker and the API must point at the same store. run() blocks; run_async() is the awaitable version for an existing event loop.

Pass a WorkerOptions for the runtime knobs:

from pyrula.agents import WorkerOptions, PoisonOptions
WorkerOptions(
max_concurrent_turns=50,
orphan_scan_interval=60.0,
timer_poll_interval_s=5.0,
schedule_poll_interval_s=30.0,
poison=PoisonOptions(max_retries=3, retry_ttl_s=3600.0),
)

A turn that keeps crashing the worker is retried up to PoisonOptions.max_retries. After that it’s quarantined: the worker writes run:error with a poison reason and moves on, so one bad turn can’t wedge the tier. Quarantined turns show up as RunStatus.quarantined.

If a worker dies mid-turn, another worker claims the turn during its orphan scan and resumes it from the first unfinished step. Sleeping and signal-waiting turns aren’t treated as orphans; they wake on their own schedule. This is the engine’s replay and recovery in production.

Sharding works as it does for workflows: a crashed worker’s queued turns are picked up right away by other workers, its in-flight turns recover on the orphan scan, and a clean worker.stop() releases its shards immediately. See Scaling across shards.

PyrulaWorker(store="redis://...") builds a default ValkeyStore. Pass a ValkeyStore(shard_count=..., cluster=...) to configure sharding or a cluster. The agents PostgresStore takes the same shard_count, shard_lease_ttl and cluster for its live Valkey tier, plus live_ttl_after_archive (default 300 s).