Skip to main content

Workflow patterns

Common durable workflow patterns supported by Catalyst Workflows (built on Dapr Workflow):

Task chaining

Execute a sequence of activities in order, passing output from one step to the next. If any step fails, the workflow retries it from that step — earlier steps are not re-executed.

Fan-out / Fan-in

Spawn multiple activity instances in parallel, then aggregate their results once all complete. Catalyst Workflows tracks each branch independently and resumes the aggregation step only after all branches succeed.

Async HTTP (polling consumer)

Start a long-running task, return an HTTP 202 to the caller immediately, then expose a status endpoint the caller can poll. The workflow runs durably in the background regardless of how long the task takes.

Monitor

A loop that wakes periodically (using a durable timer), checks an external condition, and sends a notification or raises an event when the condition is met. The timer survives process restarts.

External events / Human-in-the-loop

Pause execution at a step that waits for an external event — an approval, a webhook callback, or a manual signal. The workflow remains durable while waiting; you can raise the event from the CLI or the console.

The example below shows a request-escalation workflow: orders under $1,000 are auto-approved; larger orders wait for a human approval event with a 7-day timeout.

@wfr.workflow(name="request_escalation")
def request_escalation_workflow(ctx: DaprWorkflowContext, order_str: str):
order = json.loads(order_str) if isinstance(order_str, str) else order_str
amount = order.get("amount", 0)

# Auto-approve orders under $1000
if amount < 1000:
yield ctx.call_activity(auto_approve_activity, input=order)
return

# Orders $1000+ require human approval (7 days max)
approval_event = ctx.wait_for_external_event("human_approval")
timeout = ctx.create_timer(timedelta(days=7))
winner = yield when_any([approval_event, timeout])

if winner == timeout:
yield ctx.call_activity(handle_timeout_activity, input=order)
return

approval_result = approval_event.get_result()
yield ctx.call_activity(process_approval_activity, input=approval_result)

Raise the event from the CLI once the approval is ready:

diagrid workflow raise-event --app-id my-workflow-app \
--instance-id <id> --event-name human_approval --event-data '{"approved": true}'