Runtime per-tree replication configuration
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.This sample drives cross-cluster replication enablement at runtime through the
replication control API, instead of declaring replicated trees statically in the
LatticeReplicationOptions.ReplicatedTrees options map at boot.
What it shows
The control facade ILatticeReplicationControl writes to a replicated CRDT
system tree, sys-replication-config, keyed by target tree id. Every cluster
that enrols that tree converges on the same per-tree decision: whether the tree
is replicated, and under which merge mode. Because the decision itself is a
CRDT, there is no bespoke handshake and no single owning cluster.
The sample hosts one single-silo Orleans cluster and runs a scripted, non-interactive flow:
- Enable replication for the
orderstree under anOrSetmerge mode. The merge mode is fixed at enable-time. - Report the live per-tree config through
GetReplicationConfigAsync, showingenabled=True mode=OrSet ambiguous=False. The report also lists thesys-replication-configtree itself: the report covers the static enrollment map as well as the runtime entries, and the config tree is statically enrolled underOrMap. - Reject an in-place mode change. Re-enabling
ordersunder a different mode throwsLatticeReplicationModeChangeRejectedException. The sanctioned path to change a tree's merge mode is disable, then re-enable under the new mode (naming a bootstrap source cluster on that enable re-seeds a tree that already holds data). - Disable the tree. This removes the tree's resolved runtime merge mode but
does not tear down a shipper that is already running (a peer that resolves
no mode drops what it still ships while acknowledging the batch). It never
purges data already replicated to peers and keeps the tree's fixed merge
mode, which is why the next report still shows
mode=OrSet. - Report the config again, showing
enabled=False.
Running it
dotnet run --project samples/RuntimeReplicationConfig
Expected output:
Silo starting... ready.
Enabling replication for tree 'orders' under OrSet...
enabled: tree=orders mode=OrSet alreadyEnabled=False bootstrapRequested=False
Replication config (2 tree(s)):
tree=orders enabled=True mode=OrSet ambiguous=False
tree=sys-replication-config enabled=True mode=OrMap ambiguous=False
Attempting an in-place mode change to LwwRegister (expected to be rejected)...
rejected as expected: Tree 'orders' is already enabled under merge mode 'OrSet', ...
Disabling replication for tree 'orders'...
disabled: tree=orders alreadyDisabled=False
Replication config (2 tree(s)):
tree=orders enabled=False mode=OrSet ambiguous=False
tree=sys-replication-config enabled=True mode=OrMap ambiguous=False
Sample complete. Stopping silo...
Done.
Wiring
The silo opts in with two calls:
AddLatticeReplication(..., enableRuntimeConfig: true)enables the replication engine, sets this cluster'sClusterId, and statically anchors thesys-replication-configtree. That anchor is the one static enrolment the runtime-config model requires; every other tree is enabled dynamically through the facade.AddLatticeReplicationApi()bindsILatticeReplicationControlover the config authority.
Authorization
This sample registers no auth stack, so the default allow-all access gate
authorizes every facade call. A production deployment registers
Orleans.Lattice.Auth and authors through the fail-closed API access gate,
which default-denies anonymous callers. Propagation to peers is not
re-consented per cluster: the trust boundary is the existing peer enrolment.
See also
docs/lattice.api.replication/README.md- the control facade and its DTOs.docs/lattice.api.replication.grpc/README.md- the cross-process gRPC binding.docs/lattice.replication/runtime-config.md- the engine-side config tree and compiled snapshot.samples/CrossClusterReplication- the static two-site replication topology.