Atomic Writes
This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at README.md, and llms.txt lists every page.What it shows
ILattice.SetManyAtomicAsync commits a batch of key-value pairs all-or-nothing:
either every key in the batch becomes visible together, or - on failure or a
failed guard - nothing is committed and every key keeps its pre-batch value. This
sample commits a successful batch, then runs a guarded batch whose precondition
fails to prove no partial state leaks, re-runs it with a guard every key
satisfies so it commits in full, and finally uses the
IGrainFactory.SetManyAtomicAsync overload to flip keys across two separate
trees as one unit.
Run it
dotnet run --project samples/AtomicWrites
Expected output
== AtomicWrites sample ==
1) Committing a 3-key shipment batch atomically...
order:42/status = shipped
order:42/tracking = 1Z999
customer:alice/last-order = 42
-> all three keys are visible together.
2) Seeded order:1=120, order:2=80.
Guard 'current.Total >= 100' outcome: PreconditionFailed
order:1 = 120, order:2 = 80
-> both keys keep their ORIGINAL totals: no partial write leaked.
3) Guard 'current.Total > 0' outcome: Committed
order:1 = 999, order:2 = 5
-> both keys now hold the new totals: the batch committed as a unit.
4) Committing a batch spanning 'orders-east' and 'inventory'...
Cross-tree outcome: Committed
orders-east/order:42/status = fulfilled
inventory/sku:99/reserved = 0
-> keys on both trees flipped together.
Done.
When to use
- A multi-key change must be all-or-nothing (a shipment record, a re-key move, a guarded conditional update) and a reader must never see it half-applied.
- You need a precondition checked against the current stored values before the
batch commits (the predicate overload), or a batch that spans two or more
trees (the
IGrainFactoryoverload).
When not to use
- The hot write path where raw throughput matters. Atomic writes coordinate
across keys via a saga, which is more expensive than a plain
SetAsyncor the non-atomicSetManyAsync. Reach for atomicity only where the all-or-nothing guarantee is actually required.