Statesman: A modern, robust Ruby state machine — GoCardless Blog
- 要件を満たす既存のステートマシン実装が無かった
- 他のRubyオブジェクトと容易に組み合わせられる
- ステートマシンを独立したクラスとして実装し、それらをRailsモデルに選択的に組み込みたい
- データベースレベルでのデータ完全性
- 復数のアプリケーションサーバーを稼働しているので、レースコンディションに関わる状態変化を防ぐためデータベースでの一貫性を利用したい
- 状態遷移を追うことができる完全な履歴
- 各遷移における非構造化メタデータとともに遷移をデータベースに永続化したい
- 他のRubyオブジェクトと容易に組み合わせられる
- Statesmanはrobust audit trailとデータ完全性のために設計された
- 特徴
- ステートマシンロジックをモデルから分離させており、1つ以上の他のモデルとのコンポジションが容易
- 完全な履歴をデータベースに永続化する
- 遷移の重複をデータベースレベルで防ぐ
- 遷移におけるメタデータとしてJSONを保存できる
- 分離されたステートマシンロジック
- ステートマシンクラスの実装
Statesman::Machine
をインクルードするstate
で状態を定義するtransition
で遷移ルールを定義する
- モデルクラスとして、対象モデルクラスとそれに対応するトランジションクラスを用意する
Payment
とPaymentTransition
など(いずれもActiveRecord::Base
のサブクラス)
- 新しいステートマシンインスタンスはモデルクラスとトランジションクラスを渡して生成する
PaymentStateMachine.new(payment, transition_class: PaymentTransition)
- ステートマシンインスタンスが生成されると新しいトランジションインスタンスが保存される
- ステートマシンに対する
current_state
メソッドはデータベースクエリを利用して結果を返す - ステートは親となる
Payment
モデルには一切保存されない
- インメモリアダプタが標準で用意されている