Write steps as code
No DSL, no YAML, no state machine diagrams. A workflow is a function; a step is a call.
await hop.step("charge_card",
() => stripe.charge(order));
await hop.sleep("cooloff", "30d");Rockets blow up on the pad. Workers die mid-payment. Write your steps as ordinary code and Hopskip journals every one, so when the process craters, the work walks away and finishes somewhere else. Nothing charged twice. Nothing left half-done.
go on. it's insured.
THE PROBLEM
A queue can deliver a message. It cannot tell you which business steps already succeeded, whether a retry is safe, or how to continue after a deploy. Soon the process is scattered across workers, retry loops, status tables, cron jobs, and recovery scripts, with the important state living in the gaps between them.
Hopskip keeps the process and its progress together. That is durable execution: application code that can stop, wait, fail, and continue without forgetting where it was.
No DSL, no YAML, no state machine diagrams. A workflow is a function; a step is a call.
await hop.step("charge_card",
() => stripe.charge(order));
await hop.sleep("cooloff", "30d");Each completed step commits a frame to the journal. The worker holds nothing that matters.
When a worker dies, another one replays the journal, skips committed steps, and picks up mid-process.
worker_03 ✗ SIGKILL @ frame 1
journal → replay 1 frame
worker_07 ✓ resumed, attempt 2
WHERE IT EARNS ITS KEEP
Charge once, exactly once, even when the process dies mid-capture.
authorize → capture → invoice → dunning(30d)Inventory, carrier, tracking, refund windows, a week-long process in one function.
reserve → charge → ship → sleep(7d) → closeDrip sequences and trials that survive every deploy between day 0 and day 30.
welcome → sleep(3d) → nudge → convertExtract, transform, load, and re-run from the failed step, not from zero.
extract → transform → validate → load → verify