Configuration
This page documents Orleans.Lattice.Storage.AzureTable 9.9.0, in 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 configuration.md, and llms.txt lists every page.This document covers AzureTableWalStorageOptions, the public configuration surface for Orleans.Lattice.Storage.AzureTable. Register the provider with AddAzureTableWalStorage; see API Reference for public types and Architecture for behavioural details.
Registering the provider
using Orleans.Lattice.Storage.AzureTable;
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ConnectionString = "UseDevelopmentStorage=true";
o.TableName = "OrleansLatticeWal";
});
Each registration must configure exactly one authentication mode. The connection-string form above is one option; the three registrations below show the other mutually exclusive alternatives - pick whichever one matches your deployment, not more than one:
using Azure.Core;
using Azure.Data.Tables;
using Orleans.Lattice.Storage.AzureTable;
TokenCredential tokenCredential = null!;
TableSharedKeyCredential sharedKeyCredential = null!;
TableServiceClient serviceClient = null!;
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ServiceUri = new Uri("https://account.table.core.windows.net");
o.TokenCredential = tokenCredential;
});
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ServiceUri = new Uri("https://account.table.core.windows.net");
o.SharedKeyCredential = sharedKeyCredential;
});
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ServiceClient = serviceClient;
});
Options Reference - AzureTableWalStorageOptions
Authentication and client
| Option | Type | Default |
|---|---|---|
ConnectionString |
string? |
null |
ServiceUri |
Uri? |
null |
TokenCredential |
TokenCredential? |
null |
SharedKeyCredential |
TableSharedKeyCredential? |
null |
ServiceClient |
TableServiceClient? |
null |
TableName |
string |
"OrleansLatticeWal" |
ConfigureClientOptions |
Action<TableClientOptions>? |
null |
Retry options
| Option | Type | Default |
|---|---|---|
RetryMaxAttempts |
int? |
null |
RetryDelay |
TimeSpan? |
null |
RetryMaxDelay |
TimeSpan? |
null |
RetryNetworkTimeout |
TimeSpan? |
10 s |
RetryMode |
RetryMode? |
null |
Commit pipeline options
| Option | Type | Default |
|---|---|---|
PipelinePhaseTwoCommits |
bool |
true |
EliminateCandidateRowOnHotPath |
bool |
true |
PipelinedPhaseTwoFaultHandler |
Action<Exception>? |
null |
PhaseTwoCoalescingWindow |
TimeSpan |
5 ms |
PhaseTwoCommitTimeout |
TimeSpan? |
12 seconds |
PhaseOneTransientRetryMaxAttempts |
int |
2 |
PhaseOneTransientRetryBaseDelay |
TimeSpan |
25 ms |
Saturation options
| Option | Type | Default |
|---|---|---|
HonorSaturationSignal |
bool |
true |
SaturationShortCircuitCooldown |
TimeSpan |
2 seconds |
Compression options
| Option | Type | Default |
|---|---|---|
Compression |
LatticeCompression |
Zstd |
CompressionMinPayloadBytes |
int |
256 |
Every non-null default above is also published as a public member of AzureTableWalStorageOptions: the constants DefaultTableName, DefaultPipelinePhaseTwoCommits, DefaultEliminateCandidateRowOnHotPath, DefaultHonorSaturationSignal, DefaultPhaseOneTransientRetryMaxAttempts, DefaultCompression, and DefaultCompressionMinPayloadBytes, and the static readonly TimeSpan fields DefaultRetryNetworkTimeout, DefaultPhaseTwoCoalescingWindow, DefaultPhaseTwoCommitTimeout, DefaultSaturationShortCircuitCooldown, and DefaultPhaseOneTransientRetryBaseDelay. DefaultPhaseOneTransientRetryMaxDelay (250 ms) is not an option's default but the fixed cap on the phase-1 retry backoff.
Option guidance
ConnectionString
Storage account connection string. Use this for Azurite, development, or deployments that manage secrets outside the Azure identity stack. Mutually exclusive with ServiceUri, credentials, and ServiceClient.
ServiceUri
Azure Table service endpoint. Pair it with exactly one credential: TokenCredential or SharedKeyCredential.
TokenCredential
Azure identity credential used with ServiceUri. This is the preferred production shape for managed identity or workload identity.
SharedKeyCredential
Shared-key credential used with ServiceUri. Mutually exclusive with TokenCredential.
ServiceClient
Pre-built TableServiceClient supplied by the host. When set, the provider uses it verbatim. ConfigureClientOptions, retry knobs, and provider-attached Azure SDK policies do not modify the supplied client; the host owns its options, pipeline, and lifetime.
TableName
Azure Table name used for WAL storage. Defaults to AzureTableWalStorageOptions.DefaultTableName. The table is created on first use. Use distinct table names when sharing one storage account across independent Lattice deployments.
ConfigureClientOptions
Callback used only when the provider constructs a TableServiceClient. Retry knobs are applied before this callback, so callback changes have final say. Add custom policies with AddPolicy rather than replacing the whole retry setup unless you intentionally want to own it.
RetryMaxAttempts
Overrides the Azure SDK retry count after the initial attempt. null leaves the SDK default. 0 disables retries. Must be non-negative.
RetryDelay
Overrides the Azure SDK base retry delay. null leaves the SDK default. Must be non-negative and must not exceed RetryMaxDelay when both are set.
RetryMaxDelay
Overrides the Azure SDK maximum retry delay. null leaves the SDK default. Must be non-negative and at least RetryDelay when both are set.
RetryNetworkTimeout
Overrides the Azure SDK per-attempt network timeout. Defaults to 10 s - a finite bound below the WAL flush budget so a stuck request surfaces a fault into the WAL shard's failure handler (which releases and recovers the slot) instead of being abandoned while the transport zombies on for the SDK's unbounded ~100 s default. Set to null to restore the SDK default; must be positive when set. Prevents one stuck request from occupying a WAL slot - and, under a sustained storage brown-out, accumulating into hundreds of zombie attempts that self-sustain the brown-out.
RetryMode
Overrides the Azure SDK retry mode. null leaves the SDK default, usually exponential backoff.
using Azure.Core;
using Orleans.Lattice.Storage.AzureTable;
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ConnectionString = "UseDevelopmentStorage=true";
o.RetryMaxAttempts = 2;
o.RetryDelay = TimeSpan.FromMilliseconds(50);
o.RetryMaxDelay = TimeSpan.FromSeconds(1);
o.RetryNetworkTimeout = TimeSpan.FromSeconds(5);
o.RetryMode = RetryMode.Exponential;
});
PipelinePhaseTwoCommits
When true, the provider can return from an append after the durable entry write and after observing the previous pending completion for the same shard. Each completion commit still writes its pending batches in ascending offset order, and failures remain sticky to a later append or the configured fault handler. Set to false when you want every append to wait for its own completion before returning.
Because the read path is derived from commit metadata, this option introduces a bounded read visibility lag: the trailing batch on a shard is durable when the append returns but is not readable until its completion lands, so a read can omit it. The reported highest offset does not lag - GetHighestOffsetAsync folds the already-durable batches the shard's completion worker has accepted over the stored tail, so it never reports an offset lower than one a completed append returned. Callers that need read-after-write should await the provider's phase-two flush barrier rather than sleeping or polling; see Architecture. Set the option to false if you would rather pay the latency on every append than take a barrier where you need one.
EliminateCandidateRowOnHotPath
When true, the provider removes an extra recovery-marker write from the normal append path. Recovery still detects interrupted batches using stored batch metadata and the committed shard tail. Upgrade from false to true is safe because both recovery shapes are recognized. Before moving from true back to false, drain pending appends and let reconciliation complete on a true deployment.
PipelinedPhaseTwoFaultHandler
Optional observer invoked once for every pipelined completion that faults, whether or not a successor append later observes the same fault, so a fault on a shard that goes idle before a successor append arrives still reaches the application. Because one fault can be reported both here and to that successor, the delegate should be idempotent and observability-only. Exceptions thrown by the delegate are ignored. It is never invoked when PipelinePhaseTwoCommits is false, because every append then observes its own completion.
using Orleans.Lattice.Storage.AzureTable;
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ConnectionString = "UseDevelopmentStorage=true";
o.PipelinedPhaseTwoFaultHandler = static ex => _ = ex.Message;
});
PhaseTwoCoalescingWindow
Maximum wait after the first pending completion arrives so more completions can be coalesced into the same Azure Table transaction. Default is 5 ms. Must be non-negative. Use TimeSpan.Zero to commit as soon as work is available.
PhaseTwoCommitTimeout
Per-commit deadline for the ordered completion transaction. Default is 12 seconds. Set to null to make completion unbounded, or set a positive TimeSpan tuned above the worst commit latency a browned-out account produces and below the silo-level timeout.
The deadline bounds how long the shard waits, not the transaction: on a timeout the waiting batches fail fast, but the abandoned transaction keeps running to a real outcome, because the service may already hold it and can still apply it. The shard's post-failure resync waits for it before reading the log, so the writer never resumes beneath rows that transaction then writes. A transaction still running 60 seconds after it was abandoned is cancelled so the wait stays bounded.
The 12-second default comes from multi-silo real-Azure measurement: one storage account under about 36k keys/s had a 6-9 second latency brown-out in which completion transactions took up to 6 seconds. The former 3-second default tripped on every shard at once and turned that brown-out into a failure storm; with no deadline the same run failed no keys. 12 seconds leaves 2x headroom over that worst case while staying below the 15-second WAL flush timeout and the silo request timeout, so a genuinely wedged shard is still broken.
using Orleans.Lattice.Storage.AzureTable;
var options = new AzureTableWalStorageOptions
{
ConnectionString = "UseDevelopmentStorage=true",
PhaseTwoCommitTimeout = TimeSpan.FromSeconds(30),
};
PhaseOneTransientRetryMaxAttempts
Number of additional in-place retries the provider issues when a phase-1 batch commit faults transiently. Each retry resubmits the byte-identical batch at the same offsets, so an already-durable prior attempt is resolved as an idempotent-replay success and a genuine offset collision still surfaces immediately without retry. Default is 2 (three attempts total); each retry increments orleans.lattice.provider.phase1.transient_retries. Set to 0 to surface every transient fault immediately. This knob is not validated: a negative value is treated as 0.
PhaseOneTransientRetryBaseDelay
Base delay for the jittered backoff between phase-1 transient retries. The wait before the n-th retry (1-based) is a random value in [0, BaseDelay * n), capped at 250 ms (AzureTableWalStorageOptions.DefaultPhaseOneTransientRetryMaxDelay), so multiple hot shards do not retry in lockstep. Default is 25 ms. Set to TimeSpan.Zero to retry without delay. This knob is not validated: a negative value also retries without delay.
HonorSaturationSignal
When true, and when IWalSaturationSignal is registered, the provider attaches SaturationAwareRetryPolicy to clients it constructs. The first attempt reaches the network; retry attempts can short-circuit while aggregate WAL state is saturated. Set to false to leave Azure SDK retries unguarded.
SaturationShortCircuitCooldown
Sticky window after the last saturated observation during which retry attempts continue to short-circuit. Default is 2 seconds. Must be non-negative. Set to TimeSpan.Zero to consult only the present aggregate state.
using Orleans.Lattice.Storage.AzureTable;
var optionsWithCooldownOverride = new AzureTableWalStorageOptions
{
ConnectionString = "UseDevelopmentStorage=true",
HonorSaturationSignal = true,
SaturationShortCircuitCooldown = TimeSpan.FromSeconds(5),
};
Compression
Stored WAL payload compression algorithm. Default is LatticeCompression.Zstd; set LatticeCompression.None to store payloads verbatim. Rows are self-describing, so changing this option affects newly written rows while older rows continue to decode with their recorded tags.
Compression also decides whether a large entry fits. Each entry is stored in one binary property, which the Azure Table service limits to 64 KiB, measured on the stored bytes. With LatticeCompression.None, or for a payload compression cannot shrink, an entry fails as soon as its encoded record exceeds 64 KiB; a compressible one fits while its compressed form stays under the limit. See Architecture.
CompressionMinPayloadBytes
Minimum encoded payload size at which compression is attempted. Default is 256 bytes. Must be non-negative. Ignored when Compression is LatticeCompression.None.
using Orleans.Lattice;
using Orleans.Lattice.Storage.AzureTable;
siloBuilder.AddAzureTableWalStorage(o =>
{
o.ConnectionString = "UseDevelopmentStorage=true";
o.Compression = LatticeCompression.None;
o.CompressionMinPayloadBytes = 0;
});
Validation
When the provider is constructed it rejects a negative CompressionMinPayloadBytes (ArgumentOutOfRangeException), a registered ILatticeCompressor that claims LatticeCompression.None or shares an algorithm tag with another registered compressor (ArgumentException), and a Compression algorithm other than None for which no ILatticeCompressor is registered (InvalidOperationException).
At first use - when it builds its Azure SDK client and creates the table - the provider validates the following, throwing InvalidOperationException on a violation:
- Exactly one authentication mode is configured.
TableNameis non-empty.- Credential modes are mutually exclusive.
- Retry values are within valid ranges.
RetryDelaydoes not exceedRetryMaxDelaywhen both are set.PhaseTwoCoalescingWindowandSaturationShortCircuitCooldownare non-negative.PhaseTwoCommitTimeoutis positive when set.CompressionMinPayloadBytesis non-negative.
See also
- Core WAL Storage Providers - provider seam and placement.
- WAL tuning - batch sizing and provider saturation envelope.
- WAL saturation signal - saturation classifier used by retry short-circuiting.