Shuttle.Recall
22.0.0-beta.1
Prefix Reserved
See the version list below for details.
dotnet add package Shuttle.Recall --version 22.0.0-beta.1
NuGet\Install-Package Shuttle.Recall -Version 22.0.0-beta.1
<PackageReference Include="Shuttle.Recall" Version="22.0.0-beta.1" />
<PackageVersion Include="Shuttle.Recall" Version="22.0.0-beta.1" />
<PackageReference Include="Shuttle.Recall" />
paket add Shuttle.Recall --version 22.0.0-beta.1
#r "nuget: Shuttle.Recall, 22.0.0-beta.1"
#:package Shuttle.Recall@22.0.0-beta.1
#addin nuget:?package=Shuttle.Recall&version=22.0.0-beta.1&prerelease
#tool nuget:?package=Shuttle.Recall&version=22.0.0-beta.1&prerelease
Shuttle.Recall
Shuttle.Recall is an event-sourcing mechanism for .NET that provides a flexible way to persist and retrieve event streams.
Installation
dotnet add package Shuttle.Recall
Registration
To register Shuttle.Recall, use the AddRecall extension method:
services.AddRecall(builder =>
{
builder.AddProjection("ProjectionName", projection =>
{
projection.AddEventHandler<SomeEvent>((context, evt) =>
{
// handle event
});
});
});
The following types are registered:
IEventStore(Scoped): Used to retrieve and save event streams.IEventProcessor(Singleton): Used to process projections.IEventMethodInvoker(Singleton): Invokes event handling methods on aggregate roots.ISerializer(Singleton): Serializes and deserializes events.IConcurrencyExceptionSpecification(Singleton): Detects concurrency exceptions.
Configuration Options
services.AddRecall(options =>
{
options.EventProcessing.ProjectionThreadCount = 5;
options.EventProcessing.IncludedProjections.Add("ProjectionName");
options.EventProcessing.ExcludedProjections.Add("ExcludeMe");
options.EventProcessing.ImmediateConsistency.Enabled = true;
options.EventProcessing.ImmediateConsistency.IncludedProjections.Add("ProjectionName");
options.EventStore.CompressionAlgorithm = "gzip";
options.EventStore.EncryptionAlgorithm = "aes";
});
EventProcessing Options
| Property | Default | Description |
|---|---|---|
ProjectionThreadCount |
5 |
Number of threads for projection processing |
IncludedProjections |
[] |
List of projection names to include |
ExcludedProjections |
[] |
List of projection names to exclude |
ProjectionProcessorIdleDurations |
varies | Idle durations for processor polling |
ImmediateConsistency |
see below | Options controlling immediate consistency processing |
ImmediateConsistencyFailed |
AsyncEvent<ImmediateConsistencyFailedEventArgs> raised when a projection handler throws while processing an event immediately |
ImmediateConsistency Options
By default, a projection only ever processes an event once the background IEventProcessor gets round to it. Immediate consistency lets specific projections handle an event synchronously, as part of the IEventStore.SaveAsync call that persisted it, so that a read model built from that projection is guaranteed to reflect the event by the time SaveAsync returns.
| Property | Default | Description |
|---|---|---|
Enabled |
false |
While false, every save is processed eventually only and IncludedProjections/ExcludedProjections below are ignored |
IncludedProjections |
[] |
Projection names that should be handled immediately. If empty, every registered projection is eligible (subject to ExcludedProjections). May not be specified together with ExcludedProjections |
ExcludedProjections |
[] |
Projection names to exclude from immediate handling when IncludedProjections is empty. May not be specified together with IncludedProjections |
These IncludedProjections/ExcludedProjections only decide which projections are handled immediately — they are separate from, and have no effect on, the EventProcessing.IncludedProjections/ExcludedProjections above, which decide which projections the eventual IEventProcessor handles at all.
If a projection's handler throws while being invoked immediately, the event is not lost: EventProcessing.ImmediateConsistencyFailed is raised, and the eventual IEventProcessor will still pick up and retry the event on its next pass.
options.EventProcessing.ImmediateConsistencyFailed += (args, cancellationToken) =>
{
_logger.LogWarning("Projection '{ProjectionName}' failed to handle event '{EventId}' immediately: {Exception}", args.ProjectionName, args.PrimitiveEvent.EventId, args.Exception);
return Task.CompletedTask;
};
You can also request immediate consistency for a single SaveAsync call, regardless of whether Enabled is set — see Saving with Immediate Consistency.
EventStore Options
| Property | Default | Description |
|---|---|---|
CompressionAlgorithm |
"" |
Compression algorithm (e.g., "gzip") |
EncryptionAlgorithm |
"" |
Encryption algorithm (e.g., "aes") |
EventHandlingMethodName |
"On" |
Method name invoked on aggregate roots |
BindingFlags |
Instance \| NonPublic |
Binding flags for event method discovery |
Usage
Saving an Event Stream
var eventStore = serviceProvider.GetRequiredService<IEventStore>();
var streamId = Guid.NewGuid();
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Saving with Headers
var stream = await eventStore.GetAsync(streamId, builder =>
{
builder.AddHeader("key", "value");
});
stream.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Saving with Concurrency Check
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
stream.ConcurrencyInvariant(5); // throws EventStreamConcurrencyException if version != 5
await eventStore.SaveAsync(stream);
Saving with Correlation ID
var stream = await eventStore.GetAsync(streamId);
stream
.WithCorrelationId(correlationId)
.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Saving with Immediate Consistency
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream, builder =>
{
builder.WithImmediateConsistency();
});
This requests immediate consistency for this save only, even when EventProcessing.ImmediateConsistency.Enabled is false. Which projections actually run immediately is still governed by EventProcessing.ImmediateConsistency.IncludedProjections/ExcludedProjections — see ImmediateConsistency Options.
Retrieving an Event Stream
var stream = await eventStore.GetAsync(streamId);
// Apply committed events to an aggregate root or state object
stream.Apply(someAggregateRoot);
Retrieving Events by Type
var stream = await eventStore.GetAsync(streamId);
// Get only committed events
var committedEvents = stream.GetEvents(EventStream.EventRegistrationType.Committed);
// Get only appended events
var appendedEvents = stream.GetEvents(EventStream.EventRegistrationType.Appended);
// Get all events
var allEvents = stream.GetEvents(EventStream.EventRegistrationType.All);
Committing Events Before Apply
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
// Events are only applied after commit
stream.Commit();
// Now Apply() will include the committed events
stream.Apply(someAggregateRoot);
Removing an Event Stream
var stream = await eventStore.GetAsync(streamId);
stream.Remove();
await eventStore.RemoveAsync(streamId);
Projections
Handler Implementation
Implement the IEventHandler<T> interface to handle events:
public class OrderProjection : IEventHandler<OrderPlaced>
{
public async Task HandleAsync(IEventHandlerContext<OrderPlaced> context, CancellationToken cancellationToken = default)
{
var evt = context.Event;
var projection = context.Projection;
var primitiveEvent = context.PrimitiveEvent;
// Process the event
await SaveToReadModelAsync(evt.OrderId, evt.Amount, cancellationToken);
// Optionally defer for retry
// context.Defer(TimeSpan.FromSeconds(5));
}
}
Registering Projections
services.AddRecall(builder =>
{
builder.AddProjection("OrderProjection", projection =>
{
projection.AddEventHandler<OrderProjection>();
});
});
Inline Projection Handlers
services.AddRecall(builder =>
{
builder.AddProjection("OrderProjection", projection =>
{
projection.AddEventHandler((IEventHandlerContext<OrderPlaced> context) =>
{
var evt = context.Event;
// handle event inline
});
});
});
Delegate-based Handlers
builder.AddProjection("ProjectionName", (IEventHandlerContext<SomeEvent> context) =>
{
// handle event
});
IEventProcessor Lifecycle
var processor = serviceProvider.GetRequiredService<IEventProcessor>();
await processor.StartAsync();
// ... application runs ...
await processor.StopAsync();
EventEnvelope Properties
The EventEnvelope class contains metadata about each event:
| Property | Description |
|---|---|
EventId |
Unique identifier for the event |
EventType |
Full type name of the event |
AssemblyQualifiedName |
Assembly-qualified type name |
Event |
The serialized event bytes |
RecordedAt |
When the event was recorded |
Version |
Event version in the stream |
CorrelationId |
Optional correlation ID |
CompressionAlgorithm |
Compression algorithm used |
EncryptionAlgorithm |
Encryption algorithm used |
Headers |
Custom key-value headers |
EventStream Properties
| Property | Description |
|---|---|
Id |
The stream's unique identifier |
Version |
Current stream version |
CorrelationId |
Correlation ID (if set) |
Removed |
Whether the stream has been removed |
IsEmpty |
Whether the stream has no events |
Count |
Total number of events |
Exceptions
EventStreamConcurrencyException: Thrown when concurrent modification is detectedEventProcessingException: Thrown during projection event processing failures
Documentation
Please visit the Shuttle.Recall documentation for more information.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Hosting (>= 10.0.10)
- Microsoft.Extensions.Logging (>= 10.0.10)
- Shuttle.Contract (>= 21.0.1)
- Shuttle.Pipelines (>= 21.0.2)
- Shuttle.Reflection (>= 21.0.1)
- Shuttle.Serialization (>= 21.0.1)
- Shuttle.Specification (>= 21.0.1)
- Shuttle.Streams (>= 21.0.1)
- Shuttle.Threading (>= 21.0.2)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on Shuttle.Recall:
| Package | Downloads |
|---|---|
|
Shuttle.Esb.Process
Shuttle.Esb process management using Shuttle.Recall event sourcing. |
|
|
Shuttle.Recall.SqlServer.Storage
Sql Server event storage. |
|
|
Shuttle.Recall.SqlServer.EventProcessing
Sql Server event projection processing. |
|
|
Shuttle.Recall.Logging
Provides non-intrusive logging for Shuttle.Recall components. |
|
|
Shuttle.Recall.OpenTelemetry
OpenTelemetry instrumentation for Shuttle.Recall. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 22.0.1 | 129 | 8/17/2026 |
| 22.0.0 | 161 | 8/17/2026 |
| 22.0.0-beta.1 | 152 | 8/15/2026 |
| 22.0.0-alpha.1 | 72 | 8/15/2026 |
| 21.0.3 | 804 | 4/17/2026 |
| 21.0.2 | 164 | 4/15/2026 |
| 21.0.2-rc3 | 196 | 4/11/2026 |
| 21.0.2-rc2 | 215 | 3/21/2026 |
| 21.0.2-rc1 | 136 | 3/21/2026 |
| 21.0.1-rc1 | 165 | 2/28/2026 |
| 21.0.1-beta | 173 | 2/7/2026 |
| 21.0.0-alpha | 158 | 1/18/2026 |
| 20.0.0 | 1,965 | 2/2/2025 |
| 18.0.0 | 608 | 8/5/2024 |
| 17.0.1 | 675 | 5/3/2024 |
| 17.0.0 | 623 | 4/30/2024 |
| 16.1.1 | 3,996 | 12/1/2022 |
| 16.0.0 | 4,200 | 9/4/2022 |
| 14.0.0 | 3,272 | 5/29/2022 |
| 13.1.0 | 2,952 | 5/6/2022 |