Skip to content
bitzorcas
中EN

Guide

Interface Idempotency and Replay: Idempotency-Key in Action

Master BitzOrcas.Modern interface idempotency. Learn Idempotency-Key contracts, Redis/DB deduplication stores, concurrency mutexes, and historical response replays.

Last updated

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

Completed - ResponseCachedIn-Flight - ConcurrentRequest RunningNew Key

1. Inbound Request (With Idempotency-Key)

2. IdempotencyPipelineBehavior

3. Query Idempotency Store (Redis / DB)

4. Replay Cached Response (Bypasses Handler)

5. Return 409 Conflict (In Progress)

6. Acquire Lease -> Execute Handler -> Cache Result


Step 1: Annotating Request Contracts

Have Commands implement IIdempotentRequest:

CreateOrderCommand.cs: Idempotent Contract
using BitzOrcas.Application.Abstractions.Idempotency;
using BitzOrcas.Domain.Results;
using Mediator;
namespace BitzOrcas.Ordering.Contracts.Commands;
// Implements IIdempotentRequest to declare pipeline protection
public 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:

IdempotencyPipelineBehavior.cs: Idempotency Pipeline
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 IIdempotentRequest with zero extra handler code;
  • Concurrency Safe: Atomic locks eliminate race conditions;
  • Seamless Replays: Clients retry safely with identical responses.

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%