Under mobile network retries, gateway timeouts, or rapid user clicks, identical write requests (e.g. “Create Order”, “Process Payment”) frequently arrive concurrently. Without server-side idempotency, this causes severe data corruption:
- Duplicate orders inserted into databases;
- Customers charged multiple times, causing critical financial discrepancies.
BitzOrcas.Modern includes an enterprise-grade Idempotency Engine: Clients provide an Idempotency-Key header, while IdempotencyPipelineBehavior executes “Concurrent Mutex Locking + Response Caching + Transparent Replays”.
Idempotency Execution Lifecycle
Step 1: Annotating Request Contracts
Have Commands implement IIdempotentRequest:
using BitzOrcas.Application.Abstractions.Idempotency;using BitzOrcas.Domain.Results;using Mediator;
namespace BitzOrcas.Ordering.Contracts.Commands;
// Implements IIdempotentRequest to declare pipeline protectionpublic sealed record CreateOrderCommand( string ProductId, int Quantity, string IdempotencyKey) : ICommand<Result<string>>, IIdempotentRequest{ // Expose key for pipeline resolution string IIdempotentRequest.IdempotencyKey => IdempotencyKey;}Step 2: Automated Pipeline Interception
IdempotencyPipelineBehavior intercepts requests before starting transactions:
using System;using System.Threading;using System.Threading.Tasks;using BitzOrcas.Domain.Results;
public static class IdempotencyErrors{ public static readonly Error RequestInProgress = Error.Conflict("System.RequestInProgress", "Request currently processing, please do not resubmit.");}
public sealed class IdempotencyPipelineBehavior<TRequest, TResponse>( IIdempotencyStore store, ICurrentTenant currentTenant) : IPipelineBehavior<TRequest, TResponse> where TRequest : IIdempotentRequest{ public async ValueTask<TResponse> Handle( TRequest message, CancellationToken cancellationToken, MessageHandlerDelegate<TRequest, TResponse> next) { var tenantId = currentTenant.Tenant.EffectiveTenantId; var compositeKey = $"idempotency:{tenantId}:{message.IdempotencyKey}";
// 1. Attempt atomic lock acquisition (60s in-flight lease) var lockResult = await store.TryAcquireAsync(compositeKey, cancellationToken); if (lockResult.IsCompleted) { // 2. Request was completed previously: replay cached response directly return (TResponse)lockResult.CachedResponse!; }
if (!lockResult.Acquired) { // 3. Concurrent request currently executing: short-circuit with conflict return (TResponse)(object)Result.Failure(IdempotencyErrors.RequestInProgress); }
// 4. Fresh request: proceed to inner business handler var response = await next(message, cancellationToken);
// 5. Cache successful response payload (24h retention for replays) await store.SaveResponseAsync(compositeKey, response, TimeSpan.FromHours(24), cancellationToken);
return response; }}Summary
BitzOrcas idempotency protects critical business paths:
- Zero Handler Coupling: Implements
IIdempotentRequestwith zero extra handler code; - Concurrency Safe: Atomic locks eliminate race conditions;
- Seamless Replays: Clients retry safely with identical responses.