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
37 changes: 28 additions & 9 deletions src/content/docs/dotnet-next/persistence/event-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ All of those are immutable records.

The event store provides the following operations:

| Function | What's it for |
|------------------|------------------------------------------------------------------|
| `AppendEvents` | Append one or more events to a given stream. |
| `AppendEvents` | Append events to multiple streams in a single operation. |
| `ReadEvents` | Read events from a stream forwards, from a given start position. |
| `StreamExists` | Check if a stream exists. |
| `TruncateStream` | Remove events from a stream up to a given position. |
| `DeleteStream` | Delete a stream entirely. |
| Function | What's it for |
|----------------------|-------------------------------------------------------------------|
| `AppendEvents` | Append one or more events to a given stream. |
| `AppendEvents` | Append events to multiple streams in a single operation. |
| `ReadEvents` | Read events from a stream forwards, from a given start position. |
| `ReadEventsBackwards`| Read events from a stream backwards, from a given start position. |
| `StreamExists` | Check if a stream exists. |
| `TruncateStream` | Remove events from a stream up to a given position. |
| `DeleteStream` | Delete a stream entirely. |

## Usage examples

Expand Down Expand Up @@ -124,7 +125,25 @@ foreach (var evt in events) {
}
```

The `ReadStream` extension method handles pagination automatically and returns all events:
The `IEventReader.ReadEvents` interface method returns `IAsyncEnumerable<StreamEvent>`. `KurrentDBEventStore` streams events as they arrive from the server, holding at most one deserialized event at a time. Relational stores buffer up to `count` events per call before yielding, so memory usage can grow with `count` — keep the count bounded when reading from those stores.

### Reading a whole stream

To read a stream to the end, use the `ReadStreamToEnd` extension method instead of calling `ReadEvents` with `int.MaxValue` as the count. It reads events in pages (500 by default) and yields them as they arrive, so memory use stays bounded by the page size no matter how large the stream is:

```csharp
await foreach (var evt in eventStore.ReadStreamToEnd(
streamName,
StreamReadPosition.Start,
cancellationToken: cancellationToken
)) {
// Process one event at a time with bounded memory use
}
```

Use the `pageSize` parameter to tune the page size, and `failIfNotFound: false` to get an empty sequence instead of a `StreamNotFound` exception when the stream doesn't exist.

If you need the whole stream as an array, the `ReadStream` extension method pages through the stream the same way and collects all events:

```csharp
var allEvents = await eventStore.ReadStream(
Expand Down
14 changes: 14 additions & 0 deletions src/content/docs/dotnet-next/whats-new.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,22 @@ await foreach (var evt in eventReader.ReadEvents(stream, start, count, ct)) {
}
```

`KurrentDBEventStore` yields each event as it arrives from the server, holding at most one deserialized event at a time regardless of the requested count. Relational stores buffer up to `count` events per call, so memory usage can grow with `count` — keep the count bounded when reading from those stores.

The previous signatures (with `failIfNotFound`, returning `Task<StreamEvent[]>`) are preserved as extension methods in `StoreFunctions`, so **all existing callers compile and work unchanged**.

### Read a whole stream with ReadStreamToEnd

To read a stream to the end, use the new `ReadStreamToEnd` extension method instead of calling `ReadEvents` with `int.MaxValue` as the count. It reads events in pages (500 by default) and yields them as they arrive, so memory use stays bounded by the page size no matter how large the stream is:

```csharp
await foreach (var evt in eventReader.ReadStreamToEnd(stream, StreamReadPosition.Start, cancellationToken: ct)) {
// Process one event at a time with bounded memory use
}
```

Use `pageSize` to tune the page size, and `failIfNotFound: false` to get an empty sequence instead of a `StreamNotFound` exception when the stream doesn't exist. The `ReadStream` extension method pages through the stream the same way and collects the result into an array.

### SignalR subscription gateway

Two new packages enable real-time event streaming to browser UIs, mobile apps, or other remote clients via SignalR:
Expand Down