トランザクションアクションの組み合わせ
各サービスの API リファレンスには「1 つのトランザクションに指定できる組み合わせ」という表があります。 このページは、その表を読むための前提をまとめたものです。
アクションの「種別」
各サービスのアクション表にある「種別」は、そのアクションをトランザクションの検証・消費・入手のどの並びに置けるかを表します。
アクションの名前や実際の効果と一致しないことがあります。名前が Verify でも消費アクションだったり、何も更新しないのに入手アクションだったりします。
各サービスの表の読み方
各サービスのページには、そのサービスの操作を並べた表があります。
| 列 | 意味 |
|---|---|
| 操作 | まとめられる単位。同じ行に並ぶ操作どうしは 1 件に統合されます |
| 同じ行を重ねたとき | その行の操作を 1 つのトランザクションに複数指定した結果 |
| 入れ子越し | 同じ対象への更新が内側のトランザクションからも届いた場合の結果 |
| 別の対象になる境界 | ここが違えば別の対象なので、いくつ並べても衝突しません |
同じ境界の中で、違う行の操作を重ねるとトランザクションが失敗します。 行が分かれているのは、値を合成する方法が定義できないからです。
結果の欄には次の語を使います。
| 語 | 意味 |
|---|---|
| 統合される | 1 件にまとめられ、値が合算または結合されます |
| 同値なら統合 | 同じ値を指定していれば 1 件になります。値が違えば発行時にエラーになります |
| 先勝ち | エラーにならず、2 つ目以降が黙って捨てられます |
| 失敗する | トランザクションが失敗します (400)。リトライしても直りません |
| 衝突しない | 重ねてかまいません |
この 5 語で足りない場合、セルにはそのサービス固有の結果がそのまま書かれます。「後から届いたほうの値で上書きされる」「進行を触らない」のような記述がそれです。
検証アクションは読み取りしか行わないので、どの更新と同居させてもかまいません。検証の行だけは上の規則の例外です。
検証アクションどうしを重ねた場合、対象・検証タイプ・しきい値がすべて同じものだけが 1 つにまとめられます。どれか 1 つでも違えば、それぞれ独立に判定されます。
まとめられたときの扱いは 2 通りあり、アクションによって違います。
| 扱い | 結果 |
|---|---|
| しきい値が合算される | まったく同じ検証を 2 回書くと、しきい値が 2 倍の検証 1 件になります |
| 2 つ目が捨てられる | まったく同じ検証なので、結果は変わりません |
どちらになるかは各サービスのページに書いています。multiplyValueSpecifyingQuantity に false を明示したアクションはグループ化の対象から外れ、常にそれぞれ独立に判定されます。
「同じ行を重ねたとき」の欄にある「発行時にエラー」は、トランザクションを組み立てる時点で弾かれます。入れ子越しの場合はその検査が働かないため、同じ食い違いが実行時の失敗になります。どちらも 400 で、リトライしても直りません。
表に該当する行が見つからない場合、その組み合わせは指定してかまいません。「書かれていないので分からない」ではなく「制限がない」と読んでください。別のサービスのアクションどうしも衝突しません。
失敗の種類とリトライ
| 表の記述 | いつ拒否されるか | ステータス |
|---|---|---|
| トランザクションが失敗します | 実行時 | 400 |
| 発行時にエラーになります | 実行より前、トランザクションを組み立てる時点 | 400 |
どちらもトランザクションの組み方そのものの問題です。リトライしても直りません。
コンフリクト (409) は状態が競合しただけなので、リトライしてかまいません。ただしサービスによっては、リトライしても解消しないコンフリクトがあります。該当する場合は各サービスのページに書いています。
入れ子になったトランザクション
アクションの中には、そのアクション自身がさらに別のトランザクションを発行するものがあります。次が該当します。
抽選 (GS2-Lottery)、交換 (GS2-Exchange)、強化と解放 (GS2-Enhance)、報酬の受け取り (GS2-Mission / GS2-LoginReward / GS2-Idle / GS2-Ranking2)、メッセージの開封 (GS2-Inbox)、シリアルコードの使用 (GS2-SerialKey)、陳列棚からの購入 (GS2-Showcase)、ノードの解放 (GS2-SkillTree)、倍率の適用 (GS2-Experience / GS2-Grade)、スクリプトの実行 (GS2-Script)、ステートマシンの開始 (GS2-StateMachine)
各サービスの組み合わせの表は、1 つのトランザクションに直接指定したアクションどうしの話です。内側のトランザクションが発行する更新は、それらと統合されません。これは 2 つの形で起こります。
- 外側と内側 — トランザクションに直接指定したアクションと、内側のトランザクションが発行する更新が、同じ対象を触る
- 内側どうし — 2 つ以上の入れ子アクションが、それぞれの内側で同じ対象を触る
後者を見落としがちです。10 連の抽選、複数ステップのログインボーナスをまとめて受け取る、陳列棚から 2 商品を買う、といった構成はすべてこの形になります。入れ子どうしも統合されないので、外側と内側の場合とまったく同じ扱いです。
どちらも、その対象が 2 つの書き込みを許さない場合はトランザクションが失敗します。この衝突は不正なトランザクションとして扱われるので、リトライしても解消しません。
入れ子の中身をどう調べるか
入れ子のアクションが何を配る (消費する) かは、そのアクションが参照するマスタデータで決まります。抽選なら景品テーブル、ミッションなら報酬、シリアルコードならキャンペーン、ログインボーナスならボーナスモデルです。
配られるものの多くは GS2-Inventory のアイテム、GS2-Money2 の通貨、GS2-Experience の経験値です。同じ対象を外側でも触っていないかを、それぞれのサービスのページで確認してください。
制限を回避したい場合
ここまでの制限は、トランザクションを 1 回のアトミックなコミットとして実行することから来ています。実行の方針は、そのトランザクションを発行するネームスペースの トランザクション設定 で変更できます。入れ子の内側から届く更新との衝突も、外側のトランザクションを発行するネームスペースでこの設定を変えれば回避できます。
enableAtomicCommitを無効にすると、アクションがまとめてではなく 1 つずつ実行されるようになるため、同じ対象を複数のアクションが更新しても衝突しません。引き換えに、トランザクション全体が一括で成功・失敗する保証がなくなり、途中まで適用された状態があり得ます。acquireActionUseJobQueueを有効にすると、アトミックなコミットは維持したまま、入手アクションが 2 つ以上あるときにそれらを GS2-JobQueue 経由で 1 つずつ実行するようになります。検証アクションと消費アクションのアトミック性は保たれます。引き換えに入手アクションが非同期になり、トランザクションの応答時点では反映が完了していません。
どちらもネームスペースの設定で、そのネームスペースが発行するすべてのトランザクションに影響します。維持したい保証と見比べて選んでください。
acquireActionUseJobQueue が分離できるのは入手アクションどうしだけです。入手アクションと消費アクションの組み合わせで失敗する場合には効きません。どちらに当たるかは各サービスのページに書いています。
「発行時にエラーになります」と書かれているものは、どちらの設定でも解消しません。実行の方針より前、トランザクションを組み立てる時点の判定だからです。
実行順序と、各アクションが見る状態
検証アクション、消費アクション、入手アクションの順に実行されます。この順序はどの設定でも変わりません。
既定のアトミックなコミットでは、すべてのアクションがトランザクション開始時点の状態を基準に判定されます。同じトランザクションの他のアクションが行った変更は、どのアクションからも見えません。そのため「削除した結果を作成アクションが見る」「更新した結果を検証アクションが見る」といった組み方はできません。
enableAtomicCommit を無効にした場合と acquireActionUseJobQueue を有効にした場合は、入手アクションが 1 つずつ実行され、それぞれが直前までの結果を見ます。前者では消費アクションも 1 つずつ実行されるため、入手アクションはその結果も見ます。
ただし検証アクションと消費アクションが入手アクションより後に実行されることはありません。「入手したものを同じトランザクションで消費する」という組み方は、どの設定でもできません。順序が必要な場合はトランザクションを分けてください。