Skip to content
Pyrula

Runs as Event Streams

A run of a @workflow is one append-only stream of events in the store. The same stream does two jobs: it’s the log a worker replays to recover, and it’s the feed a client reads to follow the run live.

There’s one source of truth. If a secondary index ever disagrees with the stream, the stream wins.

Events are RunEvent records tagged with an EventKind. Lifecycle kinds describe the run; step kinds describe individual durable operations.

from pyrula.workflows import RunEvent, EventKind, RunStatus
GroupKinds
Lifecyclerun:init, run:complete, run:error, run:interrupted, run:resumed, run:sleeping, run:woken, run:signal_waiting, run:signal_received
Stepstep:pending, step:done, step:error
Internalheartbeat, stream:overflow

You don’t track status by hand. RunStatus is derived from the stream: pending, in_progress, complete, cancelled, error, quarantined, interrupted, sleeping, signal_waiting.

An ordered, append-only log means any worker can rebuild the exact in-memory state of a run by reading it from the start. No separate snapshot, no checkpoint format to keep in sync. That property is what makes replay work.