Node.js での DynamoDB TransactWriteItems(AWS SDK v3)
成功した TransactWriteItemsCommand はほとんど何も教えてくれません。アイテムもなし、属性もなし、空のレスポンスです。必要なものはすべて例外の上にあるので、SDK v3 では以下の catch ブロックこそが本当の API 表面であり、そこに何が着地するのかを正確に知っておく価値があります。(そもそもトランザクションが正しい選択かどうかは DynamoDB のトランザクションを参照してください。)
コード
import {DynamoDBClient, TransactWriteItemsCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
// Move one award between two songs — atomically. If the first song has no
// award to give, NEITHER update happens.
const command = new TransactWriteItemsCommand({
TransactItems: [
{
Update: {
TableName: 'Music',
Key: {Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'Cubano Chant'}},
UpdateExpression: 'SET #upd0 = #upd0 - :one',
ConditionExpression: '#upd0 >= :one',
ExpressionAttributeNames: {'#upd0': 'Awards'},
ExpressionAttributeValues: {':one': {N: '1'}}
}
},
{
Update: {
TableName: 'Music',
Key: {Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'A Mis Abuelos'}},
UpdateExpression: 'SET #upd0 = if_not_exists(#upd0, :zero) + :one',
ExpressionAttributeNames: {'#upd0': 'Awards'},
ExpressionAttributeValues: {':one': {N: '1'}, ':zero': {N: '0'}}
}
}
]
});
try {
await client.send(command);
console.log('Transaction committed');
} catch (err) {
if (err.name === 'TransactionCanceledException') {
// One reason per action, in TransactItems order. 'None' means that action
// was fine — some OTHER action sank the transaction.
const codes = (err.CancellationReasons ?? []).map((r) => r.Code);
console.log('Transaction canceled:', codes); // e.g. ['ConditionalCheckFailed', 'None']
} else {
throw err;
}
}解説
TransactItems—Put、Update、Delete、ConditionCheckのアクションを並べた順序付き配列です。順序は実行順ではありません(トランザクションはアトミックです)が、失敗理由が返ってくる順序 です。順序を気にする理由はそれだけです。上限は後述します。- v3 が実際に投げるもの。捕まえたオブジェクト自身のプロパティは
$fault、$retryable、$metadata、name、CancellationReasons、message、__typeです。err.codeはありません。分岐に使う文字列はerr.nameで、err.$metadataはhttpStatusCode: 400とattempts: 1を運びます。これで SDK が黙ってキャンセルをリトライしなかったことが分かります。 CancellationReasonsは位置対応で、まばらです。上のトランザクションでは[{"Code":"ConditionalCheckFailed","Message":"The conditional request failed"},{"Code":"None"}]として返ります。NoneのエントリにはMessageプロパティ自体が存在しないので、err.CancellationReasons.map((r) => r.Message.trim())は、まさに成功したアクションのところでエラーハンドラーの中から例外を投げます。ReturnValuesOnConditionCheckFailure: 'ALL_OLD'は、そのアクションの理由にItemを、CodeとMessageより前に、生の DynamoDB JSON で追加します。負けたアイテムの属性が無料で返ってきます。代わりの手は、競合に負けた後の追加のGetItemです。err.nameによるチェックには穴があり、それがどれかは知っておく価値があります。2 つのアクションを同じアイテムに向けると、DynamoDB はTransaction request cannot include multiple operations on one itemというメッセージのValidationExceptionを返し、CancellationReasonsはまったくありません。何も試みられなかったからです。上のelse { throw err }の分岐がそれを再スローします。これはバグではなく正しい挙動ですが、構造的な誤りがキャンセルのログには決して届かないということでもあります。- v3 は省略しても
ClientRequestTokenをすでに送っています。シリアライズされたボディを捕捉すると、ワイヤー上に新しい UUID が現れ、同じコマンドオブジェクトに対する 2 回のsend()は 2 つの異なるトークンで出ていきました。つまりトークンが守るのは飛行中の 1 回の呼び出しであって、自分のリトライループではありません。catch して再送すれば、新しいトークンになり冪等性はありません。リトライがプロセス境界をまたぎうるなら自分のトークンを渡してください。パラメーターを 1 つでも変えて使い回すと、静かな二重適用ではなくIdempotentParameterMismatchになります。 - 専用のコード経路が要る他のコードは 1 つだけです。
TransactionConflictは、同時実行中のトランザクションがあなたのアイテムのどれかを保持していたという意味なので、バックオフ付きのリトライが正しい応答です。ConditionalCheckFailedでは決してそうではありません。残りは TransactionCanceledException のページで解説しています。 - コスト — トランザクション内の各アイテムは内部で 2 回書き込まれる(準備、次にコミット)ので、通常の書き込みの約 2 倍の書き込みキャパシティを見込んでください。単一アイテムの条件付き書き込みなら、その半分のコストで 1 アイテムのアトミック性が得られます。
どちらの上限に先に当たるか
100 アクションの上限と 4 MB の上限は独立していて、人を驚かせるのはバイト側です。カウンターのインクリメント 100 個は何でもありませんが、太ったアイテムが十数個あれば単独で合計を使い切れます。いくつのアクションをバッチにするかを決める前に、代表的なアイテムを DynamoDB アイテムサイズ計算ツールで計測してください。条件をまだ書いている最中に、アクションが触れるアイテムを読むには、DynoTable をダウンロードしてください。
関連する例
- Python での DynamoDB TransactWriteItems — boto3 による同じトランザクション。
- AWS CLI での DynamoDB TransactWriteItems — シェルからの同じトランザクション。
- Node.js での DynamoDB 条件付き書き込み — 2 倍のコストなしの単一アイテムのアトミック性。
- DynamoDB のトランザクション — 分離レベル、冪等性、そしてトランザクションが割に合うとき。
- DynamoDB TransactionCanceledException — キャンセル理由コードのすべてを解説。
- 「Too many actions in a TransactWriteItems call」 — 100 アクションと 4 MB のトランザクション上限。
- 「Transaction request cannot include multiple operations on one item」 — 1 トランザクションにつき 1 アイテム 1 アクション。
参考資料
- TransactWriteItems — Amazon DynamoDB API Reference
- Amazon DynamoDB transactions: how it works — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
最終検証日 2026-07-28、上記にリンクした公式 AWS ドキュメントに照らして確認しました。