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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Franz.Common.Messaging.Sagas" Version="1.7.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Franz.Common.Messaging.Sagas" Version="1.7.4" />
                    
Directory.Packages.props
<PackageReference Include="Franz.Common.Messaging.Sagas" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Franz.Common.Messaging.Sagas --version 1.7.4
                    
#r "nuget: Franz.Common.Messaging.Sagas, 1.7.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Franz.Common.Messaging.Sagas@1.7.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Franz.Common.Messaging.Sagas&version=1.7.4
                    
Install as a Cake Addin
#tool nuget:?package=Franz.Common.Messaging.Sagas&version=1.7.4
                    
Install as a Cake Tool

πŸ“¦ 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)
  • SagaTransition system for outgoing messages

βœ” Saga Execution Engine

  • SagaOrchestrator
  • SagaRouter
  • SagaExecutionPipeline (middleware-like wrapping)

βœ” Validations

  • SagaTypeValidator
  • SagaMappingValidator
  • 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.7.4 84 12/27/2025
1.7.3 168 12/22/2025
1.7.2 167 12/21/2025
1.7.1 111 12/20/2025
1.7.0 267 12/16/2025
1.6.21 182 11/27/2025