OutboxRelay is a robust message relay system implementing the Outbox pattern to ensure reliable message delivery in distributed systems. It guarantees at-least-once delivery semantics while maintaining data consistency through atomic transactions.
- Outbox Pattern Implementation: Ensures reliable message delivery with transactional consistency
- At-least-once Delivery: Guarantees message delivery even in case of failures
- Atomic Transactions: Maintains data consistency across database and message operations
- Concurrent Processing Safety: Thread-safe message handling with SQL Server locks
- Idempotent Consumer: Handles duplicate messages gracefully through status checks
- Retry Mechanism: Database-level exponential backoff for failed deliveries
- Publisher/Consumer Architecture: Separate worker services for publishing and consuming messages
- Logging: Comprehensive logging for tracking message flow and debugging
- .NET 8: Latest .NET runtime with improved performance and features
- Entity Framework Core 9: Modern ORM with code-first approach
- SQL Server: Robust database engine for storing transactions and outbox messages
- RabbitMQ 7.1.2: Message broker for reliable message delivery
- Unit of Work Pattern: Ensures transaction consistency
- Repository Pattern: Clean data access abstraction
The project implements the Outbox pattern to handle distributed transactions reliably, with several key safety mechanisms:
-
Transaction Flow:
- Incoming transaction is saved to the database
- Outbox message is created in the same transaction
- Publisher service picks up pending messages
- Messages are published to RabbitMQ
- Consumer processes messages and updates transaction status
-
Concurrency Safety:
- Publisher Concurrency: Uses SQL Server's
UPDLOCKandREADPASThints in to prevent duplicate message processing when multiple publisher instances are running - Consumer Concurrency: Implements pessimistic locking with
UPDLOCKin to prevent race conditions during message consumption - Idempotent Consumer: Handles duplicate messages through transaction status checks, ensuring at-least-once delivery without side effects
- Publisher Concurrency: Uses SQL Server's
-
Retry Management:
- Implements database-level exponential backoff
- Prevents self-DDoS during service outages
- Automatically adjusts retry intervals based on failure count
-
Components:
OutboxRelay.Api: REST API for transaction creationOutboxRelay.PublisherWorker: Background service for message publishingOutboxRelay.ConsumerWorker: Background service for message consumingOutboxRelay.Core: Domain models and database contextOutboxRelay.Infrastructure: Data access and message broker implementation
- .NET 8 SDK
- SQL Server 2022
- RabbitMQ 7.1.2
- Clone the Repository
git clone https://github.com/leventozz/OutboxRelay.git
cd OutboxRelay- Configure Connection Strings
Update appsettings.json in each project:
{
"ConnectionStrings": {
"MSSQL": "Server=localhost;Database=OutboxRelay;Trusted_Connection=True;TrustServerCertificate=True"
},
"RabbitMQ": {
"HostName": "localhost",
"Port": 5672,
"UserName": "guest",
"Password": "guest"
}
}- Run the Projects
# Start API
dotnet run --project OutboxRelay.Api
# Start Publisher Worker
dotnet run --project OutboxRelay.PublisherWorker
# Start Consumer Worker
dotnet run --project OutboxRelay.ConsumerWorkerThe database will be automatically created on first run using EF Core's EnsureCreated().
POST /api/Transactions/CreateTransaction
Content-Type: application/json
{
"fromAccountId": 1,
"toAccountId": 2,
"amount": 100.00
}- Transaction is created via API
- Outbox entry is created in the same transaction
- Publisher worker picks up pending messages
- Messages are published to RabbitMQ
- Consumer worker processes messages and updates transaction status
OutboxRelay/
├── OutboxRelay.Api/ # REST API
├── OutboxRelay.Application/ # Application logic
├── OutboxRelay.Common/ # Shared components
├── OutboxRelay.ConsumerWorker/ # Message consumer
├── OutboxRelay.Core/ # Domain models
├── OutboxRelay.Infrastructure/ # Data access & messaging
└── OutboxRelay.PublisherWorker/ # Message publisher
AppDbContext: EF Core database context implementing code-first approach with optimized table structures and indexesIUnitOfWork: Ensures transactional consistency across multiple operations with automatic rollback on failuresOutboxRepository: Handles atomic message claiming using UPDLOCK/READPAST and implements database-level exponential backoff logicRabbitMqPublisher: Manages reliable message publishing with connection recovery and channel managementTransactionConsumedHandler: Ensures idempotent message processing and handles consumer-side pessimistic locking to prevent race conditions
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
- Visual Studio 2022 or later
- SQL Server Management Studio
- RabbitMQ Management Console
- Follow C# coding conventions
- Use async/await for I/O operations
- Implement proper exception handling
- Add appropriate logging
- Write unit tests for new features
This project is licensed under the MIT License - see the LICENSE file for details.