Use durable state
Install the pre-release Microsoft.Orleans.Journaling package in the silo project. Install a journal storage provider and configure it before activating a DurableGrain.
All Journaling APIs are experimental and carry diagnostic ORLEANSEXP005.
Define a durable grain
Section titled “Define a durable grain”Inject durable states with FromKeyedServicesAttribute. The service key becomes the state’s stable name in the grain journal:
public sealed class ShoppingCartGrain( [FromKeyedServices("cart-items")] Orleans.Journaling.IDurableDictionary<string, int> items) : Orleans.Journaling.DurableGrain, IShoppingCartGrain{ public async ValueTask AddItem(string itemId, int quantity) { items[itemId] = quantity; await WriteStateAsync(); }
public ValueTask<IReadOnlyDictionary<string, int>> GetItems() => ValueTask.FromResult<IReadOnlyDictionary<string, int>>( new Dictionary<string, int>(items));}The dictionary mutation is immediately visible to the current activation. Awaiting WriteStateAsync establishes the durability point for every pending durable-state mutation on that grain.
Select a state type
Section titled “Select a state type”| State type | In-memory API | Journaled operations |
|---|---|---|
| IDurableValue<T> | One mutable value | Set |
| IDurableDictionary<T, U> | IDictionary<T, U> | Set, remove, clear, snapshot |
| IDurableList<T> | IList<T> plus AddRange | Add, insert, set, remove, clear, snapshot |
| IDurableQueue<T> | Queue operations | Enqueue, dequeue, clear, snapshot |
| IDurableSet<T> | ISet<T> | Add, remove, clear, snapshot |
| IDurableTaskCompletionSource<T> | Durable task completion | Complete, fault, or cancel |
| IPersistentState<T> | Record-style state | Set or clear a versioned state value |
All named states in one grain share the grain’s journal and participate in the same write. This makes a single WriteStateAsync the atomic storage boundary for their pending changes. Coordination with another grain or an external service requires an application protocol such as idempotency, an inbox, or an outbox.
An IDurableTaskCompletionSource<T> changes status in memory when TrySetResult, TrySetException, or TrySetCanceled succeeds. Its Task completes after a write acknowledges that status or recovery replays it, allowing waiters to observe a durable completion.
Keep state names and schemas stable
Section titled “Keep state names and schemas stable”The keyed service name identifies a durable state across activations and deployments. Apply these rules:
- Keep each name unique within the grain.
- Preserve names when changing constructors or refactoring fields.
- Keep JSON key, value, and record schemas backward readable during rolling upgrades.
- Register every JSON payload type in the configured source-generated serializer context when trimming or using Native AOT.
- Retain removed state definitions through the retirement grace period when a rollback can reintroduce them.
Registering two states with the same name fails activation. Registering a state after activation setup also fails because recovery has already assigned journal stream identities.
Use journal-backed persistent state
Section titled “Use journal-backed persistent state”Journaling registers keyed IPersistentState<T> services. Its familiar State, WriteStateAsync, and ClearStateAsync members write through the same journal manager as the durable collections. ReadStateAsync completes from the already-recovered in-memory state because activation setup replayed the grain journal.
Use a unique keyed service name exactly as you would for another durable state. The ETag is the journal-backed state’s recovered version and RecordExists indicates whether a stored value is present.
Implement a custom journaled state
Section titled “Implement a custom journaled state”Advanced integrations can implement IJournaledState and register it with IJournaledStateManager. The implementation owns its operation codec, snapshot representation, replay logic, deep-copy behavior, and volatile bookkeeping.
An implementation runs on one logical grain thread. It applies mutations in memory, writes recoverable operations, and uses OnWriteCompleted for behavior that must follow storage acknowledgement. Its Reset and replay methods must rebuild all state after a failed write or activation recovery.
