---
{
  "id": "platform.workflow.branching-loops-and-sleep",
  "topic": "workflow",
  "title": "Workflow branches, loops, and Sleep rhythm",
  "locale": "en",
  "version": "2026-08-09",
  "summary": "Use ordered next arrays for sequential fan-out, understand no-barrier diamonds, and pace bounded polling loops with Sleep.",
  "content": "A step's `next` array queues each target exactly once in array order after that step completes. Phase 2 executes the queue as sequential breadth-first search; branches do not run in parallel. A diamond such as A → (B, C) → D has no join or barrier, so D runs twice—once for B's traversal and once for C's. Use separate downstream steps when duplicate side effects would be unsafe. A failing Delivery step fails the entire run, and inside a loop each iteration independently queues and charges a delivery. A `notify` step is the opposite reliability boundary: persistence or push failure never fails the run.\n\nBack edges and self-loops are valid. Every visit is a new zero-based `iteration`, and `{{steps.X.output}}` always reads X's latest completed iteration. For polling, route work through a Sleep step with `seconds` from 1 through 3600 before returning to the poll step. Sleep creates its own visible step run, checks cancellation at least every five seconds, and stops at the workflow deadline. A run that reaches its maximum duration is an expected neutral outcome for deliberately long polling, not necessarily a workflow design failure.\n\nSet `maxVisitsPerStep` from 1 through 1000; its default is 25. When a step has already executed that many times, the incoming traversal is dropped, a run-level notice is recorded, and other queued branches continue. A run completes when the queue drains, including after visit-fuse drops. `maxDurationSeconds` and manual cancellation are independent safeguards. Keep `graph.layout` untouched because it is opaque UI metadata. The live Action schema and run detail are authoritative for fields, status, iterations, and notices.\n",
  "aliases": [
    "workflow branching",
    "fan out workflow",
    "workflow loop",
    "polling loop",
    "sleep step",
    "max visits per step",
    "diamond workflow",
    "分支流程",
    "迴圈輪詢"
  ],
  "tags": [
    "workflow",
    "branching",
    "loops",
    "sleep",
    "iterations"
  ],
  "relatedActions": [
    "arinova.workflow.create_workflow",
    "arinova.workflow.update_workflow",
    "arinova.workflow.run_workflow",
    "arinova.workflow.get_run",
    "arinova.workflow.cancel_run"
  ],
  "relatedActionPrefixes": [],
  "url": "https://docs.arinova.ai/en/kb/workflow/branching-loops-and-sleep/"
}
---

A step's `next` array queues each target exactly once in array order after that step completes. Phase 2 executes the queue as sequential breadth-first search; branches do not run in parallel. A diamond such as A → (B, C) → D has no join or barrier, so D runs twice—once for B's traversal and once for C's. Use separate downstream steps when duplicate side effects would be unsafe. A failing Delivery step fails the entire run, and inside a loop each iteration independently queues and charges a delivery. A `notify` step is the opposite reliability boundary: persistence or push failure never fails the run.

Back edges and self-loops are valid. Every visit is a new zero-based `iteration`, and `{{steps.X.output}}` always reads X's latest completed iteration. For polling, route work through a Sleep step with `seconds` from 1 through 3600 before returning to the poll step. Sleep creates its own visible step run, checks cancellation at least every five seconds, and stops at the workflow deadline. A run that reaches its maximum duration is an expected neutral outcome for deliberately long polling, not necessarily a workflow design failure.

Set `maxVisitsPerStep` from 1 through 1000; its default is 25. When a step has already executed that many times, the incoming traversal is dropped, a run-level notice is recorded, and other queued branches continue. A run completes when the queue drains, including after visit-fuse drops. `maxDurationSeconds` and manual cancellation are independent safeguards. Keep `graph.layout` untouched because it is opaque UI metadata. The live Action schema and run detail are authoritative for fields, status, iterations, and notices.
