Distributed-transaction-style workflows ("book flight, charge card, email confirmation, on failure roll back") map naturally to actors but writing the orchestration by hand is repetitive. Saga is the standard pattern: a list of steps, each with an explicit compensation action that runs on failure.
API sketch:
```ts
const result = await Saga.run([
{
do: async () => bookingActor.tell({ kind: 'reserve', flightId }),
compensate: async () => bookingActor.tell({ kind: 'release', flightId }),
},
{
do: async () => paymentActor.tell({ kind: 'charge', amount }),
compensate: async () => paymentActor.tell({ kind: 'refund', amount }),
},
{
do: async () => emailActor.tell({ kind: 'send', template: 'confirmation' }),
// no compensation — emails can't be unsent, but step 3 is the last one anyway
},
]);
```
Scope:
- `Saga.run(steps, opts?)`: runs steps in order; on failure, runs `compensate` of all completed steps in reverse.
- `opts.persistenceId?` enables crash-safe sagas — write each step's status to a journal so a restart resumes from where it stopped.
- Built on top of `PersistentActor` when persistenceId is set; pure in-memory otherwise.
Out of scope:
- Cross-process saga coordination (saga lives in one actor; the steps it triggers can be cluster-wide).
- Long-running (> hours) sagas with state that lives in DD — separate issue if needed.
Estimate: 4-5 days.
Distributed-transaction-style workflows ("book flight, charge card, email confirmation, on failure roll back") map naturally to actors but writing the orchestration by hand is repetitive. Saga is the standard pattern: a list of steps, each with an explicit compensation action that runs on failure.
API sketch:
```ts
const result = await Saga.run([
{
do: async () => bookingActor.tell({ kind: 'reserve', flightId }),
compensate: async () => bookingActor.tell({ kind: 'release', flightId }),
},
{
do: async () => paymentActor.tell({ kind: 'charge', amount }),
compensate: async () => paymentActor.tell({ kind: 'refund', amount }),
},
{
do: async () => emailActor.tell({ kind: 'send', template: 'confirmation' }),
// no compensation — emails can't be unsent, but step 3 is the last one anyway
},
]);
```
Scope:
Out of scope:
Estimate: 4-5 days.