Goで実装した
UPSIDERの決済金額リミット機能
株式会社 UPSIDER
Miki Masumoto
1
Gopherは「Go」のマスコットキャラクター、原作者は Renee French さんです。以降のページも同様。
自己紹介
● Masumoto Miki
● 2022/1からUPSIDERにJOIN
○ Sler→フリーランス→UPSIDER
● Gopher歴は1年ほど
○ JavaとJavaScript/TypeScriptをよく書いてました
● 常にワーケーション中
2
UPSIDERについて
● 成長企業向けの法人カード、支払いプラットフォームを提供
● ビジネスの「お金」を呼吸感覚まで自在に
3
Today’s
goal
決済というクリティカルかつリアルタイム性が
求められるシステムで
Goをどう活用しているのかを知ってもらうこと
4
目次
● 決済システムの概要
● 決済金額リミットを扱う機能の紹介
● 実装のポイントとGoのコードサンプル
● Goで書いてよかったところ
5
カード決済の流れ
6
カード決済
システム
加盟店
オーソリ(承認要求)
クリアリング(売上確定)
◯◯円で決済します
OK/NG
◯◯円請求します
カード利用者
決済金額のリミット機能とは?
決済が飛んできた時にチェックされる金額上限
1.企業ごとの決済金額リミット
2.ユーザーごと1取引の決済金額リミット
3.ユーザーごとの月間決済金額リミット
毎月1日0時にリセット
4.ユーザーごとの日次決済金額リミット
毎日0時にリセット
ユーザごとのリミットはユーザが任意で設定可能
7
決済金額リミット関連の処理たち
● 決済金額のリミットを設定/解除する
○ WEB画面からの操作によって呼ばれる
● DBからのトータル決済額の読み込み・書き込み
○ オーソリ・クリアリングなどが飛んできた時に呼ばれる
● トータル金額のリセット
○ システム内部のバッチで呼ばれる
8
決済金額リミット関連のデータを扱うstruct
9
実装のポイント① 柔軟な金額リミット機能
10
実装のポイント① 柔軟な金額リミット機能
11
今後、もっと柔軟なリミット機能が欲しくなるかも
● 週ごと/期ごとにリミットを持たせたい... etc
● 毎月20日/15日など間隔は同じで特定日や時間にリセットしたい
実装のポイント① 柔軟な金額リミット機能
12
💡新しいリミットのタイプを実装したい
👉次回のリセットのタイミングを計算するロジックだけ作れば実装できる
実装のポイント① 柔軟な金額リミット機能
13
👉次回リセット日時(NextResetAt)を変えることで実現できる
💡既存のリミット間隔で特定の日付・時間にリセットしたい
● 20日にリセットされる月間リミット
7/1 8/1 9/1
リミットの設定をする
NextResetAt = 7/20
リセット処理が走る
NextResetAt = 8/20
LastResetAt = 7/20
7/17 7/20 8/20
実装のポイント② 安全なトータル金額のリセット
14
実装のポイント② 安全なトータル金額のリセット
15
トータル金額リセット時の懸念
● リセット時刻にリセットする処理が遅延/失敗したら?
● オーソリなどのリアルタイムで飛んでくる決済が同時に飛んできたら?
実装のポイント② 安全なトータル金額のリセット
16
💥ケース1:リセット処理がまだなのにオーソリが飛んできてしまった
単純な、トータル金額を0円にするリセット処理ではなぜダメなのか
00:00:00 00:00:01
23:59:59
トータル金額
0時にリセットされる1日あたりの決済金額リミットの例
10000円 13000円 0円
オーソリ
3000円
リセット処理の実行
本当の
トータル金額 10000円 3000円 3000円
合わない
実装のポイント② 安全なトータル金額のリセット
17
💥ケース2:日付が変わる直前にオーソリが飛んできて処理中にリセットが走った
単純な、トータル金額を0円にするリセット処理ではなぜダメなのか
00:00:00 00:00:01
23:59:59
トータル金額
0時にリセットされる1日あたりの決済金額リミットの例
10000円 0円 4000円
オーソリ 4000円(処理に時間がかかった)
リセット処理の実行
本当の
トータル金額 10000円 0円 0円
合わない
実装のポイント② 安全なトータル金額のリセット
18
リセット前後のトータル金額も保持し、取得時刻から使われるべきトータル金額を判断する
実装のポイント② 安全なトータル金額のリセット
19
トータル金額リセット処理は0にするのではなく、次の断面にスライドさせる
Goのよかったところ①
20
● 言語仕様がシンプルで既存コードのキャッチアップしやすい
処理の流れと分岐が追いやすい
Goのよかったところ②
21
● 抽象化の機能が限られているので、個別ケースの扱いに困ったり
過度な抽象化による難読コードを書くリスクを避けられる
抽象化していないことで
コードを追いやすい
似た振る舞いのstruct
Goのよかったところ③
22
● エラーハンドルが必ず入るのでバグに気付きやすい
いろんなところにif err
If errを書きながら不具合に気づく
Try catchのネストもない
Goのよかったところ④
23
● ほぼ標準ライブラリで開発が可能(特にテストで嬉しい)
テストカバレッジも自動で出してくれる🎉
標準ライブラリで
テーブル駆動テストが簡単に書ける
まとめ
24
📍 決済というクリティカルかつリアルタイム性が求められるシステムで
Goをどう活用しているのか?
💪 考えることが多い要件や仕様でもGoのシンプルな言語仕様を生かし
レビューしやすく見通しの良いコードを書くことによって
堅牢なシステム作りをしています
Thank you for
listening.
25
We are hiring!
@masumomo
@m_miki0108

Goで実装した UPSIDERの決済金額リミット機能

Editor's Notes

  • #30 さて、先ほどの図で出てきたカード決済システムがUPSIDERではどんな構成になっているかみてみます。 弊社はマイクロサービスを採用していて、複数のサービスによって構成されています。 先ほどの話でてできた、オーソリとかクリアリングと呼ばれる電文は私たちの場合はVisaNetと呼ばれるVisaのネットワークから飛んできます。 そこからUPSIDERのゲートウェイやルータなどを介して、オーソリ、クリアリングなどの電文ごとのハンドラーに渡されます。 そこからさらに各ドメインを担当しているReaderやWriterと呼ばれるマイクロサービスたちを呼び出すといった流れです。 今回のメインテーマである決済金額のリミットの機能も、ユーザの利用金額を管理するサービスとして独立しています。 ではその決済金額のリミット機能の紹介に入っていきます。が、