🛍️

モンストWebショップの裏側:“商品購入”が完了するまで

に公開

MIXI M事業部エンジニアの田代です。

モンストWebショップ(以下Webショップ)は、モンスターストライク(以下モンスト)のアプリ外課金を実現するためのサイトです。MIXI M事業部が主体となり、モンストチームと連携して開発・運用しています。

https://webshop.monster-strike.com/

この記事ではWebショップにおける、購入の管理について焦点を当てて説明していきます。

Webショップシステム構成

はじめにWebショップのシステム構成について説明します。Webショップは複数のシステムを組み合わせて実現しています。

それぞれのシステムについて説明します。

  • Webショップ フロントエンド
    • ユーザーが直接操作する画面を提供する部分です。
    • Next.js(App Router)、Chakra UI、Amplify Hosting などのモダン技術を採用しています。
  • Webショップ バックエンド
    • Webショップフロントエンドからのリクエストを受け付け、決済システムやモンストゲームサーバーなどの関連システムと連携し、購入フロー全体を管理するサーバーです。
    • Webショップに必要な商品管理やその他の機能も有しています。
    • Elixirで実装しており、データベースにはDynamoDBを採用しています。
  • MIXI ID
    • Webショップの認証基盤として利用しており、ユーザーのログイン認証を行います。
    • 認証手段としては、メールやSMSによるOTP認証、パスキー認証、ソーシャルログインに対応しています。
    • OpenID Connect(OIDC)という標準化された仕様に準拠します。
    • モンストのデータ連携や他のMIXIサービスでも利用しています。
    • 参考: https://zenn.dev/mixi/articles/0f9af1ffd77f18
  • MIXI Payment
  • モンストゲームサーバー
    • モンスターストライクのゲームサーバーであり、Webショップからの購入に応じてアイテムの付与やゲームユーザー情報の提供を行います。

購入における状態遷移について

Webショップでの購入は次の流れで行います。

  1. ユーザーはMIXI IDを用いてストアサイトにログインします。
  2. ストア上で任意のアイテムを選択して購入に進みます。
  3. 決済を行い購入を完了します。
  4. アプリに戻って購入したアイテムを確認します。

ユーザー体験的には一般的なECサイトとほぼ同様です。違いとしてはカートの概念がないことがあげられます。
Webショップにカートが存在しない理由としては

  • 迅速にリリースしたかったこと
  • 複数アイテム付与や重複購入の取り消し等のイレギュラーケースへの考慮が複雑なこと

があげられます。

購入の各ステータスについて

Webショップバックエンドは購入フローを管理するためのモデルを実装しています。このモデルは購入の開始から完了までそれぞれに応じたステータスを持ちます。

ステータスは次の購入シーケンスに従い進行します。

Webショップの決済処理は承認と確定でステップが分かれます。流れ的には

  1. 決済の承認
  2. モンストゲームサーバーでのアイテム付与
  3. 決済の確定

となります。

各ステータスについて補足します。

  • 作成
    • ユーザーが商品を決定し、購入を開始した選択した状態です。
    • 決済処理は開始しておらず、この状態のまま進行しなかったトランザクションは一定時間の経過後削除されます。
  • 決済の開始
    • ユーザーが決済手段を選択し、決済処理が開始された状態です。
    • Paymentシステムにおいて決済データが作成されます。
  • 決済承認済み
    • 決済処理における3DS認証が完了し、オーソリ(与信)が得られた状態です。
    • この後、アイテムの付与処理が行われます。
  • 確定待ち
    • モンストゲームサーバーでのアイテム付与が成功し、決済の確定待ちの状態です。
    • この状態から決済の確定処理を非同期で行います。
  • 確定済み
    • 決済が確定された状態です。
  • 決済承認の取消済み
    • モンストゲームサーバーでのアイテム付与が失敗し、オーソリが取り消された状態です。
    • 制限のある商品を重複購入した際にこのステータスに遷移します。
  • 決済確定の返金済み
    • ユーザーからの問い合わせなどにより返金処理が完了した状態です。

購入可否判定について

Webショップはアプリ内とほぼ同様の商品を扱っています。
商品の種類によっては購入回数を制限しており、アプリとWebショップでの重複購入を防ぐ仕組みが必要です。Webショップではモンストゲームサーバーからユーザ毎に購入可能な商品のリストを問い合わせを行います。これを元に商品表示の調整や購入バリデーションを行っています。

購入処理における「滞留」とその対策

購入処理中には、様々な要因により処理が中断してしまう「滞留」が発生する可能性があります。Webショップではリリース当初想定以上の滞留が発生する問題がありました。これらの原因と対策を紹介します。

滞留とは

滞留とは購入処理において、ネットワークの問題や予期せぬエラーなどにより、購入処理が完了しないまま中断してしまう状態を指します。 具体的には「決済承認済み」 状態から 「確定済み」や「決済承認の取消済み」などの最終ステータスへの移行が完了しないケースが主な問題となります。

滞留が発生した場合、

  • ユーザにアイテムが付与できずユーザー不利益に繋がる
  • 売上の確定ができず損失になる

などの不具合が発生します。

滞留が発生する原因

滞留は、以下のような様々な要因によって発生し得ます。

  • ネットワークの不安定さ: ユーザー側の通信環境やサーバー間のネットワーク遅延、パケットロスなど。
  • システム負荷: 大型イベント時など、アクセス集中によるシステム全体の負荷上昇。
  • ハンドリング漏れ: 予期せぬエラー発生時の適切なエラーハンドリングの不備。

Webショップ購入フローではアイテム付与をモンストゲームサーバー、決済処理をMIXI Paymentを通じて購入が完了します。システムを分離しているこのようなケースでは滞留は発生しうる問題です。

滞留検知の仕組み

Webショップでは発生した滞留を早期に検知し、対応するための仕組みを導入しています。

  • 滞留検知用のモデル
    • 「決済承認済み」状態となったトランザクションを専用のモデルに記録します。 一定期間以上このモデルが存在する場合、そのトランザクションは滞留していると判断します。
  • 滞留通知
    • 滞留を検知した際には、運用チームにSlack通知が行われます。
    • 通知システムなどの不具合により滞留が検知できない場合に備え、定期的に滞留している可能性のあるトランザクションを特定するバッチ処理が実行されます。

滞留への対策

モンストWebショップでは、決済処理とアイテム付与処理は冪等性を持つように設計しており、滞留した場合でも再試行によってほとんどの問題が解決できることを前提としています。

  • 再試行処理
    • アイテム付与APIの呼び出しが失敗した場合や、モンストゲームサーバーが処理中の状態を返した場合、一定回数まで再試行が行われます。
    • 再試行の間隔は、試行回数に応じて指数関数的に増加するように設計しています。
    • 即時応答と処理の安定性を高めるために、試行処理は専用のプロセスで行います。このようなプロセスを簡単に立ち上げられることがElixirの強みでもあります。
  • 状態照会API
    • リリース後、モンストゲームサーバーに特定の購入におけるアイテム付与状態を照会できるAPIが用意されました。
    • 再試行時には、必ずこのAPIで最新の付与状態を確認してから処理を進ます。
  • ロック処理
    • アイテム付与処理の競合を防ぐために、付与処理をロックする仕組みを導入しています。
    • 購入モデルには付与処理ロック用のフラグがあります。それに対してDynamoDBの条件式を用いて更新をかけることでロックを実現しています。

これらの対策の結果、現在ではWebショップにおける滞留は大幅に減少しました。システムに高負荷がかかった場合を除き、現在はほぼ発生しておりません。 滞留が発生した場合も一括再試行処理によって大部分が自動的に解消されるようになっています。

まとめ

モンストWebショップでは、ユーザーがスムーズにアイテムを購入できるよう、堅牢な購入管理と、滞留発生を抑制・解消するための多角的な対策が講じられています。

ECサイトやアプリ外課金機能の開発を行うサービスにとって、モンストWebショップの事例が少しでも参考になりましたら幸いです。

MIXI DEVELOPERS Tech Blog

Discussion