Franz.Common.Messaging.Sagas
1.7.4
dotnet add package Franz.Common.Messaging.Sagas --version 1.7.4
NuGet\Install-Package Franz.Common.Messaging.Sagas -Version 1.7.4
<PackageReference Include="Franz.Common.Messaging.Sagas" Version="1.7.4" />
<PackageVersion Include="Franz.Common.Messaging.Sagas" Version="1.7.4" />
<PackageReference Include="Franz.Common.Messaging.Sagas" />
paket add Franz.Common.Messaging.Sagas --version 1.7.4
#r "nuget: Franz.Common.Messaging.Sagas, 1.7.4"
#:package Franz.Common.Messaging.Sagas@1.7.4
#addin nuget:?package=Franz.Common.Messaging.Sagas&version=1.7.4
#tool nuget:?package=Franz.Common.Messaging.Sagas&version=1.7.4
π¦ Franz.Common.Messaging.Sagas
Version 1.6.21 β Saga Orchestration Engine for the Franz Framework
Franz.Common.Messaging.Sagas brings long-running workflows, distributed coordination, and reliable message-driven orchestration into the Franz ecosystem.
Sagas allow you to coordinate multiple microservices, enforce consistency across asynchronous processes, and implement "orchestrated" event-driven business flows β all while remaining transport-agnostic and fully compatible with:
- Franz.Common.Messaging
- Franz.Common.Mediator
- Kafka
- RabbitMQ
- EntityFramework
- Redis
- In-Memory workflows
Current Version: 1.7.4
π Whatβs New in v1.6.21
β Full Saga Infrastructure
ISaga<TState>base interface- Start / Step / Compensation handler interfaces
- Strongly typed state model (
ISagaState) SagaTransitionsystem for outgoing messages
β Saga Execution Engine
SagaOrchestratorSagaRouterSagaExecutionPipeline(middleware-like wrapping)
β Validations
SagaTypeValidatorSagaMappingValidator- Full mapping validation at startup
- Prevention of misconfigured handlers
β Persistence Providers (Pluggable)
- EntityFramework (production ready)
- Redis (stub)
- Kafka compacted topics (stub / future)
- InMemory (fast + ideal for unit tests)
β Logging & Auditing
- Structured logging (
SagaLogEvents) - Pluggable audit sinks (
ISagaAuditSink) - Included default implementation:
DefaultSagaAuditSink β ILogger
β appsettings.json First-Class Support
- Automatic wiring of persistence providers
- Automatic saga registration
- Optional auditing + validation
- Environment-friendly configuration
π Architecture Overview
A fully configured Saga registry consists of:
ISaga<TState>
β discovers
SagaRegistration
β aggregated into
SagaRouter
β invoked by
SagaOrchestrator
β coordinated via
SagaExecutionPipeline
β persisted in
ISagaRepository (EF / Redis / Mem / Kafka)
β traced with
ISagaAuditSink
π§© Defining a Saga
A Saga is simply a class implementing:
public class OrderSaga : ISaga<OrderState>,
IStartWith<OrderCreated>,
IHandle<PaymentAccepted>,
ICompensateWith<PaymentFailed>
{
public OrderState State { get; private set; } = new();
public string SagaId => State.OrderId;
public Task OnCreatedAsync(ISagaContext context, CancellationToken token)
{
State.CreatedAt = DateTime.UtcNow;
return Task.CompletedTask;
}
public async Task<ISagaTransition> HandleAsync(OrderCreated message, ISagaContext ctx, CancellationToken token) { β¦ }
public async Task<ISagaTransition> HandleAsync(PaymentAccepted message, ISagaContext ctx, CancellationToken token) { β¦ }
public async Task<ISagaTransition> HandleAsync(PaymentFailed message, ISagaContext ctx, CancellationToken token) { β¦ }
}
Franz automatically discovers handlers through:
IStartWith<TMessage>IHandle<TMessage>ICompensateWith<TMessage>
ποΈ Registering Sagas
Using the fluent builder pattern:
services
.AddFranzSagas(Configuration)
.AddSaga<OrderSaga>()
.AddSaga<PaymentSaga>();
Then finalize:
services.BuildFranzSagas(app.Services);
βοΈ Configuration (appsettings.json)
{
"Franz": {
"Sagas": {
"Persistence": "EntityFramework",
"EnableValidation": true,
"EnableAuditing": true,
"EntityFrameworkSchema": "sagas"
}
}
}
Supported persistence values:
| Value | Provider |
|---|---|
"Memory" |
Fast, volatile store (default) |
"EntityFramework" |
SQL-backed persistent store |
"Redis" |
Redis-based store (stub) |
"Kafka" |
Kafka compacted-topic storage (stub) |
𧬠Saga State Persistence
Every saga has a unique SagaId, which is:
- Extracted using
IMessageCorrelation<TMessage> - Used as the primary key of the persisted state
Persistence layer implements:
ISagaRepository
{
Task<object?> LoadStateAsync(...);
Task SaveStateAsync(...);
Task DeleteStateAsync(...); // optional
}
π οΈ Execution Pipeline
SagaExecutionPipeline provides a middleware-like wrapping:
await _pipeline.ExecuteAsync(() =>
handler.Invoke(saga, new object[] { message, ctx, token })
);
Allows adding:
- retries
- monitoring
- execution time metrics
- tracing
- global behaviors
π Auditing & Logging
Structured logs:
SagaLogEvents.StepStart(logger, sagaType, sagaId, messageType);
SagaLogEvents.StepComplete(logger, sagaType, sagaId, outgoingMessage, error);
SagaLogEvents.HandlerError(logger, sagaType, sagaId, messageType, ex);
Audit record:
SagaAuditRecord contains:
- SagaId
- SagaType
- StateType
- StepType
- IncomingMessageType
- OutgoingMessageType
- Duration
- Timestamp
- Serialized state
Default Sink β ILogger
ISagaAuditSink = DefaultSagaAuditSink
Users can override:
.AddAuditSink<ElasticSagaSink>();
π§© DI Extensions
The extension method:
AddFranzSagas(IConfiguration)
does the following:
- Loads
FranzSagaOptions - Registers
SagaRouter(provider) - Registers
SagaOrchestrator - Registers execution pipeline
- Configures persistence provider
- Configures audit sinks
- Returns builder (
FranzSagaBuilder)
Finally:
BuildFranzSagas(IServiceProvider)
validates + registers all sagas at startup.
π§ͺ Unit Testing
The in-memory provider is ideal for tests:
services
.AddFranzSagas(Configuration)
.AddSaga<TestSaga>();
services.Configure<FranzSagaOptions>(opts =>
{
opts.Persistence = "Memory";
opts.EnableValidation = true;
});
π§± Design Philosophy
Franz.Common.Messaging.Sagas follows the core Franz principles:
β Deterministic
Explicit, predictable execution. Zero ambiguity.
β pluggable
Storage, logging, and middleware are fully modular.
β transport-agnostic
Kafka, RabbitMQ, Azure Service Bus, HTTP, or anything else.
β lightweight
Zero reflection at runtime except for initial discovery.
β safe by default
Automatic validation + safe fallback persistence.
π Conclusion
Franz.Common.Messaging.Sagas (v1.6.21) brings first-class saga orchestration into the Franz ecosystem, enabling:
- long-running business workflows
- reliable distributed coordination
- strongly-typed message-driven state machines
- seamless integration with the Franz mediator and messaging frameworks
- full auditability
- easy testing
- lightweight, modular design
| 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
- Franz.Common.Business (>= 1.7.4)
- Franz.Common.DependencyInjection (>= 1.7.4)
- Franz.Common.EntityFramework (>= 1.7.4)
- Franz.Common.Errors (>= 1.7.4)
- Franz.Common.Mediator (>= 1.7.4)
- Franz.Common.Messaging (>= 1.7.4)
- Franz.Common.Messaging.Kafka (>= 1.7.4)
- Franz.Common.Messaging.RabbitMQ (>= 1.7.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.