Table of Contents

Events source

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 source.md, and llms.txt lists every page.

The source of the Events sample.

Program.cs

using System.Collections.Concurrent;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans.Hosting;
using Orleans.Lattice;

// Events sample
// =============
// Orleans.Lattice publishes metadata-only event notifications on a per-tree
// Orleans stream so caches, projections, and dashboards can react to mutations
// without polling. This sample turns publication on, subscribes to a tree's
// event stream, performs a few writes, and prints the LatticeTreeEvent records
// as they arrive.
//
// Events carry only metadata - the key name and operation kind, never the value
// bytes - so a subscriber that needs the new value issues its own GetAsync.
//
// Setup requires: PublishEvents = true, a named stream provider, and a matching
// AddMemoryStreams(...) provider plus its PubSubStore.

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.SetMinimumLevel(LogLevel.None);
    })
    .UseOrleans(silo =>
    {
        silo.UseLocalhostClustering();
        silo.AddMemoryGrainStorageAsDefault();
        silo.UseInMemoryReminderService();
        silo.AddLattice((s, name) => s.AddMemoryGrainStorage(name));
        silo.ConfigureLattice(o =>
        {
            o.PublishEvents = true;
            o.EventStreamProviderName = "Default";
        });
        // Lattice never registers a stream provider for you - add one explicitly
        // (plus the PubSubStore the stream runtime needs) and name it above.
        silo.AddMemoryStreams("Default");
        silo.AddMemoryGrainStorage("PubSubStore");
    })
    .Build();

Console.Write("Silo starting...");
await host.StartAsync();
Console.WriteLine(" ready.");
Console.WriteLine();

var client = host.Services.GetRequiredService<IClusterClient>();
var tree = client.GetGrain<ILattice>("catalog");

// Buffer received events so we can wait for them deterministically (delivery is
// best-effort and asynchronous).
var received = new ConcurrentQueue<LatticeTreeEvent>();
var handle = await tree.SubscribeToEventsAsync(
    client,
    evt =>
    {
        received.Enqueue(evt);
        return Task.CompletedTask;
    },
    providerName: "Default",
    CancellationToken.None);

Console.WriteLine("Subscribed to stream 'orleans.lattice.events' for tree 'catalog'.");
Console.WriteLine();

// Perform a handful of mutations. Each emits one metadata-only event.
Console.WriteLine("Performing writes:");
await tree.SetAsync("sku-1", Encoding.UTF8.GetBytes("widget"));
Console.WriteLine("  set    sku-1");
await tree.SetAsync("sku-2", Encoding.UTF8.GetBytes("gadget"));
Console.WriteLine("  set    sku-2");
await tree.SetAsync("sku-1", Encoding.UTF8.GetBytes("widget-v2"));
Console.WriteLine("  set    sku-1 (update)");
await tree.DeleteAsync("sku-2");
Console.WriteLine("  delete sku-2");
Console.WriteLine();

// Wait (bounded) for all four events to be delivered.
const int expected = 4;
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(10);
while (received.Count < expected && DateTime.UtcNow < deadline)
{
    await Task.Delay(50);
}

Console.WriteLine($"Received {received.Count} event(s):");
foreach (var evt in received)
{
    Console.WriteLine($"  {evt.Kind,-8} tree={evt.TreeId} key={evt.Key ?? "<none>"} shard={evt.ShardIndex?.ToString() ?? "-"}");
}

await handle.UnsubscribeAsync();
await host.StopAsync();

Events.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <RootNamespace>Orleans.Lattice.Samples.Events</RootNamespace>
    <AssemblyName>Orleans.Lattice.Samples.Events</AssemblyName>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.11" />
    <PackageReference Include="Microsoft.Orleans.Server" Version="10.2.2" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\lattice\Orleans.Lattice.csproj" />
  </ItemGroup>

</Project>