SuperAPI AI 工具集

idempotency-patterns

编程与开发

查看项目

更新于 10-16 04:18

技能介绍

用途

Idempotency Patterns 用于在 Spring Boot 3 应用中实现幂等性,使重试的 HTTP 命令或消息处理不会因重复执行而产生重复副作用。它关注的是:当客户端重试、连接丢失或 worker 崩溃后重试时,如何保证同一操作只生效一次,并能安全地重放已产生的结果。

主要能力

定义幂等契约

需要明确以下要素:已认证的租户/主体、操作、幂等键、规范化请求哈希、保留窗口以及可重放的结果。唯一性应按主体/租户与操作进行限定;原始客户端键绝不能允许读取其他用户的结果。在初次执行和重放之前都要进行认证与授权。需要限制键长度和存储的响应大小。同时要记录同一键不同载荷以及仍在进行中的请求分别返回什么。

数据库本地效果

以 PostgreSQL 为例,模式与声明示例使用复合主键和 INSERT ON CONFLICT DO NOTHING RETURNING。在单个数据库事务中:声明键、应用业务写入、存储结果状态/响应体/选定响应头,然后提交。失败时随业务变更一起回滚声明。

如果插入未返回行,则在后续语句中于 READ COMMITTED 隔离级别下加载已有结果,比较规范化哈希,仅在匹配时重放。并发插入会等待唯一性约束;需要限制锁等待时间,并在超时时返回已记录的、可重试的结果。在快照隔离下,序列化失败需要重试整个事务。不要捕获唯一约束冲突后继续在已中止的事务中执行。

结果行与业务写入必须使用同一事务管理器和同一数据库。应返回存储的结果,而不是从可变的当前实体状态重建。重放响应头需使用允许列表;不要持久化 cookie、bearer token 或逐跳(hop-by-hop)头。

外部效果与消息

数据库事务无法原子地包含 HTTP 支付或邮件发送。应随业务变更一起写入 outbox 记录,让可重试的 worker 使用提供方的幂等支持来执行外部效果。在重试不可逆效果之前,先对不确定的结果进行对账。对于消息,记录唯一的消费者/事件对,并在一个事务中应用投影;仅在提交后确认。重试失败的事务,并有意识地路由毒消息。

保留策略

根据真实的客户端重试窗口定义保留期。删除键会允许后续重复请求再次执行;不要把 TTL 呈现为精确一次(exactly-once)保证。存储的响应应作为应用数据保护,并按项目的保留策略删除。

使用方式

示例以 Java 17 和该 Boot 版本支持的 Jakarta API 为基础,依赖由项目的 Boot BOM 管理。实现时按上述契约定义、数据库本地效果、外部效果与消息、保留策略的顺序落地,并配合验证环节进行测试。

验证

需要测试:同时到达的相同请求、冲突载荷、租户隔离、声明后回滚、连接丢失后的响应重放,以及 worker 崩溃后的重试。锁与隔离测试应使用生产数据库引擎,而不是 H2 兼容模式。资料中的坏示例展示了“先检查后执行”(check-then-act)的竞态。

常见陷阱

  • 先检查存在性再插入——应在数据库层面强制唯一性。
  • 仅用 JVM map 或 Redis TTL 作为业务防护——需与实际写入事务协调。
  • 重放其他租户的结果——需限定键范围并重新授权。
  • 超时后盲目重试外部效果——需对账或使用提供方幂等性。
  • 过早删除键——需记录重试窗口与过期语义。

适用场景与限制

适用于需要处理重试、重复请求或重复消息的 Spring Boot 3 后端服务,尤其是涉及支付、邮件等外部效果以及消息消费的场景。限制方面:数据库事务无法原子包含外部 HTTP 效果,需借助 outbox 与提供方幂等支持;TTL 不构成精确一次保证;锁等待与隔离级别会带来可重试的失败,需要按文档处理。官方参考来源包括 PostgreSQL INSERT 与 ON CONFLICT、PostgreSQL 事务隔离以及 Spring 事务管理。