5

I'm building a service using the familiar event sourcing pattern:

  1. A request is received.
  2. The aggregate's history is loaded.
  3. The aggregate is rebuilt (from its history).
  4. New events are prepared and the aggregate is updated in response to the incoming request from Step 1.
  5. These events are written to the log, and are made available (published) to any subscribers.

In my case, Step 5 is accomplished in two parts. The events are written to the event log. A background process reads from the event log and publishes all events starting from an offset.

In some cases, I need to publish side effects in addition to events related to the aggregate. As far as the system is concerned, these are events too because they are consumed by and affect the state of other services. However, they don't affect the history of the aggregate in this service and are not needed to rebuild it.

How should I handle these in the code?

Option 1- Don't write side-effecting events to the event log. Publish these in the main process prior to Step 5.

Option 2- Write everything to the event log and ignore side-effecting events when the history is loaded. (These aren't part of the history!)

Option 3- Write side-effecting events to a dummy aggregate so they are published, but never loaded.

Option 4- ?

In the first option, there may be trouble if there is a concurrency violation. If the write fails in Step 5, the side effect cannot be easily rolled back. The second option write events that are not part of the aggregate's history. When loading in Step 2, these side-effecting events would have to be ignored. The 3rd option feels like a hack.

Which of these seems right to you?

Charles R
  • 17,989
  • 6
  • 20
  • 18
  • You would normally go for option 2. Let's say you have your event sourced application for example banking and second application statistics, which build statistics from event occured in the first app. Let's say statistic app subscribe to your "side effecting event". Everything will work without saving that event, till your business say: "We want to sell them as separate systems". Now your some client after two years of using banking app would buy statistic app, if you don't save your "side effecting events" before to ES, you will miss some concept or even fail with synchronization. – Dariss Jan 05 '16 at 12:41
  • @CharlesR can you give concrete examples of such "side effects" ? I'm not sure why something that doesn't affect the state of any aggregate should be treated as a domain event in the first place... – guillaume31 Jan 05 '16 at 12:49
  • 1
    @guillaume31The aggregate is "partner amount owed". This is money that was sent out that we need to claw back. Rather than bill the customer directly, we take this out of future money we would send them. Before we distribute funds, we check to see if the partner owes money, and take back what they owe. Then we publish domain events to update the partner's cash balance and distribute any funds. From the POV of this service, these are requests or side effects. We need to publish them, but they don't affect the aggregate's state (partner amount owed). – Charles R Jan 05 '16 at 16:00
  • I'm not sure about the order of events here. If I get you well, you're saying `PartnerAmountOwed.Reduced` should trigger `PartnerCashBalance.Update()` and `Funds.Distribute()`. I would do it the other way around. – guillaume31 Jan 06 '16 at 10:00
  • Besides *"We need to publish them"*, sure, but the `PartnerAmountOwed` aggregate shouldn't publish them. It should **remain unaware of side effects that ripple through other aggregates** and stick to its own internal ubiquitous language and events. – guillaume31 Jan 06 '16 at 10:03

3 Answers3

5

Name events correctly

Events are "things that happened". So if you are able to name the events that only trigger side effects in a "X happened" fashion, they become a natural part of the event history.

In my experience, this is always possible, because side-effects don't happen out of thin air. Sometimes the name becomes a bit artificial, but it is still better to name events that way than to call them e.g. "send email to that client event".

In terms of your list of alternatives, this would be option 2.

Example

Instead of calling an event "send status email to customer event", call it "status email triggered event". Of course, if there is a better name for the actual trigger, use that one :-)

theDmi
  • 17,546
  • 6
  • 71
  • 138
1

Option 4 - Have some other service subscribe to the events and produce the side effects, and any additional events related to them.

Events should be fine-grained.

KarlM
  • 1,614
  • 18
  • 28
0

Option 1- Don't write side-effecting events to the event log. Publish these in the main process prior to Step 5.

What if you later need this part of the history by building a new bounded context?

Option 2- Write everything to the event log and ignore side-effecting events when the history is loaded. (These aren't part of the history!)

How to ignore the effect of something which does not have any effect? :D

Option 3- Write side-effecting events to a dummy aggregate so they are published, but never loaded.

Why do you need consistency boundary around something which you will never change?

What you are talking about is the most common form of domain events, which you use to communicate with other BC-s. Ofc. you need to save them.

inf3rno
  • 24,976
  • 11
  • 115
  • 197