Durable · Deterministic · Workflows

Durable background work, in plain async Python.

Write workflows as regular code. Waymark compiles them to a deterministic program and runs it on a durable, interruptible VM backed by Postgres. Survives restarts, crashes, and hour-long sleeps. No broker, no replay, no missed errors.

charge_workflow.pypython
import asyncio
from waymark import Workflow, action, workflow
 
@action
async def charge(order_id: int) -> bool:
return await payments.charge(order_id)
 
@workflow
class Checkout(Workflow):
async def run(self, order_id: int) -> str:
for _ in range(3):
if await charge(order_id):
return "paid"
# durable: survives restarts
await asyncio.sleep(3600)
return "failed"
§ 01 · Durable execution

Write your backend logic as one natural function. That's durable execution.

Plenty of backend work isn't a single request. It's a sequence: charge a card, wait for confirmation, email a receipt, retry on failure, follow up next week. The old way is to chop that into queued jobs and hand-roll the state that connects them. Durable execution flips it. You write the whole flow as one ordinary function, and the engine remembers where it is, so crashes, restarts, and hour-long waits simply resume.

Waymark is durable execution that's easy to live with. It compiles your workflow instead of replaying it, so determinism is verified up front (no runtime surprises) and execution is faster. And it lives on the Postgres you already have, with no broker to host and tune.

Workflows· control flow

Your async def, made durable

The run() method is compiled and verified up front. Loops, branches, parallel gather, and sleeps that outlive a restart.

Actions· the work

Plain functions, sent to workers

Each @action is dispatched to a worker, with retries and timeouts you set per call and arguments validated on the way in.

01 · No surprise errors

If it compiles, it runs as advertised.

Waymark verifies your workflow when you register it. Nondeterministic calls like datetime.now() or uuid4() are rejected up front with a clear fix: move them into an @action. The determinism bugs that usually surface in production fail at your desk instead.

02 · No replay

Resumes without re-running a thing.

Your workflow code never re-executes. Unlike replay-based engines, Waymark persists just the state it needs at each step and resumes from there, so completed work is never recomputed. Survives restarts, crashes, and hour-long sleeps.

03 · Plain async Python

Real control flow, no DSL.

Loops, conditionals, try/except, parallel asyncio.gather. You write ordinary async Python, not YAML or a graph by hand, and the same code runs locally and in production.

04 · Just Postgres

No broker, no second system.

No Redis, no hosted queue, no extra service to deploy and babysit. Waymark runs on the Postgres you already have, driven by a Rust runtime that handles the queueing and scheduling for you.

05 · Management dashboard

See every run, live.

A beautiful web dashboard ships in the box. Watch workflows progress in real time, search through run history, and drill into any action to see its inputs, retries, and output. Nothing extra to wire up.

For Python teams

When a cron job isn't enough.

The job grows. It needs steps, retries, a parallel fan-out, a sleep that outlives a deploy. Waymark gets you there in plain async Python, on the Postgres you already run.

quickstartshell
$ uv add waymark
$ export WAYMARK_DATABASE_URL=...
$ uv run waymark-start-workers
workers ready, queue a workflow
One package, just Postgres

Add it and go.

Waymark ships as a single Python package and runs on the Postgres you already have. Point the workers at your database, queue a workflow, and it runs durably across your cluster.

Make your background jobs unbreakable.

Plain async Python, durable on the Postgres you already run.