Skip to content
bitzorcas
中EN

Guide

接口幂等去重与快速重放:Idempotency-Key 实践

深入解析 BitzOrcas.Modern 接口幂等性内核,掌握 Idempotency-Key 声明、Redis/DB 双层去重存储、并发请求互斥锁定与历史响应原样重放。

Last updated

在移动端网络抖动、网关超时重试或用户狂点提交按钮的场景下,同一个写请求(如“创建订单”、“扣款”)极易被重复发送多次。 如果服务端缺乏幂等保护,就会导致:

  • 数据库生成多张重复订单;
  • 账户被重复扣款多次,引发严重客诉与资损!

BitzOrcas.Modern 提供了开箱即用的工业级接口幂等机制:通过请求头携带 Idempotency-Key,由 IdempotencyPipelineBehavior 实现 “并发互斥锁定 + 成功响应缓存 + 重复请求原样重放”。

接口幂等执行状态机全景

已完成 - 已存在成功响应处理中 - 并发请求正在执行未执行 - 全新 Key

1. 入站请求 (携带 Idempotency-Key)

2. IdempotencyPipelineBehavior

3. 查询幂等存储 (Redis / Database)

4. 原样重放历史响应 (不重复执行业务)

5. 拦截并返回 409 Conflict (处理中请稍候)

6. 抢占互斥锁 -> 执行 Handler -> 缓存响应结果


第一步:在请求契约上启用幂等标记

让 Command 实现 IIdempotentRequest 接口:

CreateOrderCommand.cs: 启用幂等契约
using BitzOrcas.Application.Abstractions.Idempotency;
using BitzOrcas.Domain.Results;
using Mediator;
namespace BitzOrcas.Ordering.Contracts.Commands;
// 实现 IIdempotentRequest 声明该命令受幂等管道保护
public sealed record CreateOrderCommand(
string ProductId,
int Quantity,
string IdempotencyKey) : ICommand<Result<string>>, IIdempotentRequest
{
// 将命令中的 Key 映射给幂等管道识别
string IIdempotentRequest.IdempotencyKey => IdempotencyKey;
}

第二步:幂等管道工作机制

IdempotencyPipelineBehavior 在进入业务事务前进行自动拦截:

IdempotencyPipelineBehavior.cs: 幂等管道拦截流
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", "请求正在处理中,请勿重复提交。");
}
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. 尝试在存储中原子锁定该 Key(设置 60 秒处理中租约)
var lockResult = await store.TryAcquireAsync(compositeKey, cancellationToken);
if (lockResult.IsCompleted)
{
// 2. 该请求此前已成功执行过,直接反序列化历史响应并重放
return (TResponse)lockResult.CachedResponse!;
}
if (!lockResult.Acquired)
{
// 3. 另一个并发请求正在执行中,短路返回冲突
return (TResponse)(object)Result.Failure(IdempotencyErrors.RequestInProgress);
}
// 4. 首次执行:放行进入 Handler
var response = await next(message, cancellationToken);
// 5. 业务成功后,持久化响应载荷(保存 24 小时供重放)
await store.SaveResponseAsync(compositeKey, response, TimeSpan.FromHours(24), cancellationToken);
return response;
}
}

总结

BitzOrcas 的幂等防线为高并发交易提供了坚实兜底:

  • 零业务侵入:只需实现 IIdempotentRequest,无需在 Handler 写任何防重代码;
  • 并发安全:原子锁杜绝毫秒级并发穿透;
  • 原样重放:网络重试客户端无感知拿到原结果。

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%