![]() |
VOOZH | about |
dotnet add package Franz.Common.Messaging.Sagas --version 2.2.7
NuGet\Install-Package Franz.Common.Messaging.Sagas -Version 2.2.7
<PackageReference Include="Franz.Common.Messaging.Sagas" Version="2.2.7" />
<PackageVersion Include="Franz.Common.Messaging.Sagas" Version="2.2.7" />Directory.Packages.props
<PackageReference Include="Franz.Common.Messaging.Sagas" />Project file
paket add Franz.Common.Messaging.Sagas --version 2.2.7
#r "nuget: Franz.Common.Messaging.Sagas, 2.2.7"
#:package Franz.Common.Messaging.Sagas@2.2.7
#addin nuget:?package=Franz.Common.Messaging.Sagas&version=2.2.7Install as a Cake Addin
#tool nuget:?package=Franz.Common.Messaging.Sagas&version=2.2.7Install as a Cake Tool
Franz.Common.Messaging.Sagas provides long-running workflow orchestration, distributed coordination, and deterministic state machines fully integrated into the Franz architecture.
Sagas in Franz unify:
They operate transport-agnostically and integrate seamlessly with:
New persistence providers added:
MongoSagaRepositoryCosmosSagaRepositoryBoth support:
JsonSagaStateSerializer)Saga identity now follows one deterministic rule:
SagaId = derived from IMessageCorrelation<T> interface
This eliminates ambiguity across transports and persistence layers.
Task<ISagaTransition>All saga infrastructure is now guaranteed to resolve before message listeners start:
BuildFranzSagas()The entire Saga engine is now:
<Nullable>enable<TreatWarningsAsErrors>true>SagaRegistrationICompensateWith<>The Saga engine is composed of:
ISaga<TState>
β
SagaRegistration
β
SagaRouter
β
SagaOrchestrator
β
SagaExecutionPipeline
β
ISagaRepository (EF / Mongo / Cosmos / Memory)
β
ISagaAuditSink
A complete saga is defined by:
public sealed class OrderSaga :
SagaBase<OrderState>,
IStartWith<OrderCreated>,
IHandle<PaymentAccepted>,
ICompensateWith<PaymentFailed>,
IMessageCorrelation<OrderCreated>,
IMessageCorrelation<PaymentFailed>
{
public override Task OnCreatedAsync(ISagaContext ctx, CancellationToken ct)
{
State.Id = GetCorrelationId((OrderCreated)ctx.Message);
State.CreatedAt = DateTime.UtcNow;
return Task.CompletedTask;
}
public Task<ISagaTransition> HandleAsync(OrderCreated msg, ISagaContext ctx, CancellationToken ct)
=> SagaTransition.Continue(null);
public Task<ISagaTransition> HandleAsync(PaymentAccepted msg, ISagaContext ctx, CancellationToken ct)
=> SagaTransition.Continue(null);
public Task<ISagaTransition> HandleAsync(PaymentFailed msg, ISagaContext ctx, CancellationToken ct)
=> SagaTransition.Continue(null);
public string GetCorrelationId(OrderCreated message) => message.OrderId;
public string GetCorrelationId(PaymentFailed message) => message.OrderId;
}
Handler discovery uses:
IStartWith<TEvent>IHandle<TEvent>ICompensateWith<TEvent>var builder = services.AddFranzSagas(opts =>
{
opts.ValidateMappings = true;
});
builder.AddSaga<OrderSaga>();
builder.AddSaga<PaymentSaga>();
services.AddFranzMediator(β¦);
services.AddRabbitMQMessaging(β¦);
var app = host.Build();
app.Services.BuildFranzSagas();
| Provider | Package / Class | Status |
|---|---|---|
| InMemory | InMemorySagaRepository |
β Stable |
| EntityFramework | EfSagaRepository |
β Production |
| MongoDB | MongoSagaRepository |
β New in 1.7.5 |
| Cosmos DB | CosmosSagaRepository |
β New in 1.7.5 |
| Redis | RedisSagaRepository |
β Stable |
| Kafka Compaction | (future provider) | β Stable |
All saga states must implement:
public interface ISagaState
{
string? ConcurrencyToken { get; set; }
DateTime UpdatedAt { get; set; }
}
And optionally:
public interface ISagaStateWithId
{
string Id { get; set; }
}
Wraps each handler:
await _pipeline.ExecuteAsync(async () =>
{
var result = handler.Invoke(...);
if (result is Task t) await t;
});
Allows user-defined middlewares:
SagaLogEvents provides structured logs for all key lifecycle events:
Default auditing sink:
ISagaAuditSink = DefaultSagaAuditSink
Override with:
builder.AddAuditSink<MyElasticSink>();
For unit tests:
services
.AddFranzSagas(o => o.ValidateMappings = true)
.AddSaga<TestSaga>();
services.AddSingleton<ISagaRepository, InMemorySagaRepository>();
The in-memory store is:
The Saga engine adheres to Franzβs core principles:
| Principle | Meaning |
|---|---|
| Deterministic | Saga identity, mapping, and execution order are guaranteed. |
| Modular | Stores, handlers, and audit sinks are fully pluggable. |
| Transport-agnostic | Kafka, RabbitMQ, HTTP, or custom transports. |
| Zero runtime reflection | Only startup scanning. |
| Safe by default | Built-in validation + null-safety. |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.2.7 | 95 | 6/7/2026 |
| 2.2.6 | 101 | 6/6/2026 |
| 2.2.5 | 100 | 6/4/2026 |
| 2.2.4 | 94 | 6/3/2026 |
| 2.2.3 | 96 | 6/2/2026 |
| 2.2.2 | 95 | 6/2/2026 |
| 2.2.1 | 95 | 5/24/2026 |
| 2.1.4 | 104 | 4/27/2026 |
| 2.1.3 | 102 | 4/26/2026 |
| 2.1.2 | 100 | 4/26/2026 |
| 2.1.1 | 107 | 4/22/2026 |
| 2.0.2 | 118 | 3/30/2026 |
| 2.0.1 | 110 | 3/29/2026 |
| 1.7.8 | 111 | 3/2/2026 |
| 1.7.7 | 135 | 1/31/2026 |
| 1.7.6 | 122 | 1/22/2026 |
| 1.7.5 | 129 | 1/10/2026 |
| 1.7.4 | 119 | 12/27/2025 |
| 1.7.3 | 211 | 12/22/2025 |
| 1.7.2 | 201 | 12/21/2025 |