はじめに
GS2におけるトランザクション処理というのはユーザーデータの増減処理を指します。
たとえば、「課金通貨を消費してスタミナを回復する」というような操作です。
機能追加の背景
GS2はレスポンスタイムの最適化を日々行なっており、数百msのオーダーで処理が実行されます。
しかし、通信が完了するまでUIを更新しないとこの数百msのラグが違和感を生んでしまいます。
そこで、ユーザー体験を最適化するために投機的実行機能を実装しました。
追加された機能の詳細
GS2-Showcase の Buy や GS2-Exchange の Exchange 関数に第二引数
bool speculativeExecute = true
が追加されました。ここで投機実行機能を有効化するかを指定することができます。
記載の通り、デフォルトで有効化されます。
投機的実行のメカニズム
投機的実行処理を有効にしてトランザクション処理を実行すると、GS2-SDK は通信を開始する前にトランザクション実行後に期待される値でSDKがもつローカルキャッシュを更新します。
これによって、GS2-SDK を経由して取得される値も先行して期待される値に更新されます。
ローカルキャッシュを書き換えますが、このキャッシュの有効期限は10秒に設定され
10秒経ってもトランザクション処理が正常に完了しない場合は改めて最新の値をサーバーから取得します。
10秒以内にトランザクションが完了すれば、サーバーからのトランザクション完了通知を受け取ってキャッシュの有効期限がデフォルト値であれば15分に延長されます。
投機的実行できない処理
GS2-Money のストアプラットフォームのレシート検証や、GS2-Lottery の抽選処理などサーバーが処理しなければ結果がわからない処理については投機的実行は行われません。
投機的実行ができないトランザクション処理が含まれていた場合、以下の警告がコンソールに出力されます。
Speculative execution not supported on this action: XXX:XXX
投機的実行ができないだけで処理自体は今まで通り行われますので、サーバーからの完了通知をもってローカルキャッシュの更新が行われます。
そのため、この警告については深く気にする必要はありません。
投機的実行の入れ子
投機的実行処理はトランザクション処理が入れ子構造になっていても適用されます。
たとえば、GS2-Showcase で GS2-Exchange の交換処理を実行する入手アクションが設定された商品が登録されており、その商品を購入した場合は、GS2-Exchange の交換処理についても投機的実行が行われます。
連続的な処理でのチャタリング
投機的実行処理によって通信処理が完了しなくてもUI上は想定される最新の値を表示するようになったことで
交換処理のAPIを連打した時にUIのチャタリングが生じるようになる可能性があります。
具体的には以下のような順番で処理が発生した場合を想定してください。
アイテムを1個入手(処理A) -> アイテム数量1
アイテムを1個入手(処理B) -> アイテム数量2
サーバーで処理Aが完了 -> アイテム数量1
サーバーで処理Bが完了 -> アイテム数量2
この場合、一瞬アイテムの数量が 2 から 1 に巻き戻って表示されます。
このように高頻度(1秒に何度も)APIを呼び出すのであれば、API呼び出しをバッファリングし GS2-Showcase であれば Quantity、GS2-Exchange であれば Count の値を指定するようにすることで通信回数を削減で、チャタリングの発生を回避できます。