Reputation: 4698
I am trying to build a persistent relational projection of an event stream in a event-sourced/CQRS and DDD-inspired Rails 5.2.x application using RailsEventStore.
To have my projector receive notification on new events I'm using Client#subscribe
which works nicely. I set my projector subscription up in a Rails initializer file.
Now when I run tests, most of the tests don't require there to be a projection of the event stream. Therefore I would like to have the subscription only in highly integrated tests.
Because my initializer seems to run only once, before any individual tests are executed, I need to subscribe/unsubscribe the projector in tests initialization. Sadly I did not find any trace of an Client#unsubscribe
method.
Is there a way to unsubscribe from an event stream after I already subscribed to it? Or is there overall a better way to handle this situation in RailsEventStore?
Upvotes: 0
Views: 233
Reputation: 281
There's no Client#unsubscribe
method. Instead each subscription returns a lambda that you call to revoke subscription:
irb(main):001:0> event_store
=> #<RailsEventStore::Client:0x83ea4880>
irb(main):002:0> my_handler = ->(event) { }
=> #<Proc:0x000000010d6f1720@(irb):2 (lambda)>
irb(main):003:0> revoke = event_store.subscribe(my_handler, to: [Ordering::OrderSubmitted])
=> #<Proc:0x000000010d6d3568@/Users/pawelpacana/.rubies/ruby-2.5.5/lib/ruby/gems/2.5.0/gems/ruby_event_store-0.40.1/lib/ruby_event_store/subscriptions.rb:53 (lambda)>
irb(main):004:0> revoke.call
=> [Ordering::OrderSubmitted]
Or is there overall a better way to handle this situation in RailsEventStore?
My colleague Rafał described in https://blog.arkency.com/optimizing-test-suites-when-using-rails-event-store/ how particular subscribers can be enabled or disabled depending on a test case. In short the idea is to have new event_store
instance for each test and filter list of subscribers based on test metadata.
With new event_store
instance per test (without subscribers to begin with) you no longer have to unsubscribe. You could then for example explicitly subscribe in an integration test case:
def integrate_with_read_model
event_store.subscribe(::MenuOffer.method(:handle_menu_offer_chosen), to: [MenuOfferAccepted])
event_store.subscribe(::MenuOffer.method(:handle_menu_offer_rejected), to: to: [MenuOfferDeclined])
event_store.subscribe(::MenuOffer.method(:handle_menu_offer_is_pending), to: [MenuOfferIsPending])
event_store.subscribe(::MenuOffer.method(:handle_menu_offer_set), to: [MenuOfferSet])
end
before(:each) { integrate_with_read_model }
Upvotes: 1