Orchestration
Declarative processes
Model long-running business flows without giving domain code an infrastructure API.
Read it like the business describes it
public static Process OrderFulfillment => Process
.StartOn<OrderPlaced>(e => e.OrderId)
.Then(Stock.Reserve).Retry(5.Times).Undo(Stock.Release)
.Then(Payments.Charge).Retry(5.Times, Backoff.Exponential).Undo(Payments.Refund)
.Await<PaymentConfirmed>(e => e.OrderId).Within(15.Minutes)
.Then(Shipping.Ship).Retry(5.Times)
.OnCompensated(Orders.Cancel).Retry(5.Times);What the runtime guarantees
- Each envelope is handled as one atomic change set.
- Retries retain stable message identities and follow declared backoff.
- Completed steps compensate in reverse order after a rejection. Exhausted step retries suspend the instance with a reason instead;
.OrCompensate()opts into compensating. - A step given up on with an unknown outcome is fenced by its undo: a late copy of it never executes.
- Early awaited events are parked until the process reaches the matching await.
- Timeouts use the runtime clock; tests advance it without sleeping.
Retries, undos and suspension
Every step states its own retry policy: .Retry(attempts, backoff) or .NoRetry("why"). There is no default, and analyzer WYRD0014 reports a step that declares neither. Implemented
An undo does not inherit its step's retries. Undos and the outcome command always insist: 10 retries with exponential backoff (waits capped at one minute) by default, adjustable with .Undo(command, 20.Times) and impossible to disable. Implemented
When a step's retries are exhausted, or an undo or the outcome gives up, the instance becomes Suspended with a reason (ReasonOf). An operator calls ResumeAsync or CompensateAsync, and a late success resumes it on its own. .Retry(3.Times).OrCompensate() opts a step into compensating instead. Implemented The rules and the reasons are in How Wyrd behaves and Design decisions.
Observe the exact history
[00:00:00] OrderFulfillment A-1005 started by OrderPlaced
[00:00:00] OrderFulfillment A-1005 -> ReserveStock
[00:00:00] OrderFulfillment A-1005 ok StockReserved
[00:00:00] OrderFulfillment A-1005 -> ChargePayment
[00:00:00] OrderFulfillment A-1005 ok PaymentCharged
[00:00:00] OrderFulfillment A-1005 awaiting PaymentConfirmed (within 15m)
[00:15:00] OrderFulfillment A-1005 timeout: PaymentConfirmed not received in time
[00:15:00] OrderFulfillment A-1005 compensating
[00:15:00] OrderFulfillment A-1005 -> RefundPayment
[00:15:00] OrderFulfillment A-1005 ok PaymentRefunded
[00:15:00] OrderFulfillment A-1005 -> ReleaseStock
[00:15:00] OrderFulfillment A-1005 ok StockReleased
[00:15:00] OrderFulfillment A-1005 compensated