Workflow

A durable multi-step pipeline composed from the queue and KV primitives. Run state lives in KV; the queue carries { runId, step } pointers. Each worker delivery advances exactly one step and enqueues the next (paced 2s apart), so a run survives isolate restarts and every transition is observable. The stepper below is kept live by polling a JSON status endpoint (~1.2s), with a toast on each step & completion.

Tip
The 2s delay between steps is intentional (third argument to queuePush). In production use it to space out rate-limited third-party API calls, or drop it for maximum throughput.

Start a run

pipeline: validatechargeshipnotify

Runs (0)

no runs yet — start one above.

src/app/api/workflow/jobs/route.tsTypeScript
// src/app/api/workflow/jobs/route.ts
// A durable multi-step pipeline on top of queue + KV.
// The worker advances ONE step per delivery, then enqueues the next.
export async function POST(req) {
  const { payload: { runId, step } } = await req.json();
  const run = await kvGet("run:" + runId);
  run.steps[step].status = "done";
  if (step + 1 < STEPS.length) {
    run.steps[step + 1].status = "running";
    await kvSet("run:" + runId, run);
    await queuePush("demo-flow", { runId, step: step + 1 }, 2); // 2s pacing
  } else {
    run.status = "completed";
    await kvSet("run:" + runId, run);
  }
  return Response.json({ ok: true });
}

// src/app/api/workflow/status/route.ts — snapshot the page polls ~1.2s:
// returns { runs: Run[] }; the page re-renders steppers in place and
// toasts each transition by diffing against the previous snapshot.
setInterval(async function () {
  var runs = (await (await fetch("/api/workflow/status")).json()).runs || [];
  renderRuns(runs);
  runs.forEach(diffAndToast); // "✓ charge", "order completed", ...
}, 1200);