Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Restate x Stripe: 安心して眠れる決済システムを目指して

Avatar for acomagu acomagu
November 07, 2025
0

Restate x Stripe: 安心して眠れる決済システムを目指して

Avatar for acomagu

acomagu

November 07, 2025
Tweet

Transcript

  1. Stripe を使っていると Event Sourcing に惹かれる なぜか?
 - Stripe Webhook がそのままイベントとして使えるから


    - 決済システムは不整合が許されないから
 - Event Sourcing を使うことで、「真となるデータ」を1箇所(Event Store)に集約することができ、各 サービスはそこから状態を計算することに集中すればよくなる 

  2. なぜ Event Sourcing は世界を席巻していないのか A: 大変すぎるから 
 Event Sourcing を導入するには:


    - 全ての副作用を冪等(リプレイ可能)にする必要がある(External Updates 問題)
 - 全ての外部からの情報取得の結果を記録しておく必要がある(External Queries 問 題)
 - ドメインロジックの時間的な変更履歴を全てドメインロジックに組み込む必要がある (Code Changes 問題)
 e.g. 11月まではメール通知をしていなかったが、12月からはメール通知をすることになった 
 - Event Sourcing を導入すると、ユーザーからのリクエストに対して「同期的に処理を 実行し、その結果を即座にレスポンスする」ということが簡単ではなくなる

  3. ↑Stripe からのイベントだけ考えれば上記のような形でうまく行きそうだが... 
 - 例えばメール送信はどうやって冪等関数にするのか? 
 - 例えば金額を外部 CMS から取得しているとしたら、「その時点での金額」をどうやって記録しておくの

    か?
 (大体 External Gateway パターンを使って副作用の入力と出力を記録することになるが、通信するシステムが 多い場合これがかなり大変になってくる上に、Gateway 自体のバグ修正が難しい) 

  4. Restate 誕生物語 - Stephan は、Flink の顧客とコミュニケーションを取る中で「Flink は分析用途には合 うが、よりトランザクショナルな用途のアプリケーションには合わない」と感じていた
 - しかし、依然としてトランザクショナル界隈の書き心地はひどい

    
 - なので「ストリーム処理の魔法のような回復力とスケーラビリティ」と「RPC のシンプ ルさと柔軟さ」の2つの世界の橋渡しをするフレームワークを作ることに決めた
 - つまり、Restate は RPC のように書けるのに、 Event Sourcing のようにイベントドリ ブンに実行されるフレームワーク

  5. Restate の機能 メインは二つのみ
 副作用の冪等化 
 
 
 
 
 Durable

    Step
 トランザクション分離 
 
 
 
 
 Virtual Object
 Workflow

  6. Restate の機能 メインは二つのみ
 副作用の冪等化 
 
 
 
 
 Durable

    Step
 トランザクション分離 
 
 
 
 
 Virtual Object
 Workflow

  7. 副作用の冪等化 Durable Step:
 
 
 
 ctx.run で囲むことで、結果が保存されるようになる
 → 何度実行しても同じ結果が得られる


    → 何度実行しても関数内は1度しか実行されない
 ただし、失敗(throw)した場合は、結果は保存されない

  8. 副作用の冪等化 Durable Step:
 
 
 
 ctx.run で囲むことで、結果が保存されるようになる
 → 何度実行しても同じ結果が得られる


    → 何度実行しても関数内は1度しか実行されない
 ただし、失敗(throw)した場合は、結果は保存されない
 → 失敗した ctx.run は、次回再実行される

  9. Restate の機能 副作用の冪等化 
 
 
 
 
 Durable Step


    トランザクション分離 
 
 
 
 
 Virtual Object
 Workflow

  10. トランザクション分離 Service は3種類あるが、そのうち Virtual Object と Workflow がトランザクション分離の 機能を持っている。
 


    Virtual Object / Workflow 共に
 「キー(string)で分離し、キーごとに直列に実行される」分離方法
 

  11. トランザクション分離 Service は3種類あるが、そのうち Virtual Object と Workflow がトランザクション分離の 機能を持っている。
 


    Virtual Object / Workflow 共に
 「キー(string)で分離し、キーごとに直列に実行される」分離方法
 
 Virtual Object と Workflow の違い:
 - Virtual Object: 全てのメソッドが何度でも呼び出せる
 - Workflow: run メソッドが必要で、このメソッドは1回だけ呼び出される
 Durable Promise(ctx.promise)が利用可能

  12. 結局 Saga やるなら Restate 要らなくない? A: Restate を使うことで Saga をシンプルに実装可能になる

    
 最も素朴な Saga の実装では、ACID のうち「原子性」しか担保できず、「永続性」や「分 離性」「整合性」を満たしません。(整合性については議論あり)
 
 しかし、前スライドのコードのように Restate 上で Saga をするだけで、「永続性」「分離 性」を満たすことができます。
 
 永続性: ハンドラや Restate Server が落ちても、自動で中断した Action から再開されま す
 分離性: Virtual Object や Workflow を使うことで実現できます

  13. ctx.run はガチで絶対1回しか実行されないの? (リトライ除く) A: 嘘です 
 Restate のドキュメントでは「かなり稀なケースなので通常は起こらないと想定可能だ が、理論的には ctx.run

    内部の関数が成功したのに2度目が実行される場合がある」と の記述があります。
 つまり、ctx.run() の結果を Restate Server に送る瞬間にクラッシュやネットワーク断が 起こった場合です。

  14. ctx.run の2度実行に備える方法 3つあると考えています:
 1. 関数内を冪等にする
 a. ctx.run 内で外部サーバーに送る際に Idempotency Key

    を使う等で複数回実行されても安全にしま す
 2. 2つの ctx.run を使って 2PCにする
 a. 1つ目の ctx.run で Prepare し、2つ目でコミットすることで、2つ目だけが複数回実行されることが あっても1度のコミットになります 
 b. RDBMS だとラッパー関数を使って簡単に実装できます 
 3. read / write を別の ctx.run にして、Virtual Object を使って Isolation する
 a. これは「関数内を冪等にする」に近いですが、 
 SET credits = credits + 100 
 のようにするより、read / write を別の ctx.run にすることで、2つ目だけリトライされても同じ値で上 書きされるようになります。 
 また Isolation によって、その Virtual Object からのみ credits を触っている限り、不整合は起こりま せん

  15. まとめ ① Restate は「シンプルな RPC の書き心地で」「イベントドリブンなアーキテクチャの安 全性を達成できる」フレームワークです。
 
 ② Restate

    は ctx.run によって「副作用の冪等化」を、Virtual Object と Workflow で「トラ ンザクション分離」を提供します
 
 ③ Restate で ctx.run を使うだけで自動で Saga や 2PC になるわけではなく、デフォルト ではリトライのみ面倒を見ます。しかし、Restate 上で Saga や 2PC を実装すると、簡単 に更に堅牢なコードを実現できます。