Skip to content

Commit 4f85407

Browse files
ReubenBondCopilot
andcommitted
docs(streaming): document AWS Kinesis provider
Add provider guidance and an AWS sample using DynamoDB for clustering, grain storage, reminders, pub-sub storage, and stream checkpointing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3f5060d4-b229-476c-bdf3-9923ad459bb2
1 parent bb790e2 commit 4f85407

11 files changed

Lines changed: 413 additions & 2 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
title: Stream with Amazon Kinesis
3+
description: Configure Amazon Kinesis Data Streams for Orleans, including durable DynamoDB checkpoints.
4+
ms.date: 08/07/2026
5+
ms.topic: how-to
6+
---
7+
8+
# Stream with Amazon Kinesis
9+
10+
The [`Microsoft.Orleans.Streaming.Kinesis`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Kinesis) package connects Orleans persistent streams to [Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/introduction.html). Each Kinesis shard is an Orleans queue, so the number of open shards bounds physical read parallelism. Kinesis retention determines how far a consumer can replay.
11+
12+
Create the Kinesis data stream before starting Orleans. The provider discovers its shards but doesn't create, delete, split, or merge the stream.
13+
14+
## Configure the silo
15+
16+
Install the package and register a named provider:
17+
18+
```csharp
19+
using Orleans.Hosting;
20+
21+
siloBuilder
22+
.AddDynamoDBGrainStorage("PubSubStore", options =>
23+
{
24+
options.Service = "us-east-1";
25+
options.ServiceId = "orders";
26+
options.TableName = "OrdersPubSub";
27+
options.UseProvisionedThroughput = false;
28+
})
29+
.AddKinesisStreams("Orders", stream =>
30+
{
31+
stream.ConfigureKinesis(options =>
32+
{
33+
options.StreamName = "orders";
34+
options.Region = "us-east-1";
35+
});
36+
37+
stream.UseDynamoDBCheckpointer(options =>
38+
{
39+
options.Service = "us-east-1";
40+
options.TableName = "OrdersStreamCheckpoints";
41+
options.PersistInterval = TimeSpan.FromSeconds(30);
42+
});
43+
});
44+
```
45+
46+
`PubSubStore` persists explicit Orleans stream subscriptions. The checkpoint table has a different purpose: it records the last delivered Kinesis sequence number for each shard.
47+
48+
Configure every Orleans client which publishes through the provider with the same provider name, stream name, and region:
49+
50+
```csharp
51+
clientBuilder.AddKinesisStreams("Orders", options =>
52+
{
53+
options.StreamName = "orders";
54+
options.Region = "us-east-1";
55+
});
56+
```
57+
58+
When explicit credentials aren't configured, the provider uses the [AWS SDK for .NET credential resolution chain](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/creds-assign.html). In production, prefer workload credentials such as an IAM role. Set <xref:Orleans.Streaming.Kinesis.KinesisStreamOptions.Service> when using a custom Kinesis-compatible endpoint.
59+
60+
## Choose checkpoint storage
61+
62+
Kinesis shard iterators are temporary. Orleans therefore stores the last delivered sequence number outside Kinesis and uses it to resume after a restart or queue reassignment.
63+
64+
### DynamoDB table checkpoints
65+
66+
Call <xref:Orleans.Hosting.SiloKinesisStreamConfigurator.UseDynamoDBCheckpointer*> to store checkpoints directly in DynamoDB. The checkpointer:
67+
68+
- Uses one versioned item per Orleans service, provider, and Kinesis shard.
69+
- Uses consistent reads and conditional writes to prevent a previous queue owner from overwriting a newer checkpoint.
70+
- Creates an on-demand table by default. Set <xref:Orleans.Configuration.DynamoDBStreamQueueCheckpointerOptions.CreateIfNotExists> to `false` when infrastructure provisioning owns the table.
71+
- Limits writes using <xref:Orleans.Configuration.DynamoDBStreamQueueCheckpointerOptions.PersistInterval>. A shorter interval reduces replay after failure but increases DynamoDB write traffic.
72+
73+
Set <xref:Orleans.Configuration.DynamoDBStreamQueueCheckpointerOptions.UseProvisionedThroughput>, <xref:Orleans.Configuration.DynamoDBStreamQueueCheckpointerOptions.ReadCapacityUnits>, and <xref:Orleans.Configuration.DynamoDBStreamQueueCheckpointerOptions.WriteCapacityUnits> when the table uses provisioned capacity.
74+
75+
### Grain checkpoints
76+
77+
If no checkpointer is selected, the provider uses Orleans grain-backed checkpoints. Checkpoint grains use `PubSubStore` by default, so that provider must be durable in production:
78+
79+
```csharp
80+
using Orleans.Streams;
81+
82+
siloBuilder.AddKinesisStreams("Orders", stream =>
83+
{
84+
stream.ConfigureKinesis(options =>
85+
{
86+
options.StreamName = "orders";
87+
options.Region = "us-east-1";
88+
});
89+
90+
stream.UseGrainCheckpointer(options =>
91+
{
92+
options.StorageProviderName = "PubSubStore";
93+
options.CheckpointComparer = StreamCheckpointComparers.Numeric;
94+
options.PersistInterval = TimeSpan.FromSeconds(30);
95+
});
96+
});
97+
```
98+
99+
Both implementations preserve monotonic Kinesis sequence numbers and can replay a small number of already delivered records after an unclean shutdown. Consumers must tolerate duplicate delivery.
100+
101+
## Operations and permissions
102+
103+
Grant the application only the Kinesis data-plane and DynamoDB table permissions required by its configuration. The Kinesis provider lists shards, obtains shard iterators, reads records, and writes records. A provider-managed checkpoint table also requires permissions to describe and create the table and to read and conditionally write checkpoint items.
104+
105+
Monitor Kinesis iterator age, read throttling, provisioned throughput, and retention together with the [Orleans streaming metrics](streaming-operations.md#observe-health). <xref:Orleans.Streaming.Kinesis.KinesisStreamOptions.GetRecordsInterval> defaults to the fastest interval allowed by Kinesis for each shard.
106+
107+
Live resharding isn't supported. If the shard topology changes while the provider is running, receivers stop rather than risk incorrect queue ownership. Restart the Orleans stream provider after splitting or merging shards.
108+
109+
For a complete configuration which uses DynamoDB for clustering, grain state, reminders, and Kinesis checkpoints, see the [AWS Kinesis and DynamoDB sample](https://github.com/dotnet/orleans/tree/main/samples/AWS/KinesisDynamoDB).

docs/site/src/content/docs/streaming/stream-providers.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ A stream provider connects the Orleans streaming API to a transport and defines
1616
| Memory | [`Microsoft.Orleans.Streaming`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming) | Stable | No; silo memory only | Yes, within the transient in-memory cache | None |
1717
| Azure Queue Storage | [`Microsoft.Orleans.Streaming.AzureStorage`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.AzureStorage) | Stable | Yes, in Azure Storage queues | No | Azure Storage account or Azurite; credentials and a stable Orleans service ID |
1818
| Azure Event Hubs | [`Microsoft.Orleans.Streaming.EventHubs`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.EventHubs) | Stable | Yes, within Event Hubs retention | Yes | Event Hubs namespace, hub, consumer group, and checkpoint storage |
19+
| Amazon Kinesis | [`Microsoft.Orleans.Streaming.Kinesis`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Kinesis) | Stable | Yes, within Kinesis retention | Yes | Kinesis data stream, AWS credentials, region, and durable checkpoint storage |
1920
| Amazon SQS | [`Microsoft.Orleans.Streaming.SQS`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.SQS) | Stable | Yes, within SQS retention | No | AWS account, queue permissions, region/endpoint configuration |
2021
| ADO.NET | [`Microsoft.Orleans.Streaming.AdoNet`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.AdoNet) | **Alpha** | Yes, in relational tables until expiry/dead-letter eviction | No | Supported database, ADO.NET driver, and Orleans streaming SQL schema |
2122
| NATS JetStream | [`Microsoft.Orleans.Streaming.NATS`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.NATS) | **Alpha** | Configurable; file storage is the default | No | NATS server with JetStream and sufficient storage; subject/stream administration |
@@ -53,6 +54,10 @@ The examples use durable Azure Table Storage for `PubSubStore`; queue durability
5354

5455
Register [Azure Event Hubs](https://learn.microsoft.com/azure/event-hubs/event-hubs-about) with <xref:Orleans.Hosting.SiloBuilderExtensions.AddEventHubStreams*>. Event Hubs retention and partition positions make this provider rewindable. Configure a consumer group dedicated to the Orleans application and durable checkpoint storage. Partition count bounds physical read parallelism, and retention bounds how far recovery can rewind.
5556

57+
## Amazon Kinesis
58+
59+
Register [Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/introduction.html) with <xref:Orleans.Hosting.SiloBuilderExtensions.AddKinesisStreams*>. Kinesis retains events independently of Orleans, and the provider persists each shard's last delivered sequence number so that delivery can resume after shutdown or queue reassignment. See [Stream with Amazon Kinesis](kinesis-streaming.md) for configuration, checkpoint choices, and operational constraints.
60+
5661
## Amazon SQS
5762

5863
Register [Amazon SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html) with <xref:Orleans.Hosting.SiloBuilderExtensions.AddSqsStreams*>. Standard queues use [at-least-once delivery](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues-at-least-once-delivery.html), and SQS redelivers after the [visibility timeout](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html) when processing isn't acknowledged. The Orleans provider isn't rewindable. Configure credentials using the deployment environment's AWS credential chain or protected connection configuration, and monitor queue age, redelivery, and dead-letter policy.

docs/site/src/content/docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ items:
128128
href: streaming/streams-programming-apis.md
129129
- name: Stream providers
130130
href: streaming/stream-providers.md
131+
- name: Amazon Kinesis
132+
href: streaming/kinesis-streaming.md
131133
- name: Delivery semantics
132134
href: streaming/delivery-semantics.md
133135
- name: Pub-sub storage
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<ProjectReference Include="$(SourceRoot)src\Orleans.Server\Orleans.Server.csproj" />
11+
<ProjectReference Include="$(SourceRoot)src\AWS\Orleans.Clustering.DynamoDB\Orleans.Clustering.DynamoDB.csproj" />
12+
<ProjectReference Include="$(SourceRoot)src\AWS\Orleans.Persistence.DynamoDB\Orleans.Persistence.DynamoDB.csproj" />
13+
<ProjectReference Include="$(SourceRoot)src\AWS\Orleans.Reminders.DynamoDB\Orleans.Reminders.DynamoDB.csproj" />
14+
<ProjectReference Include="$(SourceRoot)src\AWS\Orleans.Streaming.Kinesis\Orleans.Streaming.Kinesis.csproj" />
15+
<PackageReference Include="Microsoft.Extensions.Hosting" />
16+
</ItemGroup>
17+
</Project>
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Hosting;
3+
using Microsoft.Extensions.Logging;
4+
using Orleans.Configuration;
5+
using Orleans.Hosting;
6+
7+
var settings = AwsSampleSettings.FromEnvironment();
8+
var builder = Host.CreateApplicationBuilder(args);
9+
10+
builder.Logging.AddSimpleConsole(options => options.SingleLine = true);
11+
builder.UseOrleans(siloBuilder =>
12+
{
13+
siloBuilder
14+
.Configure<ClusterOptions>(options =>
15+
{
16+
options.ClusterId = settings.ClusterId;
17+
options.ServiceId = settings.ServiceId;
18+
})
19+
.UseDynamoDBClustering(options =>
20+
{
21+
options.Service = settings.Region;
22+
options.TableName = $"{settings.ResourcePrefix}Silos";
23+
options.UseProvisionedThroughput = false;
24+
})
25+
.AddDynamoDBGrainStorageAsDefault(options =>
26+
{
27+
options.Service = settings.Region;
28+
options.ServiceId = settings.ServiceId;
29+
options.TableName = $"{settings.ResourcePrefix}GrainState";
30+
options.UseProvisionedThroughput = false;
31+
})
32+
.AddDynamoDBGrainStorage("PubSubStore", options =>
33+
{
34+
options.Service = settings.Region;
35+
options.ServiceId = settings.ServiceId;
36+
options.TableName = $"{settings.ResourcePrefix}PubSub";
37+
options.UseProvisionedThroughput = false;
38+
})
39+
.UseDynamoDBReminderService(options =>
40+
{
41+
options.Service = settings.Region;
42+
options.TableName = $"{settings.ResourcePrefix}Reminders";
43+
options.UseProvisionedThroughput = false;
44+
})
45+
.AddKinesisStreams(SampleConstants.StreamProvider, stream =>
46+
{
47+
stream.ConfigureKinesis(options =>
48+
{
49+
options.Region = settings.Region;
50+
options.StreamName = settings.StreamName;
51+
});
52+
stream.UseDynamoDBCheckpointer(options =>
53+
{
54+
options.Service = settings.Region;
55+
options.TableName = $"{settings.ResourcePrefix}StreamCheckpoints";
56+
options.PersistInterval = TimeSpan.FromSeconds(10);
57+
});
58+
});
59+
});
60+
61+
builder.Services.AddHostedService<SamplePublisher>();
62+
63+
await builder.Build().RunAsync();
64+
65+
internal sealed record AwsSampleSettings(
66+
string Region,
67+
string StreamName,
68+
string ResourcePrefix,
69+
string ClusterId,
70+
string ServiceId)
71+
{
72+
public static AwsSampleSettings FromEnvironment()
73+
{
74+
var region = Environment.GetEnvironmentVariable("AWS_REGION")
75+
?? Environment.GetEnvironmentVariable("AWS_DEFAULT_REGION")
76+
?? "us-east-1";
77+
78+
return new(
79+
Region: region,
80+
StreamName: Environment.GetEnvironmentVariable("ORLEANS_KINESIS_STREAM") ?? "orleans-sample",
81+
ResourcePrefix: Environment.GetEnvironmentVariable("ORLEANS_DYNAMODB_PREFIX") ?? "OrleansSample",
82+
ClusterId: Environment.GetEnvironmentVariable("ORLEANS_CLUSTER_ID") ?? "aws-kinesis-sample",
83+
ServiceId: Environment.GetEnvironmentVariable("ORLEANS_SERVICE_ID") ?? "aws-kinesis-sample");
84+
}
85+
}
86+
87+
internal sealed class SamplePublisher(
88+
IGrainFactory grainFactory,
89+
ILogger<SamplePublisher> logger) : BackgroundService
90+
{
91+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
92+
{
93+
var grain = grainFactory.GetGrain<IStreamProcessorGrain>(SampleConstants.StreamId);
94+
await grain.InitializeAsync(stoppingToken);
95+
96+
while (!stoppingToken.IsCancellationRequested)
97+
{
98+
var message = $"Event created at {DateTimeOffset.UtcNow:O}";
99+
await grain.PublishAsync(message, stoppingToken);
100+
var state = await grain.GetStateAsync(stoppingToken);
101+
logger.LogInformation(
102+
"Published an event. The processor has persisted {EventCount} events and {ReminderCount} reminder ticks",
103+
state.EventCount,
104+
state.ReminderCount);
105+
106+
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
107+
}
108+
}
109+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# AWS Kinesis and DynamoDB
2+
3+
This sample runs an Orleans silo which uses AWS services for every durable subsystem:
4+
5+
- DynamoDB cluster membership
6+
- DynamoDB grain state and `PubSubStore`
7+
- DynamoDB reminders
8+
- Amazon Kinesis Data Streams
9+
- DynamoDB Kinesis stream checkpoints
10+
11+
The sample publishes an event every five seconds. An implicitly subscribed grain consumes each event, persists its state, and registers a durable reminder.
12+
13+
## Prerequisites
14+
15+
1. Install the [.NET SDK](https://dotnet.microsoft.com/download) selected by the repository's `global.json`.
16+
1. Configure AWS credentials using the standard [AWS SDK credential chain](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/creds-assign.html).
17+
1. Create a Kinesis data stream:
18+
19+
```shell
20+
aws kinesis create-stream --stream-name orleans-sample --shard-count 1 --region us-east-1
21+
aws kinesis wait stream-exists --stream-name orleans-sample --region us-east-1
22+
```
23+
24+
The sample creates its DynamoDB tables automatically with on-demand billing. For production deployments, provision tables through infrastructure as code and disable automatic creation.
25+
26+
## Run the sample
27+
28+
From the repository root:
29+
30+
```shell
31+
dotnet run --project samples/AWS/KinesisDynamoDB/KinesisDynamoDB.csproj
32+
```
33+
34+
Press <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop.
35+
36+
The following environment variables customize the resources:
37+
38+
| Variable | Default | Purpose |
39+
|---|---|---|
40+
| `AWS_REGION` or `AWS_DEFAULT_REGION` | `us-east-1` | Region for Kinesis and DynamoDB |
41+
| `ORLEANS_KINESIS_STREAM` | `orleans-sample` | Existing Kinesis data stream |
42+
| `ORLEANS_DYNAMODB_PREFIX` | `OrleansSample` | Prefix for all five DynamoDB tables |
43+
| `ORLEANS_CLUSTER_ID` | `aws-kinesis-sample` | Orleans deployment identifier |
44+
| `ORLEANS_SERVICE_ID` | `aws-kinesis-sample` | Stable Orleans application identifier |
45+
46+
Use a distinct cluster ID for each concurrently running deployment. Keep the service ID stable when a replacement deployment must retain grain state, reminders, subscriptions, and checkpoints.
47+
48+
See [Stream with Amazon Kinesis](../../../docs/site/src/content/docs/streaming/kinesis-streaming.md) for checkpoint behavior and operational guidance.

0 commit comments

Comments
 (0)