Waiting and Polling
Three constructs suspend a run: wait for an elapsed duration, wait_for for an external event, and repeat for a bounded poll.
wait suspends the run for a duration, or until an instant. Exactly one of for or until is present, and either can be an expression. Implementations MUST NOT hold a process open while a run is suspended, here or in wait_for.
- cooling_off: wait: { for: 2d }
- day_before: wait: { until: "{{ hire.start_date | minus(1d) }}" }wait_for
Section titled “wait_for”wait_for suspends the run until an external event arrives, or until the timeout elapses.
- ask: slack.post: { channel: "#sales-ops", text: "Approve {{ deal.name }}?" }
- approval: wait_for: slack.approval match: { message: "{{ ask.ts }}" } timeout: 24htimeout is REQUIRED, and is a key of the construct rather than a step modifier. A wait_for binds a scope with two members.
| Path | Type | Meaning |
|---|---|---|
status |
enum[received, timeout] |
Whether an event arrived before the timeout elapsed. |
event |
object? |
The event payload, or null when status is timeout. |
A timeout is not a failure. The run continues at the next step, and the author branches on status.
An arriving event reaches a suspended run by correlation:
- the event’s manifest declares the correlation keys in
correlate_on; - the waiting step supplies the expected value of each key in
match; - implementations MUST deliver an event only to a run whose supplied values match.
A wait_for that omits a value for a declared correlation key is a validation error. match selects which event may reach the run, and creates no binding.
repeat
Section titled “repeat”repeat is bounded polling. max is required.
- indexed: repeat: { every: 30s, max: 20, until: "{{ check.status == 'indexed' }}" } steps: - check: { search.status: { id: "{{ ticket.id }}" } }repeat binds its id to a list of iteration scopes, indexed by position, as for_each does. Each iteration creates a scope, and no binding crosses from one iteration to the next.
The first iteration runs immediately. Implementations MUST wait every before each later iteration. Implementations MUST evaluate until after each iteration completes, in that iteration’s scope, so {{ check.status }} names the just-completed iteration’s check step.
repeat completes successfully when until is true. When max iterations complete and until is still false, the step fails. That failure is an ordinary step failure, so optional and scope recovery apply to it.
max MUST be a positive integer, and repeat MUST NOT accept unbounded. max is what proves that a polling loop terminates.