Retry And Compensation
Breyta retry and compensation example for resilient external side-effect workflows.
Quick Answer
Add :retry for transient failures and design explicit compensation for non-recoverable downstream failures.
Keep result shaping in a function step so orchestration remains focused on retries, side-effect ordering, and labeled branches.
Use Case
Handle unreliable external calls and rollback side effects on failure.
Full Definition
{:slug :retry-compensation
:name "Retry And Compensation"
:concurrency {:type :singleton :on-new-version :supersede}
:requires [{:slot :billing
:type :http-api
:label "Billing API"
:base-url "https://api.example.com"
:auth {:type :bearer}}]
:functions [{:id :build-summary
:language :clojure
:code "(fn [input] {:charge (:charge input) :receipt (:receipt input)})"}]
:triggers [{:type :manual :label "Run" :enabled true :config {}}]
:flow
'(let [input (flow/input)
charge (flow/step :http :create-charge
{:connection :billing
:method :post
:path "/charges"
:body {:customer-id (:customer-id input)
:amount-cents (:amount-cents input)}
:retry {:max-attempts 3 :backoff-ms 1000}})
receipt ^{:label "Receipt dispatch"
:yes "Send receipt"
:no "Skip receipt"}
(if (not (:skip-receipt? input))
(flow/step :http :send-receipt
{:connection :billing
:method :post
:path "/receipts"
:body {:charge-id (:id charge)}})
{:status :skipped :reason :skip-receipt})
summary (flow/step :function :summarize-result
{:ref :build-summary
:input {:charge charge
:receipt receipt}})]
summary)}
Compensation Pattern
If send-receipt fails permanently, add a compensating step to cancel/refund charge in your failure branch.
- add compensation when side effects are partially committed and invariants require rollback
- target retries at transient network/upstream instability, not deterministic validation/auth failures