Reference

flow/poll

Canonical reference for flow/poll: bounded polling loops for external async work using deterministic orchestration helpers.

Quick Answer

Use flow/poll when you need to repeatedly check external job status. Always bound it with :timeout or :max-attempts, and define success with :return-on.

When To Use

ScenarioWhy flow/poll fits
You start a remote job and must check status until completion.Encodes bounded retry loop with clear completion criteria.
Readiness is determined by response fields, not callback push.Keeps polling logic in one deterministic config map.
You need deterministic retry/backoff without hand-written loop boilerplate.Uses first-class bounds/backoff and standardized semantics.

Prefer :wait when an external actor pushes a callback/signal (human approvals, webhook completions).

Config Shape

flow/poll requires a literal config map.

(flow/poll
  {:interval "10s"
   :timeout "20m" ;; or :max-attempts
   :backoff {:type :exponential :factor 2 :max "2m"}
   :abort-on {:status #{400 401 403} :error? true}
   :return-on (fn [result] (= :completed (:status result)))
   :id :order-status-poll-sleep}
  (flow/step :http :fetch-job-status
    {:connection :jobs-api
     :method :get
     :path (str "/jobs/" job-id)}))

Important fields:

FieldRequiredMeaning
:intervalYesPoll interval ("10s" style duration or milliseconds).
:timeoutConditionallyDuration/ms timeout cap.
:max-attemptsConditionallyAttempt cap.
:timeout or :max-attemptsAt least oneAt least one bound is required.
:return-onYesPredicate function/symbol for success completion.
:abort-onNoStop condition for statuses/errors.
:backoffNoInterval progression (:constant, :linear, :exponential).
:idNoStable generated sleep step id label.

High-Level Implementation Model

flow/poll is expanded before execution into ordinary orchestration primitives:

Runtime behaviorPrimitive
Capture poll start timeflow/now-ms
Track attemptsloop / recur
Execute poll bodynormal flow/step body
Evaluate completion condition:return-on predicate
Apply stop rulesabort conditions + bounds
Sleep between attemptsflow/step :sleep
Compute next intervalflow/backoff
Enforce timeoutflow/elapsed?

Practical implication: you get a reusable polling primitive built from the same deterministic constructs you use directly.

Advanced Pattern: Poll + Persist + Compact Output

'(let [input (flow/input)
       started (flow/step :http :start-export
                 {:connection :reports-api
                  :method :post
                  :path "/exports"
                  :json {:account-id (:account-id input)}})
       job-id (:job-id started)
       final-status ^{:label "Wait for export completion"}
                    (flow/poll
                      {:interval "5s"
                       :timeout "15m"
                       :backoff {:type :exponential :factor 1.5 :max "60s"}
                       :abort-on {:status #{400 404 500} :error? true}
                       :return-on (fn [r] (= :completed (:status r)))
                       :id :export-status-sleep}
                      (flow/step :http :get-export-status
                        {:connection :reports-api
                         :method :get
                         :path (str "/exports/" job-id)}))
       artifact (flow/step :function :persist-export-status
                  {:input final-status
                   :persist {:type :blob}})]
   {:job-id job-id
    :status (:status final-status)
    :status-ref (:ref artifact)})

This keeps orchestration clear and avoids large inline payloads while polling.

Using Implicit Flow Context In Custom Patterns

flow/poll body runs inside your flow orchestration context, so it can safely use:

Context sourceTypical use
Previously bound let valuesReuse ids, cursors, and guard flags.
Connection/binding-driven configsKeep auth/routing in profile bindings.
Deterministic helper outputsReuse flow/now-ms, persisted refs, and stable keys.

Patterns that work well:

PatternShape
Staged pollingFast initial poll, then slower secondary poll branch.
Status-class routingPoll to terminal status, then branch with labeled if/cond.
Child-flow health pollingflow/call-flow + status poll in parent orchestrator.

Validation Rules You Should Expect

RuleValidation expectation
Config shapeMust be a literal map.
:return-onRequired and must be function/symbol.
:timeoutMust parse as duration/ms when provided.
Linear backoff:backoff {:type :linear} requires :step.
Bounded executionAt least one bound is required (:timeout or :max-attempts).

See platform caps in Limits And Recovery.

Related

As of Feb 13, 2026