How to add orthogonal behavior to state machines: publishing events
In this guide, we'll see how we can hook into the business flow transitions orchestrated by a state machine to add behavior that fits into another area domain.
As noted in the event bus guide, you can leverage the event bus to hook into core events. That's helpful when you need to perform something in response to a change in the system, but your logic is orthogonal (i.e., decoupled) to the main flow. Transitions between state machine states are good candidates to become hotspots where tangential logic is triggered.
Don't be confused about state machine events vs. bus events. State machine events are conditions that can produce a transition between valid states. They're local to the state machine component. On the other hand, bus events can be published and consumed anywhere within the system and, per se, have nothing to do with the state machines.
For instance, you might want to update your ERP or send an SMS when a payment is marked as completed. The cleaner way to do that is to publish an event when that happens and then subscribe to it.
First, you need to override the
#complete state machine event on
Spree::Payment (see the overrides section for the required
# frozen_string_literal: true
super.tap do |result|
Spree::Bus.publish(:payment_completed, payment: self) if result
The following is an example of a subscriber to the new event:
payment = event.payload[:payment]
Don't forget to register the new event and subscribe to it:
Done. Once the server is restarted, the
:payment_completed event will be
published every time a payment is completed. That will let its subscriber know
it's time to do their job.
Ideally, Solidus would publish events for every state machine transition out of the box. Our event
bus is fairly new and we're still working on it, but we'll get there eventually! In the meantime,
you can check
Spree::Bus.registered_events for the complete list of events that are already