TransactionInProgressException

TL;DR — TransactWriteItems のリトライが、まだ実行中 の試行と同じ ClientRequestToken を運びました。これは通常、クライアントがトランザクションの完了より速くタイムアウトし、SDK のリトライが進行中のオリジナルと衝突するためです。バックオフで再試行を続けます — オリジナルが完了した後の後続のリトライは冪等な成功を返します — そして、少なくとも1回のリトライが約5秒後に着地するようタイムアウトをチューニングします。

意味

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

ClientRequestTokenTransactWriteItems を冪等にします: 10 分のウィンドウ内の同一呼び出しは1つのトランザクションとして数えられます。最初の試行がまだ処理されている間、同じトークンを持つ2つ目の呼び出しはまだ応答できません。完了したトランザクションの重複でも新しいものでもないため、DynamoDB はこの例外で拒否します。これはデータエラーではなくタイミングのシグナルです。

発生する理由

  • トランザクションのレイテンシーより短いクライアントタイムアウト — リクエストタイムアウトが発火し、SDK がリトライし、リトライが元のトランザクションがまだコミットしている間に到着する。
  • 積極的なリトライポリシー — 非常に短いバックオフは、数秒必要とするトランザクションに複数のリトライが積み重なることを意味する。
  • 1つのトークンを共有する2つの呼び出し元 — 別々のプロセスが意図的に(または偶発的に)同じ ClientRequestToken を並行して発行する。

修正方法

  1. 指数バックオフでリトライを続けさせます — 進行中のトランザクションが完了すると、同じトークンでのリトライは書き込みを2回適用せずに成功を返します。この例外をリトライ可能として扱います。

  2. トランザクションが落ち着いた後にリトライが着地できるよう、ドキュメント化されたガイダンスに従ってタイムアウトをチューニングします:

    • 最初の試行から 5 秒経過した後 に少なくとも1回のリトライが処理されるようにします。
    • リクエストごとのタイムアウトを約 1 秒以上 に設定します。
    • ソケットタイムアウトをリクエストタイムアウトより わずかに低く 保ちます。
    • 試行間で指数バックオフを使います。
  3. リトライ時にトークンをローテーションしないでください — 試行ごとに新鮮な ClientRequestToken を生成すると、リトライが黙って 新しいトランザクション に変わります(書き込みを二重適用)。最大 10 分間、同じ意図には同じトークンです:

    const token = randomUUID(); // one token per logical transaction
    await client.send(new TransactWriteItemsCommand({TransactItems, ClientRequestToken: token}));
  4. 意図的な並行呼び出し元を直列化します — 2つのワーカーが同じ論理トランザクションを送信できる場合、一方をオーナーにするか、両方をキュー経由でルーティングします。

トランザクションがタイムアウトを引き起こすほど長く実行される場合、何を競合しているか確認しましょう。DynoTable デスクトップアプリ は関与するアイテムを検査でき、DynamoDB 料金計算ツール はトランザクション書き込みの倍増した書き込みキャパシティのコストを表示します。

関連するエラー

References

最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

Console なしで DynamoDB を扱う

DynoTable は DynamoDB 向けの高速なデスクトップクライアントです — テーブルを閲覧し、SQL スタイルのクエリを実行し、アイテムをローカルで編集できます。