Skip to content

Commit d2715a7

Browse files
Merge pull request #376 from RailsEventStore/docs/event-serialization-through-mapper
Update docs to use new mapper API and correlation/causation features
2 parents e424b14 + e9b164f commit d2715a7

File tree

3 files changed

+92
-5
lines changed

3 files changed

+92
-5
lines changed

railseventstore.org/source/docs/correlation_causation.html.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,37 @@ new_event.metadata[:correlation_id]
5353
new_event.metadata[:causation_id]
5454
```
5555

56+
This is however not necessary for sync handlers. Events published from sync handlers are by default correlated with events that caused them.
57+
58+
## Correlating events published from async handlers
59+
60+
Events published from async handlers are not correlated with events that caused them by default. To enable that functionality you need to prepend `RailsEventStore::CorrelatedHandler`
61+
62+
```ruby
63+
class SendOrderEmail < ActiveJob::Base
64+
prepend RailsEventStore::CorrelatedHandler
65+
prepend RailsEventStore::AsyncHandler
66+
67+
def perform(event)
68+
event_store.publish(HappenedLater.new(data:{
69+
user_id: event.data.fetch(:user_id),
70+
}))
71+
end
72+
73+
private
74+
75+
def event_store
76+
Rails.configuration.event_store
77+
end
78+
end
79+
```
80+
5681
## Correlating an event with a command
5782

5883
If your command responds to `correlation_id` (can even always be `nil`) and `message_id` you can correlate your events also with commands.
5984

6085
```ruby
61-
class ApproveOrder = < Struct.new(:order_id, :message_id, :correlation_id)
86+
class ApproveOrder < Struct.new(:order_id, :message_id, :correlation_id)
6287
end
6388

6489
command = ApproveOrder.new("KTXBN123", SecureRandom.uuid, nil)
@@ -126,6 +151,39 @@ class AddProductCommand < Struct.new(:message_id, :product_id)
126151
end
127152
```
128153

154+
## Building streams based on correlation id and causation id
155+
156+
You can use `RailsEventStore::LinkByCorrelationId` (`RubyEventStore::LinkByCorrelationId`) and `RailsEventStore::LinkByCausationId` (`RubyEventStore::LinkByCausationId`) to build streams of all events with certain correlation or causation id. This makes debugging and making sense of a large process easier to see.
157+
158+
```ruby
159+
Rails.application.configure do
160+
config.to_prepare do
161+
Rails.configuration.event_store = event_store = RailsEventStore::Client.new
162+
event_store.subscribe_to_all_events(RailsEventStore::LinkByCorrelationId.new)
163+
event_store.subscribe_to_all_events(RailsEventStore::LinkByCausationId.new)
164+
end
165+
end
166+
```
167+
168+
After publishing an event:
169+
170+
```ruby
171+
event = OrderPlaced.new
172+
event_store.publish(event)
173+
```
174+
175+
you can read events caused by it:
176+
177+
```ruby
178+
event_store.read.stream("$by_causation_id_#{event.event_id}")
179+
```
180+
181+
and events correlated with it:
182+
183+
```ruby
184+
event_store.read.stream("$by_correlation_id_#{event.correlation_id || event.event_id}")
185+
```
186+
129187
## Thanks
130188

131189
Image thanks to [Arkency blog](https://blog.arkency.com/correlation-id-and-causation-id-in-evented-systems/)

railseventstore.org/source/docs/protobuf.html.md.erb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,16 @@ event_store.subscribe(->(ev){ }, to: [MyApp::OrderPlaced.descriptor.name])
108108
class SendOrderEmailHandler < ActiveJob::Base
109109
self.queue_adapter = :inline
110110

111-
def perform(event)
112-
event = YAML.load(event)
111+
def perform(payload)
112+
event = event_store.deserialize(payload)
113113
# do something
114114
end
115+
116+
private
117+
118+
def event_store
119+
Rails.configuration.event_store
120+
end
115121
end
116122

117123
event_store.subscribe(SendOrderEmailHandler, to: [MyApp::OrderPlaced.descriptor.name])

railseventstore.org/source/docs/subscribe.html.md.erb

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,30 @@ Async handlers are just background jobs implemented with `ActiveJob`.
305305

306306
```ruby
307307
class SendOrderEmail < ActiveJob::Base
308+
def perform(payload)
309+
event = event_store.deserialize(payload)
310+
email = event.data.fetch(:customer_email)
311+
OrderMailer.notify_customer(email).deliver_now!
312+
end
313+
314+
private
315+
316+
def event_store
317+
Rails.configuration.event_store
318+
end
319+
end
320+
321+
event_store = RailsEventStore::Client.new
322+
event_store.subscribe(SendOrderEmail, to: [OrderPlaced])
323+
```
324+
325+
You can also use `RailsEventStore::AsyncHandler` module that will deserialize the event for you:
326+
327+
```ruby
328+
class SendOrderEmail < ActiveJob::Base
329+
prepend RailsEventStore::AsyncHandler
330+
308331
def perform(event)
309-
event = YAML.load(event)
310332
email = event.data.fetch(:customer_email)
311333
OrderMailer.notify_customer(email).deliver_now!
312334
end
@@ -349,8 +371,9 @@ You can configure your dispatcher slightly different, to schedule async handlers
349371

350372
```ruby
351373
class SendOrderEmail < ActiveJob::Base
374+
prepend RailsEventStore::AsyncHandler
375+
352376
def perform(event)
353-
event = YAML.load(event)
354377
email = event.data.fetch(:customer_email)
355378
OrderMailer.notify_customer(email).deliver_now!
356379
end

0 commit comments

Comments
 (0)