https://github.com/gokayokutucu/lycia
Idempotent, extensible, and powerful saga framework with scheduling — Rebus simplicity with MassTransit power
https://github.com/gokayokutucu/lycia
choreography-saga event-driven-architecture message-middleware orchestration-saga saga-pattern
Last synced: 5 months ago
JSON representation
Idempotent, extensible, and powerful saga framework with scheduling — Rebus simplicity with MassTransit power
- Host: GitHub
- URL: https://github.com/gokayokutucu/lycia
- Owner: gokayokutucu
- License: apache-2.0
- Created: 2023-05-27T11:22:33.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2025-11-27T09:35:53.000Z (7 months ago)
- Last Synced: 2025-11-28T01:25:49.411Z (7 months ago)
- Topics: choreography-saga, event-driven-architecture, message-middleware, orchestration-saga, saga-pattern
- Language: C#
- Homepage:
- Size: 1.98 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Lycia
[](https://www.nuget.org/packages/Lycia)
[](https://www.nuget.org/packages/Lycia)

[](https://github.com/gokayokutucu/lycia/actions/workflows/dotnet.yml)
[](https://opensource.org/licenses/Apache-2.0)
[](https://github.com/gokayokutucu/lycia/releases)
**Lycia** is the **main package** of the Lycia framework.
It provides the saga infrastructure, orchestration, and choreography support.
Extensions (e.g. Redis, RabbitMQ, Scheduling, Observability) are published separately under `Lycia.Extensions.*`.
**Lycia** began with a vision on *May 28, 2023*.
Our motto: *“Turning difficult paths into joyful simplicity.”* Inspired by the ancient *Lycian Way*, we set out to build a framework that makes complex saga workflows easy to manage — supported by strong documentation and aligned with modern software practices.
Lycia is a messaging framework (Message-oriented Middleware, MoM) built for .NET applications, supporting .NET Standard 2.0 and higher. It provides a robust foundation for distributed systems where reliable message flow and state coordination are essential.
For architectural deep-dive, compensation coordination, and integration test strategies, see [DEVELOPERS.md](DEVELOPERS.md).
---
## Getting Started / Samples
Explore the [samples/](samples) folder for real-world usage:
- **Sample.Order.Api** – API entrypoint
- **Sample.Order.Orchestration.Consumer** – Coordinated Responsive Saga (asynchronous request–response orchestration using `CoordinatedResponsiveSagaHandler`)
- **Sample.Order.Choreography.Consumer** – Reactive Saga (stateless event-driven choreography using `ReactiveSagaHandler`)
- **Sample.Order.Orchestration.Seq.Consumer** – Coordinated Saga (stateful sequential orchestration using `CoordinatedSagaHandler`, with compensation flows)
---
## Our Mission
- **Simplicity**: Define complex orchestration flows with ease.
- **Flexibility**: Support both orchestration (which we call *Coordinated Saga*) and choreography (our term: *Reactive Saga*) patterns.
- **Portability**: Work out of the box with popular infrastructures like RabbitMQ and Redis.
- **Robust Documentation**: Step-by-step guides, code samples, and best practices to lead the way.
---
## What Makes Lycia Different
Unlike other frameworks, Lycia offers:
- **Minimal Setup** – Start with a single line:
```csharp
services.AddLycia(Configuration)
.AddSagasFromCurrentAssembly()
.Build();
```
- **Clear Naming and Semantics**:
- *Coordinated Saga* → central orchestrator-based saga management
- *Reactive Saga* → event-driven choreography approach
- Built-in support for **idempotency**, **timeouts**, and **in-process retries with Polly, Ack/Nack + DLQ support on RabbitMQ**
- **Default Middleware Pipeline (Logging + Tracing + Retry, replaceable via UseSagaMiddleware)**
- **Extensibility**: Easily plug in custom implementations of `IMessageSerializer`, `IEventBus`, or `ISagaStore`.
---
## Quick Start
**Coordinated Saga**: Uses a central orchestrator to manage the full lifecycle of a saga. This handler starts a saga, executes the business logic step-by-step, and coordinates the flow by publishing commands/events. Ideal when you need deterministic, centralized control.
**Stateful Model**: Coordinated sagas always use `TSagaData` to maintain saga state across all steps.
**Coordinated Saga (Orchestration)**
```csharp
public class CreateInvoiceSagaHandler :
StartCoordinatedSagaHandler
{
public override async Task HandleAsync(CreateInvoiceCommand cmd, CancellationToken ct = default)
{
// business logic
await Context.Publish(new InvoiceStartedEvent { InvoiceId = cmd.InvoiceId }, ct);
await Context.MarkAsComplete(ct);
}
}
```
**Reactive Saga**: Implements event-driven choreography. Each handler reacts only to the event it subscribes to. There is no central orchestrator; instead, services collaborate by emitting events. Ideal for loosely coupled systems and autonomous microservices.
**Stateless Model**: Reactive sagas do not use saga state (`TSagaData`); each event is handled independently without maintaining cross-step state.
**Reactive Saga (Choreography)**
```csharp
public class InventorySagaHandler :
ReactiveSagaHandler,
ISagaCompensationHandler
{
public override async Task HandleAsync(OrderCreatedEvent evt, CancellationToken ct = default)
{
// Reserve inventory
await Context.Publish(new InventoryReservedEvent { OrderId = evt.OrderId }, ct);
await Context.MarkAsComplete(ct);
}
public Task CompensateAsync(PaymentFailedEvent failed, CancellationToken ct = default)
{
// Release reserved stock
InventoryService.ReleaseStock(failed.OrderId);
return Task.CompletedTask;
}
}
```
### Additional Saga Handler Examples
**Coordinated Responsive Saga**: Similar to a coordinated saga, but also handles direct responses (e.g., request/response patterns). Useful when the saga step must wait for a specific success or failure message before moving forward.
Like all coordinated sagas, this pattern is **stateful** and requires a `TSagaData` object to track progress across asynchronous request–response steps.
**CoordinatedResponsiveSagaHandler**
```csharp
public class CreateOrderSagaHandler :
StartCoordinatedResponsiveSagaHandler
{
public override async Task HandleAsync(CreateOrderCommand cmd, CancellationToken ct = default)
{
// Business logic
await Context.Publish(new OrderCreatedResponse { OrderId = cmd.OrderId }, ct);
await Context.MarkAsComplete(ct);
}
public override async Task HandleSuccessResponseAsync(OrderCreatedResponse response, CancellationToken cancellationToken = default)
{
// Order created, reserve inventory
await Context.Send(new ReserveInventoryCommand
{
OrderId = response.OrderId,
ParentMessageId = response.MessageId
}, cancellationToken);
await Context.MarkAsComplete();
}
}
```
---
### What Lycia Emits
- A span per saga step (`Saga.`)
- Attributes:
- `lycia.saga.id`
- `lycia.message.id`
- `lycia.correlation.id`
- `lycia.application.id`
- `lycia.saga.step.status`
- Automatic W3C trace propagation through messages (RabbitMQ / EventBus)
### How It Works
Tracing is added without requiring any saga code changes:
- The middleware creates spans around each handler invocation.
- `LyciaTracePropagation` injects `traceparent`/`tracestate` into message headers.
- The listener extracts headers and restores parent-child relationships.
This produces a full cross-service trace chain in Grafana Tempo or Jaeger.
---
## Timeline
- **May 28, 2023** – The idea was born.
- **Initial Goal** – To provide a saga framework that avoids complexity and is easy to use by anyone.
- **Today** – Development accelerated by "vibe-coding"; includes tests, integrations, and real-world usage scenarios.
---
## What's Next
- **Native Inbox / Outbox Guarantees**
- State-consistency
- Cross-service delivery reliability
- Message replay safety
- **Distributed Delayed Message Scheduling**
- Compensation timers
- Cron-like orchestration intervals
- Durable timing guarantees
- **Schema Intelligence**
- Avro/Protobuf registry integration (including the built‑in `AvroSchemaConverter`)
- Backward/forward compatibility detection
- Contract-driven saga evolution
## License
This project is licensed under the [Apache 2.0 License](LICENSE).
---
## Why Lycia? (Deep Dive Highlights)
In addition to minimal setup and clear semantics, Lycia offers:
- **SagaDispatcher** and **CompensationCoordinator** core components
- **Built-in Idempotency** and cancellation flow (`MarkAsCancelled()`)
- **Custom Retry Hooks** finalized via `IRetryPolicy` (with Polly-based default implementation, configurable via `ConfigureRetry`), supporting exponential backoff, jitter, and per-exception retry strategies
- **Choreography & Orchestration** support via `ReactiveSagaHandler` and `CoordinatedSagaHandler`
- **RedisSagaStore** built-in extension support with TTL, CAS, parent-child message tracing
- **RabbitMQ EventBus** built-in extension support with Dead Letter Queue (DLQ) and header normalization
- **ISagaContextAccessor** for contextual saga state access
- **Fluent Middleware Pipeline**: Default logging, retry, and tracing middleware (via `ActivityTracingMiddleware`), all replaceable via middleware slots (`ILoggingSagaMiddleware`, `IRetrySagaMiddleware`, `ITracingSagaMiddleware`)
- **Fluent Configuration API**: Easily plug your custom serializers, stores and buses
- **Detailed Integration Tests** for Redis, RabbitMQ (including Ack/Nack/DLQ behavior), Compensation logic
- **Appsettings.json Support**: Environment-based saga configuration