Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ Cache capacity is not durability. The queue remains the durable boundary, subjec

The agent registers as a producer for each stream and obtains subscription records from stream pub-sub. It holds a pin cursor while subscription handshakes complete so cache cleanup cannot pass the requested start token. New subscription notifications update the agent's local pub-sub cache.

Sequence tokens allow a rewindable adapter to start from a supported historical position. An adapter whose <xref:Orleans.Streams.IQueueAdapter.IsRewindable?displayProperty=nameWithType> property is `false` must reject unsupported tokens rather than pretending to honor them.
Sequence tokens allow a rewindable adapter to start from a historical position supported by its queue cache. The pulling agent passes the token to <xref:Orleans.Streams.IQueueCache.GetCacheCursor*> and continues polling the partition receiver from its existing position. Retained-history replay therefore belongs in an adapter-specific cache and receiver composition which can create historical readers and hand their cursors back to the live cache.

An adapter whose <xref:Orleans.Streams.IQueueAdapter.IsRewindable?displayProperty=nameWithType> property is `false` rejects subscription tokens. A `true` value means the adapter accepts tokens within its documented range; it does not define that range as the external transport's full retention window.

## Delivery and failure semantics

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Write a custom persistent-stream queue adapter
description: Implement and register an Orleans persistent-stream queue adapter for an external queue technology.
ms.date: 08/18/2026
ms.date: 08/30/2026
ms.topic: how-to
---

Expand Down Expand Up @@ -49,7 +49,9 @@ The factory composes the adapter with queue mapping, caching, and failure handli

:::code language="csharp" source="snippets/streaming/CustomQueueAdapter.cs" id="custom_queue_factory":::

`SimpleQueueAdapterCache` is suitable for a non-rewindable adapter whose queue remains the durability boundary. A rewindable adapter usually needs a cache and sequence-token implementation which can position cursors at retained historical messages.
`SimpleQueueAdapterCache` is suitable for an adapter whose subscription tokens only address its live in-memory cache. The pulling agent passes a requested subscription token to <xref:Orleans.Streams.IQueueCache.GetCacheCursor*>; <xref:Orleans.Streams.IQueueAdapterReceiver.GetQueueMessagesAsync*> advances the owned queue partition from the receiver's current position.

An adapter which serves tokens older than the live cache composes its cache and receiver through the factory. On a cache miss, that implementation can open a bounded historical reader at the requested provider token, feed a temporary cursor in order, and hand the cursor to the live cache after catch-up. The adapter defines retention-expiry errors, concurrent replay limits, partition ownership transfer, and shutdown for those readers.

`AddPersistentStreams` leaves checkpointing to the adapter. The non-rewindable example acknowledges completed messages through its receiver and therefore has no independent checkpoint. For a retained-log transport, implement an <xref:Orleans.Streams.IStreamQueueCheckpointerFactory>, have the receiver or cache load and update the per-partition position, and register it as a named component with `ConfigureComponent`. Persist a checkpoint only after all consumers have advanced beyond the corresponding cached messages. A no-op checkpointer is suitable only when replay position is deliberately disposable.

Expand Down
6 changes: 3 additions & 3 deletions docs/site/src/content/docs/streaming/data-adapters.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Customize persistent-stream data formats
description: Configure an Orleans persistent-stream data adapter for a versioned queue-message contract.
ms.date: 08/18/2026
ms.date: 08/30/2026
ms.topic: how-to
---

Expand All @@ -18,7 +18,7 @@ The built-in providers expose these data-adapter extension points:
| Provider | Data-adapter contract | Registration | Runtime outcome |
|---|---|---|---|
| Azure Queue Storage | <xref:Orleans.Streams.IQueueDataAdapter`2> with `string` queue messages and <xref:Orleans.Streams.IBatchContainer> batches | <xref:Orleans.Hosting.AzureQueueStreamConfiguratorExtensions.ConfigureQueueDataAdapter*> | Replaces encoding and decoding while retaining Azure Queue mapping, visibility, deletion, and non-rewindable delivery |
| Azure Event Hubs | <xref:Orleans.Streaming.EventHubs.IEventHubDataAdapter> | <xref:Orleans.Hosting.EventHubStreamConfiguratorExtensions.UseDataAdapter*> | Replaces wire-format, stream-mapping, and cache conversion behavior while retaining Event Hubs partition reading, checkpointing, and rewindable delivery |
| Azure Event Hubs | <xref:Orleans.Streaming.EventHubs.IEventHubDataAdapter> | <xref:Orleans.Hosting.EventHubStreamConfiguratorExtensions.UseDataAdapter*> | Replaces wire-format, stream-mapping, and cache conversion behavior while retaining Event Hubs partition reading, checkpoint recovery, and live-cache rewind |
| Amazon SQS | <xref:Orleans.Streaming.SQS.Streams.ISQSDataAdapter> | <xref:Orleans.Hosting.SiloSqsStreamConfigurator.UseDataAdapter*> and <xref:Orleans.Hosting.ClusterClientSqsStreamConfigurator.UseDataAdapter*> | Replaces the message body, application attributes, and batch decoding while retaining SQS queue mapping, FIFO transport fields, deletion, and non-rewindable delivery |

<xref:Orleans.Streams.IQueueDataAdapter`1> defines conversion from an Orleans batch to a native queue message. <xref:Orleans.Streams.IQueueDataAdapter`2> adds conversion from a native message to the batch container delivered by Orleans. Provider-specific contracts can add the position and cache operations required by their transport.
Expand Down Expand Up @@ -62,7 +62,7 @@ For Event Hubs, derive from <xref:Orleans.Streaming.EventHubs.EventHubDataAdapte
- <xref:Orleans.Streaming.EventHubs.EventHubDataAdapter.ToQueueMessage*> to encode events published through Orleans; and
- <xref:Orleans.Streaming.EventHubs.EventHubDataAdapter.GetPartitionKey*> to select the physical Event Hubs partition key.

The adapter also participates in cache conversion and sequence positioning through <xref:Orleans.Streaming.EventHubs.IEventHubDataAdapter>. Preserve the Event Hubs offset and sequence number when constructing batch tokens so checkpoint and rewind behavior remains aligned with the partition log.
The adapter also participates in cache conversion and sequence positioning through <xref:Orleans.Streaming.EventHubs.IEventHubDataAdapter>. Preserve the Event Hubs offset and sequence number when constructing batch tokens so checkpoint recovery and live-cache cursor positioning remain aligned with the partition log.

Register the adapter and Event Hubs connection under the same provider name on silos and publishing clients. The silo registration also configures durable Azure Table checkpoints:

Expand Down
17 changes: 10 additions & 7 deletions docs/site/src/content/docs/streaming/delivery-semantics.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Stream delivery, ordering, replay, and recovery
description: Design Orleans streaming consumers for provider-specific delivery, ordering, replay, and failure behavior.
ms.date: 08/24/2026
ms.date: 08/30/2026
ms.topic: concept-article
---

Expand Down Expand Up @@ -45,13 +45,16 @@ Use event version numbers or domain sequence numbers when business logic require

## Replay and rewindability

A rewindable provider can start or resume a subscription from a provider sequence token while the corresponding event remains in that provider's retention window. Rewindability isn't the same as durability:
A rewindable provider can start or resume a subscription from a provider sequence token within the historical range supported by its queue cache. Rewindability and external event retention are separate capabilities:

- Memory streams are rewindable only over their transient in-memory cache.
- Event Hubs and Redis Streams are rewindable over retained external data.
- Azure Queue, Amazon SQS, ADO.NET, and NATS JetStream providers aren't rewindable.
- Memory streams, Event Hubs, and Redis Streams position subscription cursors within the live Orleans queue cache.
- Event Hubs and Redis Streams also retain events externally and restore their queue receiver from a provider checkpoint after restart or ownership transfer.
- Kinesis restores its queue receiver from a durable checkpoint and currently reports its subscription API as non-rewindable.
- Azure Queue, Amazon SQS, ADO.NET, and NATS JetStream providers use forward-only subscription cursors.

Explicit subscriptions can resume from retained positions according to the provider's token semantics. An implicit subscription accepts a recovery token when an activation attaches its observer, then advances monotonically for that attachment. Once a delivery call completes successfully, resuming the active implicit handle with a sequence token throws <xref:System.InvalidOperationException>; passing `null` replaces the observer at its current position.
The built-in persistent providers resolve a subscription token through <xref:Orleans.Streams.IQueueCache.GetCacheCursor*>. A token older than that live cache produces a <xref:Orleans.Streams.QueueCacheMissException>; the pulling agent does not open an independent historical reader for that subscription. A custom retained-log adapter can provide a wider range by coupling its cache to bounded historical readers.

Explicit subscriptions can resume from positions supported by the provider's cache and token semantics. An implicit subscription accepts a recovery token when an activation attaches its observer, then advances monotonically for that attachment. Once a delivery call completes successfully, resuming the active implicit handle with a sequence token throws <xref:System.InvalidOperationException>; passing `null` replaces the observer at its current position.

See the [provider matrix](stream-providers.md#provider-matrix) for provider capabilities.

Expand All @@ -61,7 +64,7 @@ See the [provider matrix](stream-providers.md#provider-matrix) for provider capa
1. Use a durable [`PubSubStore`](pubsub-storage.md) when explicit subscription records must survive cluster loss.
1. Resume existing explicit handles after grain activation; don't call <xref:Orleans.Streams.IAsyncObservable`1.SubscribeAsync*> unconditionally.
1. Persist the last applied domain position when the application needs deterministic recovery.
1. For a rewindable provider, restart from a checkpointed token and tolerate replay of the checkpoint boundary.
1. For a rewindable provider, resume from a token that remains in its supported cache range and tolerate replay of the token boundary.
1. Make effects idempotent and alert on poison events, repeated retries, and growing lag.

Provider retention and subscription storage solve different problems. Durable events without durable subscription metadata can wait with no consumer binding; durable subscriptions with a transient provider can't recover events that disappeared.
14 changes: 7 additions & 7 deletions docs/site/src/content/docs/streaming/stream-providers.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Orleans stream providers
description: Compare built-in Orleans stream providers by durability, rewindability, status, and prerequisites.
ms.date: 08/18/2026
ms.date: 08/30/2026
ms.topic: concept-article
---

Expand All @@ -15,12 +15,12 @@ A stream provider connects the Orleans streaming API to a transport and defines
|---|---|---|---|---|---|
| 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 |
| 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 |
| 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 |
| 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 |
| Azure Event Hubs | [`Microsoft.Orleans.Streaming.EventHubs`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.EventHubs) | Stable | Yes, within Event Hubs retention | Yes, within the live Orleans cache | Event Hubs namespace, hub, consumer group, and checkpoint storage |
| Amazon Kinesis | [`Microsoft.Orleans.Streaming.Kinesis`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Kinesis) | Stable | Yes, within Kinesis retention | No; receiver recovery uses checkpoints | Kinesis data stream, AWS credentials, region, and durable checkpoint storage |
| 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 |
| 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 |
| 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 |
| Redis Streams | [`Microsoft.Orleans.Streaming.Redis`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Redis) | **Alpha** | Configurable through Redis persistence and stream retention | Yes, while entries remain | Redis deployment, persistence/HA policy, and retention sizing |
| Redis Streams | [`Microsoft.Orleans.Streaming.Redis`](https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Redis) | **Alpha** | Configurable through Redis persistence and stream retention | Yes, within the live Orleans cache | Redis deployment, persistence/HA policy, and retention sizing |

Alpha packages have an `alpha.1` version suffix. Treat their APIs and operational behavior as prerelease, validate failure modes under load, and pin versions deliberately.

Expand Down Expand Up @@ -52,13 +52,13 @@ The examples use durable Azure Table Storage for `PubSubStore`; queue durability

<a id="azure-event-hub-stream-provider"></a>

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.
Register [Azure Event Hubs](https://learn.microsoft.com/azure/event-hubs/event-hubs-about) with <xref:Orleans.Hosting.SiloBuilderExtensions.AddEventHubStreams*>. The provider accepts subscription tokens that remain in its live Orleans cache. Event Hubs retention and durable checkpoints let a queue receiver resume partition reading after restart or ownership transfer. Configure a consumer group dedicated to the Orleans application and durable checkpoint storage. Partition count bounds physical read parallelism, and cache retention bounds per-subscription rewind.

The Event Hubs provider supports a custom data adapter for provider-specific wire formats. See [Integrate external stream producers and consumers](external-streams.md) when a non-Orleans application must publish to or consume from the same Event Hub.

## Amazon Kinesis

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.
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 queue reading can resume after shutdown or reassignment. Subscription cursors advance from the receiver's current position. See [Stream with Amazon Kinesis](kinesis-streaming.md) for configuration, checkpoint choices, and operational constraints.

## Amazon SQS

Expand All @@ -74,7 +74,7 @@ Register [NATS JetStream](https://docs.nats.io/nats-concepts/jetstream) with `Ad

## Redis Streams streaming (alpha)

Register [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/) with `AddRedisStreams`. The provider stores events and checkpoints in Redis and is rewindable while entries remain. Redis durability depends on its [persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) and replication configuration. `RedisStreamingOptions.MaxStreamLength` can bound retention; without it, stream length is unbounded, so capacity planning is required.
Register [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/) with `AddRedisStreams`. The provider stores events and checkpoints in Redis and accepts subscription tokens that remain in its live Orleans cache. A queue receiver resumes from its Redis checkpoint after restart or ownership transfer. Redis durability depends on its [persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) and replication configuration. `RedisStreamingOptions.MaxStreamLength` can bound external retention; `SimpleQueueCacheOptions.CacheSize` bounds the subscription rewind range.

## Custom adapters

Expand Down