Table of Contents

Orleans.Lattice.Replication.Grpc

This page documents Orleans.Lattice.Replication.Grpc 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 README.md, and llms.txt lists every page.

Canonical gRPC transport binding for Orleans.Lattice.Replication - wires the public IReplicationTransport seam to ASP.NET Core gRPC endpoints so clusters can push live batches, exchange replication acks, and use the same peer endpoints for bootstrap and anti-entropy traffic.

What is it?

Orleans.Lattice.Replication.Grpc is the opt-in transport package for multi-cluster replication. Hosts reference it when they want a production network binding instead of an in-process or custom IReplicationTransport.

It provides:

  • Outbound live push. The canonical sender sends one unary RPC per ReplicationBatchEnvelope over a cached HTTP/2 channel per peer cluster.
  • Inbound apply. The receiver endpoint decodes the envelope and drives IReplicationApplier, returning a ReplicationAck with the applied high-water mark and flow-control hints.
  • Shared endpoint shape. The same peer map is used for live push, remote snapshot bootstrap, anti-entropy probes, and the cross-cluster saga control channel exposed by the replication package.
  • Security defaults. HTTPS endpoints are required by default, with shared-secret authentication documented in Transport Security; the receiver also binds each authenticated call's secret to the origin cluster it stamps, through BindCredentialToOriginCluster (on by default).

The package has no external broker and no .proto file to maintain.

Core Properties

  • Public seam only. Callers configure LatticeReplicationGrpcOptions, send through IReplicationTransport, and receive through IReplicationApplier.
  • Long-lived channels. Each outbound transport caches a long-lived HTTP/2 channel per peer endpoint - live push and the peer probes share one, and snapshot bootstrap and saga control each keep their own - and every channel multiplexes concurrent calls.
  • Idempotent delivery. Sender retries may redeliver a batch; the receiver's record-identity dedup (an exact (origin, hlc, key, op) match, backed by an idempotent leaf-level apply) makes repeated records no-ops.
  • Ack-driven progress. Senders advance their per-peer cursor to the ReplicationAck.HighestAppliedHlc reported by the receiver (or, when an accepted ack reports a frontier at or below the current cursor because every entry was deduplicated, to the last shipped entry's HLC); a rejected ack leaves the cursor in place.
  • Transport-neutral payload. The wire bytes are the normal ReplicationBatchEnvelope encoding described in Wire Format.

Features

Feature What it gives you Docs
gRPC live push Sub-second push path over HTTP/2 using the public IReplicationTransport seam. Architecture
Unified peer options One LatticeReplicationGrpcOptions instance configures peer endpoints, TLS policy, channel customization, and origin header override. Configuration
Receiver endpoint mapping MapLatticeReplicationGrpc exposes the inbound replication endpoints on an ASP.NET Core route builder. API Reference
Bootstrap and anti-entropy transport The same peer endpoint carries snapshot bootstrap and read-only drift probes used by the replication package. Replication docs
Saga control channel The same peer endpoint carries the cross-cluster saga control calls (prepare, commit, abort, status) that coordinated restore drives, and the receiver serves them behind a peer allow-list gate. Coordinated restore
Transport chaos coverage Fault-injected channel tests prove that bounded caller retries deliver every batch with no key loss. Chaos Tests

Quick Start

Register the replication package on the silo, then add the gRPC binding and map its endpoints on the ASP.NET Core host:

using Microsoft.AspNetCore.Builder;
using Orleans.Hosting;
using Orleans.Lattice;
using Orleans.Lattice.Replication;
using Orleans.Lattice.Replication.Grpc;

var builder = WebApplication.CreateBuilder();

builder.Host.UseOrleans(silo => silo
    .AddLattice((s, storageName) => s.AddMemoryGrainStorage(storageName))
    .AddLatticeReplication(opts =>
    {
        opts.ClusterId = "site-a";
        opts.ReplicatedTrees = new Dictionary<string, LatticeMergeMode>(StringComparer.Ordinal)
        {
            ["orders"] = LatticeMergeMode.LwwRegister,
        };
        opts.ReplicationPeers = new[] { "site-b" };
    }));

builder.Services.AddLatticeReplicationGrpc(grpc =>
{
    grpc.Peers["site-b"] = new Uri("https://site-b.example:5001");
});

var app = builder.Build();
app.MapLatticeReplicationGrpc();
app.Run();

Reference

For day-to-day use and operations:

For internals (the "how"):