TransactionInProgressException

TL;DR — 一次 TransactWriteItems 重试携带了与一次_仍在执行_的尝试相同的 ClientRequestToken。这通常是你的客户端超时快于事务完成,因此 SDK 的重试与进行中的原始请求碰撞了。用退避继续重试——在原始请求完成后的一次较晚重试会返回幂等的成功——并调优超时,使至少一次重试在约 5 秒后落地。

含义

TransactionInProgressException: The transaction with the given request token
is already in progress.

ClientRequestTokenTransactWriteItems 具有幂等性:10 分钟窗口内相同的调用算作一个事务。当第一次尝试仍在被处理时,用相同 token 的第二次调用还无法被应答——它既不是一个已完成事务的重复,也不是一个新的——因此 DynamoDB 用这个异常拒绝它。它是一个时序信号,而非数据错误。

为什么会发生

  • 客户端超时短于事务延迟——请求超时触发,SDK 重试,而重试在原始事务仍在提交时到达。
  • 激进的重试策略——很短的退避意味着几次重试可能堆到一个需要几秒的事务上。
  • 两个调用者共享一个 token——不同的进程有意(或无意)并发地发出同一个 ClientRequestToken

如何修复

  1. 让重试用指数退避继续——一旦进行中的事务完成,用相同 token 的一次重试会返回成功,而不会把写入应用两次。把这个异常当作可重试。

  2. 按文档指引调优超时,使一次重试能在事务稳定后落地:

    • 允许至少一次重试在自第一次尝试起过了 5 秒之后被处理;
    • 把逐请求超时设为大约 1 秒或更高
    • 让套接字超时略低于请求超时;
    • 在尝试之间使用指数退避。
  3. 不要在重试时轮换 token——每次尝试生成一个新的 ClientRequestToken 会悄悄地把重试变成_新事务_(把写入应用两次)。相同意图、相同 token,最长 10 分钟:

    const token = randomUUID(); // one token per logical transaction
    await client.send(new TransactWriteItemsCommand({TransactItems, ClientRequestToken: token}));
  4. 串行化有意的并发调用者——如果两个 worker 可能提交同一个逻辑事务,就让其中一个成为所有者,或把两者都通过一个队列路由。

如果事务运行得足够久以致触发超时,检查它们在争用什么——DynoTable 桌面应用让你检查涉及的项目,而 DynamoDB 定价计算器会显示事务性写入翻倍的写入容量的成本。

相关错误

References

最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。

无需控制台即可使用 DynamoDB

DynoTable 是面向 DynamoDB 的快速桌面客户端 —— 浏览表、运行 SQL 风格的查询,并在本地编辑项。