安定して通話がつながっている間だけ、秒単位で課金する
enqor の中核となる機能は、ビデオ・音声通話です。ストリーミングは Agora を使ったので難しくありませんでしたが、課金のパイプラインは自分で作らなければならない課題でした。モバイルは通信状態が悪くなることが多いため、正常につながっていた時間の分だけ課金する必要があり、さらに秒単位の課金まで求められました。
まず、「安定した通話」とは何かを決めなければなりません。これは、サーバーとクライアントがやり取りする ping で定義しました。どちらか一方の参加者でも ping が3回届かなければ接続に問題があると判断し、課金を止めます。7回届かなければ通話が切れたと判断し、セッションを終了するようにしました。
次の問題は、毎秒課金という要件です。最初は、通話時間全体から不安定だった時間を引き、通話が終わった後にデータベースを一度だけ更新するつもりでした。ところが、要件が思った以上に複雑でした。通話中にアプリ内通貨のクラップをチャージできる必要があり、チャージしたクラップで互いにプレゼントもでき、通話可能な時間が20秒未満になれば、もうすぐ通話が終わることも知らせなければなりません。チャージ、消費、照会がすべてリアルタイムで行われる必要があるため、残りのクラップを読み書きの軽いどこかに保存して処理するのが簡単だと判断しました。
通話が始まると、発信者のクラップ残高を変更できないようにします。現在の残高を読んで Redis の通話セッションに複製しておくと、この値が通話中に発信者が使える残高の基準になります。毎秒この値を減らして課金し、チャージやプレゼントがあればこの値を更新し続けます。チャージは決済の記録を残す必要があるので、DB にも別途残します。残りの通話時間も、この値をもとに計算してクライアントに返します。通話が終わったら、残高を DB に書き戻します。チャージとプレゼントを除けば、通話1件あたりの DB 操作は開始と終了の2回だけなので、複雑なロジックを直感的に実装できるようになりました。