TransactionInProgressException
TL;DR — 一次 TransactWriteItems 重试携带了与一次_仍在执行_的尝试相同的 ClientRequestToken。这通常是你的客户端超时快于事务完成,因此 SDK 的重试与进行中的原始请求碰撞了。用退避继续重试——在原始请求完成后的一次较晚重试会返回幂等的成功——并调优超时,使至少一次重试在约 5 秒后落地。
含义
TransactionInProgressException: The transaction with the given request token
is already in progress.ClientRequestToken 让 TransactWriteItems 具有幂等性:10 分钟窗口内相同的调用算作一个事务。当第一次尝试仍在被处理时,用相同 token 的第二次调用还无法被应答——它既不是一个已完成事务的重复,也不是一个新的——因此 DynamoDB 用这个异常拒绝它。它是一个时序信号,而非数据错误。
为什么会发生
- 客户端超时短于事务延迟——请求超时触发,SDK 重试,而重试在原始事务仍在提交时到达。
- 激进的重试策略——很短的退避意味着几次重试可能堆到一个需要几秒的事务上。
- 两个调用者共享一个 token——不同的进程有意(或无意)并发地发出同一个
ClientRequestToken。
如何修复
让重试用指数退避继续——一旦进行中的事务完成,用相同 token 的一次重试会返回成功,而不会把写入应用两次。把这个异常当作可重试。
按文档指引调优超时,使一次重试能在事务稳定后落地:
- 允许至少一次重试在自第一次尝试起过了 5 秒之后被处理;
- 把逐请求超时设为大约 1 秒或更高;
- 让套接字超时略低于请求超时;
- 在尝试之间使用指数退避。
不要在重试时轮换 token——每次尝试生成一个新的
ClientRequestToken会悄悄地把重试变成_新事务_(把写入应用两次)。相同意图、相同 token,最长 10 分钟:const token = randomUUID(); // one token per logical transaction await client.send(new TransactWriteItemsCommand({TransactItems, ClientRequestToken: token}));串行化有意的并发调用者——如果两个 worker 可能提交同一个逻辑事务,就让其中一个成为所有者,或把两者都通过一个队列路由。
如果事务运行得足够久以致触发超时,检查它们在争用什么——DynoTable 桌面应用让你检查涉及的项目,而 DynamoDB 定价计算器会显示事务性写入翻倍的写入容量的成本。
相关错误
- IdempotentParameterMismatchException——相同 token,_不同_载荷。
- TransactionCanceledException——事务本身失败了。
- TransactionConflictException——与另一个事务的项目级冲突。
- 代码示例:TransactWriteItems in Node.js——展示了 ClientRequestToken 的用法。
- 学习:DynamoDB transactions
References
- TransactWriteItems — Amazon DynamoDB API Reference
- Amazon DynamoDB Transactions: How it works — Amazon DynamoDB Developer Guide
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。