{"id":37542591,"url":"https://github.com/gokayokutucu/lycia","last_synced_at":"2026-01-16T08:47:11.268Z","repository":{"id":295049791,"uuid":"646126858","full_name":"gokayokutucu/lycia","owner":"gokayokutucu","description":"Idempotent, extensible, and powerful saga framework with scheduling — Rebus simplicity with MassTransit power","archived":false,"fork":false,"pushed_at":"2025-11-27T09:35:53.000Z","size":2078,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-28T01:25:49.411Z","etag":null,"topics":["choreography-saga","event-driven-architecture","message-middleware","orchestration-saga","saga-pattern"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gokayokutucu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-05-27T11:22:33.000Z","updated_at":"2025-11-27T09:35:57.000Z","dependencies_parsed_at":"2025-06-20T13:26:00.328Z","dependency_job_id":"b1ceb6eb-bf72-4742-8ee2-729d67511e30","html_url":"https://github.com/gokayokutucu/lycia","commit_stats":null,"previous_names":["gokayokutucu/lycia"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/gokayokutucu/lycia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokayokutucu%2Flycia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokayokutucu%2Flycia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokayokutucu%2Flycia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokayokutucu%2Flycia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gokayokutucu","download_url":"https://codeload.github.com/gokayokutucu/lycia/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gokayokutucu%2Flycia/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["choreography-saga","event-driven-architecture","message-middleware","orchestration-saga","saga-pattern"],"created_at":"2026-01-16T08:47:11.151Z","updated_at":"2026-01-16T08:47:11.246Z","avatar_url":"https://github.com/gokayokutucu.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lycia\n\n[![NuGet](https://img.shields.io/nuget/v/Lycia.svg)](https://www.nuget.org/packages/Lycia)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/Lycia.svg)](https://www.nuget.org/packages/Lycia)\n![Target Framework](https://img.shields.io/badge/.NET-netstandard2.0%20%7C%20net8.0%20%7C%20net9.0-blue)\n[![Build](https://github.com/gokayokutucu/lycia/actions/workflows/dotnet.yml/badge.svg)](https://github.com/gokayokutucu/lycia/actions/workflows/dotnet.yml)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![GitHub release](https://img.shields.io/github/v/release/gokayokutucu/lycia)](https://github.com/gokayokutucu/lycia/releases)\n\n**Lycia** is the **main package** of the Lycia framework.  \nIt provides the saga infrastructure, orchestration, and choreography support.  \nExtensions (e.g. Redis, RabbitMQ, Scheduling, Observability) are published separately under `Lycia.Extensions.*`.\n\n**Lycia** began with a vision on *May 28, 2023*.  \nOur 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.\n\nLycia 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.\n\nFor architectural deep-dive, compensation coordination, and integration test strategies, see [DEVELOPERS.md](DEVELOPERS.md).\n\n---\n\n## Getting Started / Samples\n\nExplore the [samples/](samples) folder for real-world usage:  \n- **Sample.Order.Api** – API entrypoint  \n- **Sample.Order.Orchestration.Consumer** – Coordinated Responsive Saga (asynchronous request–response orchestration using `CoordinatedResponsiveSagaHandler`)  \n- **Sample.Order.Choreography.Consumer** – Reactive Saga (stateless event-driven choreography using `ReactiveSagaHandler`)  \n- **Sample.Order.Orchestration.Seq.Consumer** – Coordinated Saga (stateful sequential orchestration using `CoordinatedSagaHandler`, with compensation flows)  \n\n---\n\n## Our Mission\n\n- **Simplicity**: Define complex orchestration flows with ease.  \n- **Flexibility**: Support both orchestration (which we call *Coordinated Saga*) and choreography (our term: *Reactive Saga*) patterns.  \n- **Portability**: Work out of the box with popular infrastructures like RabbitMQ and Redis.  \n- **Robust Documentation**: Step-by-step guides, code samples, and best practices to lead the way.\n\n---\n\n## What Makes Lycia Different\n\nUnlike other frameworks, Lycia offers:\n\n- **Minimal Setup** – Start with a single line:\n\n```csharp\nservices.AddLycia(Configuration)\n        .AddSagasFromCurrentAssembly()\n        .Build();\n```\n\n- **Clear Naming and Semantics**:  \n  - *Coordinated Saga* → central orchestrator-based saga management  \n  - *Reactive Saga* → event-driven choreography approach  \n\n- Built-in support for **idempotency**, **timeouts**, and **in-process retries with Polly, Ack/Nack + DLQ support on RabbitMQ**  \n- **Default Middleware Pipeline (Logging + Tracing + Retry, replaceable via UseSagaMiddleware)**  \n- **Extensibility**: Easily plug in custom implementations of `IMessageSerializer`, `IEventBus`, or `ISagaStore`.\n\n---\n\n## Quick Start\n\n**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.\n\n**Stateful Model**: Coordinated sagas always use `TSagaData` to maintain saga state across all steps.\n\n**Coordinated Saga (Orchestration)**\n\n```csharp\npublic class CreateInvoiceSagaHandler :\n    StartCoordinatedSagaHandler\u003cCreateInvoiceCommand, CreateInvoiceSagaData\u003e\n{\n    public override async Task HandleAsync(CreateInvoiceCommand cmd, CancellationToken ct = default)\n    {\n        // business logic\n        await Context.Publish(new InvoiceStartedEvent { InvoiceId = cmd.InvoiceId }, ct);\n        await Context.MarkAsComplete\u003cCreateInvoiceCommand\u003e(ct);\n    }\n}\n```\n\n**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.\n\n**Stateless Model**: Reactive sagas do not use saga state (`TSagaData`); each event is handled independently without maintaining cross-step state.\n\n**Reactive Saga (Choreography)**\n\n```csharp\npublic class InventorySagaHandler :\n    ReactiveSagaHandler\u003cOrderCreatedEvent\u003e,\n    ISagaCompensationHandler\u003cPaymentFailedEvent\u003e\n{\n    public override async Task HandleAsync(OrderCreatedEvent evt, CancellationToken ct = default)\n    {\n        // Reserve inventory\n        await Context.Publish(new InventoryReservedEvent { OrderId = evt.OrderId }, ct);\n        await Context.MarkAsComplete\u003cOrderCreatedEvent\u003e(ct);\n    }\n\n    public Task CompensateAsync(PaymentFailedEvent failed, CancellationToken ct = default)\n    {\n        // Release reserved stock\n        InventoryService.ReleaseStock(failed.OrderId);\n        return Task.CompletedTask;\n    }\n}\n```\n\n### Additional Saga Handler Examples\n\n**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.\n\nLike all coordinated sagas, this pattern is **stateful** and requires a `TSagaData` object to track progress across asynchronous request–response steps.\n\n**CoordinatedResponsiveSagaHandler**\n\n```csharp\npublic class CreateOrderSagaHandler :\n    StartCoordinatedResponsiveSagaHandler\u003cCreateOrderCommand, OrderCreatedResponse, CreateOrderSagaData\u003e\n{\n    public override async Task HandleAsync(CreateOrderCommand cmd, CancellationToken ct = default)\n    {\n        // Business logic\n        await Context.Publish(new OrderCreatedResponse { OrderId = cmd.OrderId }, ct);\n        await Context.MarkAsComplete\u003cCreateOrderCommand\u003e(ct);\n    }\n    \n    public override async Task HandleSuccessResponseAsync(OrderCreatedResponse response, CancellationToken cancellationToken = default)\n    {\n        // Order created, reserve inventory\n        await Context.Send(new ReserveInventoryCommand\n        {\n            OrderId = response.OrderId,\n            ParentMessageId = response.MessageId\n        }, cancellationToken);\n        await Context.MarkAsComplete\u003cOrderCreatedResponse\u003e();\n    }\n}\n```\n\n---\n\n### What Lycia Emits\n\n- A span per saga step (`Saga.\u003cHandlerName\u003e`)\n- Attributes:\n  - `lycia.saga.id`\n  - `lycia.message.id`\n  - `lycia.correlation.id`\n  - `lycia.application.id`\n  - `lycia.saga.step.status`\n- Automatic W3C trace propagation through messages (RabbitMQ / EventBus)\n\n### How It Works\n\nTracing is added without requiring any saga code changes:\n- The middleware creates spans around each handler invocation.\n- `LyciaTracePropagation` injects `traceparent`/`tracestate` into message headers.\n- The listener extracts headers and restores parent-child relationships.\n\nThis produces a full cross-service trace chain in Grafana Tempo or Jaeger.\n\n---\n\n## Timeline\n\n- **May 28, 2023** – The idea was born.  \n- **Initial Goal** – To provide a saga framework that avoids complexity and is easy to use by anyone.  \n- **Today** – Development accelerated by \"vibe-coding\"; includes tests, integrations, and real-world usage scenarios.\n\n---\n\n## What's Next\n\n- **Native Inbox / Outbox Guarantees**\n  - State-consistency\n  - Cross-service delivery reliability\n  - Message replay safety\n  \n- **Distributed Delayed Message Scheduling**\n  - Compensation timers\n  - Cron-like orchestration intervals\n  - Durable timing guarantees\n\n- **Schema Intelligence**\n  - Avro/Protobuf registry integration (including the built‑in `AvroSchemaConverter`)\n  - Backward/forward compatibility detection\n  - Contract-driven saga evolution\n\n## License\n\nThis project is licensed under the [Apache 2.0 License](LICENSE).\n---\n\n## Why Lycia? (Deep Dive Highlights)\n\nIn addition to minimal setup and clear semantics, Lycia offers:\n\n- **SagaDispatcher** and **CompensationCoordinator** core components  \n- **Built-in Idempotency** and cancellation flow (`MarkAsCancelled\u003cT\u003e()`)  \n- **Custom Retry Hooks** finalized via `IRetryPolicy` (with Polly-based default implementation, configurable via `ConfigureRetry`), supporting exponential backoff, jitter, and per-exception retry strategies  \n- **Choreography \u0026 Orchestration** support via `ReactiveSagaHandler\u003cT\u003e` and `CoordinatedSagaHandler\u003cT\u003e`  \n- **RedisSagaStore** built-in extension support with TTL, CAS, parent-child message tracing  \n- **RabbitMQ EventBus** built-in extension support with Dead Letter Queue (DLQ) and header normalization  \n- **ISagaContextAccessor** for contextual saga state access  \n- **Fluent Middleware Pipeline**: Default logging, retry, and tracing middleware (via `ActivityTracingMiddleware`), all replaceable via middleware slots (`ILoggingSagaMiddleware`, `IRetrySagaMiddleware`, `ITracingSagaMiddleware`)  \n- **Fluent Configuration API**: Easily plug your custom serializers, stores and buses  \n- **Detailed Integration Tests** for Redis, RabbitMQ (including Ack/Nack/DLQ behavior), Compensation logic  \n- **Appsettings.json Support**: Environment-based saga configuration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgokayokutucu%2Flycia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgokayokutucu%2Flycia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgokayokutucu%2Flycia/lists"}