Saganator is a modular, extensible .NET framework that implements the Saga Pattern for managing distributed workflows, compensating failures, and maintaining consistency across microservices or complex domains.
It provides:
- Execution and compensation pipelines
- Activity chaining
- State bootstrapping and persistence
- Integration with Redis, EF Core, and In-Memory stores
- Complete Dependency Injection support
Modern microservices require reliable state coordination across boundaries. Saganator enables you to:
✅ Model distributed transactions
✅ Chain complex workflows with compensation
✅ Bootstrap saga state from databases
✅ Swap persistence mechanisms easily
✅ Integrate with .NET DI and hosted services
Saganator separates concerns into 4 key layers:
| Layer | Responsibility |
|---|---|
Saganator.Abstractions |
Interfaces and contracts |
Saganator |
Core implementation (execution, context) |
Saganator.DependencyInjection.Core |
DI setup and builder flow |
Saganator.Persistence.* |
Pluggable state repositories |
Saganator.Loader.* |
State bootstrappers (e.g., EF Core) |
- A message is dispatched via
ISagaCoordinator. - It resolves the registered activity via DI.
- Saga state is loaded and locked via
ISagaStateManager. - The activity is executed, and optionally compensated.
- Final state is saved via the repository.
| Interface | Purpose |
|---|---|
ISagaState |
Holds saga identity and state |
ISagaContext |
Execution metadata (timestamps, exceptions) |
ISagaExecuteActivity |
Stateless saga step |
ISagaActivity |
Step with compensation logic |
ISagaCoordinator |
Dispatches messages into the pipeline |
ISagaEventProcessor |
Executes saga logic |
ISagaStateManager |
Locks & updates saga state |
ISagaStateRepository |
Abstracts persistence (Redis/In-Mem/etc.) |
ISagaLoader |
Loads states on startup |
IStateMapper |
Transforms between entities and saga states |
services.AddSaga<OrderSagaState, Guid>(builder =>
{
builder.UseInMemoryPersistence();
builder.UseSagaActivity<StartOrderActivity, StartOrderMessage>();
});This will:
- Register all core services
- Setup saga event handling
- Wire up persistence
- Register hosted state loaders (if needed)
Saganator supports building chains of steps:
public class PaymentChain : SagaChainActivity<PaymentState, Guid, PaymentMessage>
{
public PaymentChain(...) : base(
new ValidateCardStep(),
new ReserveFundsStep(),
new CapturePaymentStep()) { }
public override async Task HandleChainAsync(...) { ... }
public override async Task CompensateChainAsync(...) { ... }
}Each node is reversible and composable.
| Module | Backend | Usage |
|---|---|---|
Saganator.Persistence.InMemory |
ConcurrentDictionary | Fast, simple, non-persistent |
Saganator.Persistence.Redis |
Redis Hashes | Distributed, scalable |
Saganator.Loader.EfCore |
EF Core + DbContext |
Bootstraps saga state from database |
builder.UseInMemoryPersistence();builder.UseRedisPersistence("localhost:6379");builder.UseEfCoreSagaLoader<OrderMapper, OrderState, Guid, OrderEntity, AppDbContext>();public class OrderPlacedActivity : ISagaActivity<OrderState, Guid, OrderPlaced>
{
public Task<OrderState> InitializeAsync(Guid id, OrderPlaced msg) => Task.FromResult(new OrderState { CorrelationId = id });
public Guid ResolveCorrelationId(OrderPlaced msg) => msg.OrderId;
public Task HandleAsync(OrderPlaced msg, ISagaContext<OrderState, Guid> ctx)
{
ctx.CurrentState.Status = "Processing";
return Task.CompletedTask;
}
public Task CompensateAsync(OrderPlaced msg, ISagaContext<OrderState, Guid> ctx)
{
ctx.CurrentState.Status = "Failed";
return Task.CompletedTask;
}
public Task ContextUpdatedAsync(ISagaContext<OrderState, Guid> ctx) => Task.CompletedTask;
}- ✅ Deep copy of state using expression trees
- ✅ HostedService integration for loaders
- ✅ Conditional mapping between states and entities
- ✅ Compensation flow for partial rollbacks
- ✅ Reflection-based activity registration via
UseActivities(...)
Saganator/
├── Abstractions/
├── Core/
├── Persistence/
│ ├── InMemory/
│ └── Redis/
├── Loader/
│ └── EfCore/
└── DependencyInjection.Core/
- Install via NuGet (structure ready)
- Register services with
AddSaga<TState, TId>(...) - Define and register your saga activities
- Send messages via
ISagaCoordinator
MIT License
PRs and discussions are welcome. Build powerful distributed workflows together.