バッチ処理での確認

概要

Mobage JS SDKのアイテム購入のフローでは、 コインによるアイテム決済 にて先にモバコインが引き落とされ、アイテムの受注処理 はその後に行われます。このため、モバコインが引き落とされた直後にブラウザがクラッシュしたり、Clientからのアイテム付与リクエストが失敗すると、コインは引き落とされたのにアイテムがまだ付与されていないという状態になります。
 
これを防ぐための方法として、最も確実に付与漏れをリカバリできる枠組みが バッチを用いたアイテム購入の非同期確認処理 です。
ここでは、作成から一定時間以上経過した未処理の Transaction を全て確認し、「コインは引き落とされたのにアイテムがまだ付与されていない」という場合にアイテムを付与する機能を開発していきます。
 

作成するファイル一覧

このチュートリアルで作成するファイルは下記になります。

ファイル名

概要

config.php

各種設定値をまとめます

save_refresh_token.php

Refresh Token を Game Server の Database に保存します

bank_debit_get.php

Bank Debit API をつかって決済トランザクションを確認します

catcher.php

発行から一定時間以上経過した全ての未処理トランザクションの状態を確認し、場合によってアイテム付与をします

 

なお本文中で定義するテーブル定義はこのチュートリアルの為のサンプルなので、参考程度に留めて下さい。

 

チュートリアルをはじめる前に

このチュートリアルは、以下のチュートリアルを終わらせている前提で進めます。
以下のチュートリアルでファイル作成していない場合は、先にそちらを完成させましょう。

サンプルコードのダウンロード

Github からサンプルコードを clone できます。

また、以下のライブラリを利用するので、ダウンロードしておきます。

 

開発のステップ

バッチを用いたアイテム購入の非同期確認処理を実現するために、大きく以下の4ステップで進めます。

  1. Order DB から 一定時間経過した、未処理の Order データを取得する
  2. Access Token / Refresh Token を取得する
  3. Bank Debit API を用いて 決済 Transaction を確認する
  4. アイテム付与 / Order データの更新を実施する
※このチュートリアルでは、アイテム付与管理を行うテーブルを Order DB 、Order DB 上のトランザクションを表すデータを Order データ として解説を進めます。

Order DB から 一定時間経過した、未処理の Order データを取得する

アイテム購入処理を始める際に、決済 Transaction が作成されます。 この決済 Transaction は、ユーザの操作や時間の経過により、以下のいずれかの状態に変更されます。

  • open ( コイン引き落とし処理中 )
  • closed (正常終了)
  • canceled (キャンセルまたは失効)
  • error (エラー)
     
    Platform側での最終的な決済 Transaction の状態と、ゲームサーバの Order DB 内にある Order データは、下記のような理由で一致しないことがあります。
  • ユーザーが購入フローの途中で止まり、トランザクションの有効期限 (10分) が切れた
  • 購入フローの途中でブラウザを閉じてしまった
  • 購入フローの途中で通信状態が悪化して処理できなかった

これらのような理由で、「モバコインは引き落とされたが、アイテムは付与されていない」といったユーザーを救済するために、バッチ処理を実装します。

決済 Transaction が作成されて一定時間は、まだ購入処理の途中である可能性があります。 そのため、バッチ処理は、作成されて一定時間経過した Transaction に限定して処理を行います。
ここでは、作成されたから一定時間以上経過した Transaction に限定して処理を行います。

ここでは、アイテム付与状態の管理を行うテーブルを Order DB として下記のように定義しています。

上記に定義した Order DB は、あくまでこのチュートリアル用のサンプルであり、一例です。実際にゲームに実装する際には、ゲームの要件に従ったテーブルを定義してください。

 
このテーブルからSQLを利用して 一定時間以上経過した未処理の Transaction を抽出します。
抽出された 一定時間以上経過した未処理の Transaction について、1件1件 Bank Debit API を利用し、 Platfrom 側での状態を確認していきます。
TOC
 

Access Token / Refresh Token を取得する

作成後一定時間以上経過した未処理の決済 Transaction について、1件1件「モバコインが引き落とされたか」確認していきます。 
Platform側で「モバコインが引き落とされたか」を確認するためには、 Bank Debit API を利用します。 
 
Bank Debit API を利用するためには、Transaction ID と Access Token が必要となります。
Transaction ID は Order データのパラメタとして格納されていますが、Access Token は格納されていません。
 Access Token はユーザーごとに発行されているものなので、 Order データに格納されている User ID を利用して、 Access Token の取得の処理を実装します。

ユーザーが Mobage Connect にログインする際、Game Server では Token Request を実施して Access Token, Refresh Token を取得しています。
ここでは、これらの Token を Game Server で管理し、Bank Debit API の呼び出しを行う際に利用します。
以下に Access Token および Refresh Token の定義をまとめます。

token

説明

Access Token

RESTful API を呼び出す際に必要なトークンです。 OAuth 2.0 のBearer Token と呼ばれる形式です。 Mobage Connect では15 分間有効です。

Refresh Token

Access Token を再発行する際に必要なトークンです。Mobage Connect では90 日間有効です。(6. Refreshing an Access Token - RFC6749に利用方法が定義されています)

 
ここでは、Bank Debit API で利用する Access Token を、以下のように取得します。

  1. 有効期間の長い Refresh Token が発行された際に、 MySQL 上に保存します
  2. Refresh Token を利用して Access Token を再発行します
  3. 再発行したAccess Token を利用して Bank Debit API を呼び出します。
     
    ここから実装する Access Token の取得の方法は、あくまでこのチュートリアル用のサンプルであり、一例です。実際にゲームに実装する際には、ゲームの要件に従った方法を実装してください。

このチュートリアルでは、 Refresh Token を下記のようなMySQL上のテーブルで管理します。

また、 Refresh Token は、 Game Server が Refresh Token を取得した際、上記テーブルに保存します。

ユーザが Mobage Connect にログインする際、 Game Server にて Token Request を実施します。
その Token Request の Response で Refresh Token を受け取った際に、 Refresh Token を保存します。

 
Bank Debit API の利用で必要な Access Token は有効期間が15分間と短いため、 ここでは有効期間が90日間と長い Refresh Token を利用して Access Token を再発行します。Access Token を再発行するために、MySQL 上に保存された Refresh Token を取得して利用します。

Refresh Token を利用して Access Token を再発行します。Access Token は、Token Endpoint に対して Token Request を送ることで再発行されます。 
Token Endpoint は sandbox/service で以下のように異なる値となっています。

環境

URI

sandbox

https://sb-connect.mobage.jp/connect/1.0/api/token

service

https://connect.mobage.jp/connect/1.0/api/token

 
 
Client 認証に client_secret_post を利用した Token Request の例が下記になります。

また、Token Requestを送る処理は以下のように実装します。

mobage-jssdk-sample-payment/batch/catcher.php

 
Access Token を再発行するために、 Refresh Token を利用して Token Request を実行しましたが、Token Request が成功した場合 Token Responseでは下記のようなパラメタを取得できます。

key

value

access_token

Game Server から API を実行するための access_token が返されます。

token_type

Bearer

expires_in

900

refresh_token

grant_type=refresh_token による Token Request で改めて access token を得る為に必要なトークンです。発行時から90日間有効です。

scope

現在、クライアント向けに認可されているユーザーに関する権限を全て示すスペース区切りの文字列です。

Token Request により Access Token を再発行する際に、Refresh Token も新しい値が返ってくる場合があります。この場合、古い Refresh Token を利用できなくなるので、新しい Refresh Token をMySQL上のテーブルに上書き保存します。

 
次は Access Token を使って、Bank Debit API を呼び出します。

TOC

Bank Debit API を用いて 決済 Transaction を確認する

 
作成後一定時間以上経過した決済 Transaction について、モバコインが引き落とし済みか Bank Debit APIを使って確認するプログラムを作成します。

Bank Debit API を利用するためには、 Transaction ID と Access Token が必要です。
このチュートリアルでは、 Order DB の Order データに Transaction ID を格納しています。
一方で、 Access Token は Order DB に格納されておらず、 Order データに格納されている User ID を利用して、前述した方法にて Access Token を再発行しました。
この Transaction ID と Access Token を使って Bank Debit API の呼び出しを実施していきます。

Bank Debit APIの呼び出しは、OAuth 2.0 Bearer Tokenを利用して行います。
OAuth 2.0 の Bearer Token として、再発行したばかりの Access Token を利用します。

mobage-jssdk-sample-payment/bank_api_connectors/bank_debit_get.php

 
次に、curlを使ってBank Debit APIを呼び出します。Bank Debit API からのレスポンスから、決済 Transaction を取得します。

mobage-jssdk-sample-payment/bank_api_connectors/bank_debit_get.php

なお、Bank Debit API へのリクエスト、レスポンスの例は下記となります。

 
Bank Debit API から受け取ったレスポンスにより、該当 Transaction がモバコイン引き落とし済みか確認します。
モバコイン引き落とし済みかどうかは、state 値の状態を見ることで確認できるため、state 値を抽出します。

mobage-jssdk-sample-payment/batch/catcher.php

 
TOC

アイテム付与 / Order データの更新を実施する

作成後一定時間以上経過した未処理の Transaction について、「モバコイン引き落とされているがアイテム付与されていない」という状態であるか確認するためには、「モバコインの決済状態」と「アイテムの付与状態」の2つを確認する必要があります。これらを確認して、必要な場合にアイテムを付与するプログラムを作成します。

Bank Debit API から受け取ったレスポンス(決済トランザクション)内の state 値を確認することで、モバコインが引き落とされているか判断します。

この決済トランザクションの state 値は以下のように分けられます。

state

状態

処理途中か処理完了か

authorized

まだコインを引き落としていない

処理途中

error

エラー Platform により canceled に変更されます

処理途中

open

コインの引き落とし処理中 Platform により canceled に変更されます

処理途中

canceled

コインの引き落としはキャンセル済み

処理完了

closed

コインを引き落とし済み

処理完了

canceled, closed となった決済トランザクションの state 値は変更されることはありません。
Game Server ではアイテム未付与の Order DB の Order データのみを対象に処理しているので、「モバコインが引き落とされている」という状態の Order データ を対象とし、ユーザーにアイテムを付与します。

「アイテムの付与状態」を確認する上で忘れずに対応したいのが、「アイテムの付与状態」を確認して「アイテム付与される」まで、他のプロセスによって邪魔されない(アイテムを付与されない)ことを担保することです。

ここでは、処理が始まってアイテム付与が終わるまで他のプロセスによって邪魔されないように、Order データを排他制御する手法を採用します。
排他制御を取り入れることで、同じようなタイミングで複数プロセスからリクエストがあった際に、アイテムの間違った重複付与を防ぐことができます。
また、他プロセスに直前に Order データを更新されていることも考慮して、排他制御で取得した最新の Order データの確認も行います。

このチュートリアルでは下記のようにMySQLのストレージエンジンInnoDBを利用して行レベルでの排他制御を行い、最新の Order データを確認します。

mobage-jssdk-sample-payment/batch/catcher.php

 

「モバコインの決済状態」と「アイテムの付与状態」の比較と対応

「モバコインの決済状態」を表す決済トランザクションの state 値に応じてアイテム付与を行います。

決済 Transaction のstate値が 'authorized'/'open'/'error' である

決済 Transaction の state 値が authorized / open / error の場合は、まだ購入処理の途中であるため、
アイテム付与処理や Order データの更新は必要ありません。 ただし、Order データの排他制御は解放してください。

決済トランザクションのstate値が'canceled' である

決済トランザクションの state 値が canceled の場合は、モバコイン消費がキャンセル/失効済みの状態なので、ゲーム側でのアイテム付与処理は不要となります。
ここでは、Order データのみを更新して、該当トランザクションの処理を終了させます。また、Order データの排他制御を開放します。

決済 Transaction のstate値が'closed'である

決済 Transaction の state 値が closed の場合は、「モバコインは引き落とされているがアイテム付与されていない」という状態なので、アイテム付与処理を実行します。
このチュートリアルでは、ユーザのアイテムを管理するテーブルにレコードを追加/更新することでアイテムを付与します。
以下がこのチュートリアルで定義しているユーザのアイテム管理テーブルです。

上記に定義したアイテム管理テーブルは、あくまでこのチュートリアル用のサンプルであり、一例です。実際にゲームに実装する際には、ゲームの要件に従ったテーブルを定義してください。

 
上記のテーブル定義に従ってユーザーへのアイテム付与処理を実行し、Order データも更新することで、該当トランザクションの処理を終了させます。また、Order データの排他制御も開放します。

mobage-jssdk-sample-payment/batch/catcher.php

 
これらの処理により、 モバコインが引き落とされたのにアイテムが付与されていないユーザー に対して、網羅的にアイテム付与を行うことが出来ました。
 
TOC
 

動作確認

では、開発したプログラムを下記のように Game Server に配置します。
(* は バッチのプログラムをおいているディレクトリを想定しています。)

ファイル名

URL

config.php

*/mobage-jssdk-sample-payment/config.php

save_refresh_token.php

*/mobage-jssdk-sample-payment/batch/save_refresh_token.php

bank_debit_get.php

*/mobage-jssdk-sample-payment/bank_api_connectors/bank_debit_get.php

catcher.php

*/mobage-jssdk-sample-payment/batch/catcher.php

また、 mobage-jssdk-sample-payment/JWT/ に以下のライブラリを配置します。

なお、アイテムを購入するプログラムは、下記のチュートリアルで先に開発しておきます。

  • 事前にアイテム登録されている場合
  • 事前にアイテム登録されてない場合
     
    バッチによる非同期確認処理を実施する準備として、上記のアイテムを購入するプログラムを利用して何度か購入操作とキャンセル操作を繰り返し、下記のような Order DB とアイテム管理テーブルの状態を作り出します。
    上記の準備により、7度アイテムが購入され、3度購入がキャンセルされたこと、ユーザにアイテムが7つ付与されたことが分かります。

その後、 Game Server でのアイテム付与などの処理が失敗した状況を模擬的に作成するため、 Order DB の order_status を直接 authorized (アイテム未付与:処理途中) に変更します。

 

実際は購入処理が成功し、アイテムも付与されていますが、これは動作確認テストなので、その点は無視します。

また、仕様上一定時間以前のトラザクションだけを処理の対象にするので、 create_at のタイムスタンプを強制的に一定時間前に戻します。

これらのコマンドにより、Order DB には order_state が authorized (アイテム未付与:処理途中) で、作成されて 一定時間経過した 決済 Transaction と同様の Order データが作成されました。

 
前述した準備が整ったら、チュートリアルで開発したバッチを実行します。

バッチ処理が完了したら、Order DB が更新され、アイテムが再度付与されているか確認します。

上記のように、バッチ処理により再度アイテムが7つ付与され、元々付与されていた7個の倍である14個のアイテムを保持していることと、Order DB も正常に更新されたことを確認できました。

開発したコード

このチュートリアルで開発したコードは Github から clone できます。

利用したライブラリは下記になります。

 

更新履歴

  • 2016/04/14
    • 決済トランザクションの state 値の説明に open, canceled を追加
    • 確認処理を行う対象を、発行後 一定時間経過した決済トランザクションに変更
    • 決済トランザクションの有効期間を10分に修正

 

PREVIOUS

Client 側での即時確認処理

NEXT

推奨する課金フロー