eugene-khyst / postgresql-event-sourcing

A reference implementation of an event-sourced system that uses PostgreSQL as an event store built with Spring Boot. Fork the repository and use it as a template for your projects. Or clone the repository and run end-to-end tests to see how everything works together.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to handle incomming integration events?

alibabashack opened this issue · comments

Thank you very much @eugene-khyst ! Especially the paragraph about Domain events vs Integration events was an eye-opener.

I am currently wondering how replaying of events works and how the system state can be reliably recreated (conceptually). A reason to do that might be an added or modified projection (e.g. to add another column in a table providing extra information which can be extrapolated from existing events).

This seems to be strait forward when only internal domain events contribute to the aggregate's state. We simply drop the table(s) belonging to the projection, then pipe all historic events through the new/changed event handler of the projection and finally continue to feed new events synchronously.

But, can't we also have aggregates that perform state changes due to incoming integration events? (I am unsure if this is conceptually correct.)

How would we deal with incoming integration events in this case? In order to be able to replay events later, it seems to me, that the incoming events need to be enqueued into the event store along with the internal domain events, because only then we are able to preserve their exact order of processing relative to the internal events.

So in this case we had some process receiving incoming integration events. First, it sticks them into the event store (while dropping repeatedly delivered events). Then it hands them over to synchronous event processing (but not asynchronous forwarding). Finally, it acknowledges the reception to the event broker.

Does this sound valid or is there a better pattern? I am thankful for every comment.

Hi @alibabashack
Before trying to answer your question, I want to make sure I fully understand it. Could you please provide an abstract example of the domain you describing? I can extend the repo to have a section dedicated to this example.

Okay, it might feel a bit staged, but let's amend your example with an additional service called Driver Work Time Tracking. Among other things, this service is also used by drivers to call in sick. The service has a command callInSickForToday(driverId).

And there is a new business rule:

Given a driver has accepted an order and given the order is not completed yet, when this driver is reported absent, then the order is canceled.

Let's assume we want to implement this using the event choreography approach. Hence, there is no direct command from the Driver Work Time Tracking, but instead DriverAbsent(driverId) integration events are emitted towards the Order service using some kind of message broker.

My questions are:

  1. What happens in the Order service when a DriverAbsent event is received in order to potentially cancel orders (and how do we receive it).
  2. How is event replay working at a later stage and which events will be replayed to restore the state?

Meanwhile, I understood that an aggregate is not allowed to change state by accepting events directly (neither internal domain events, nor integration events). An aggregate only acts upon commands. Events being emitted is the result of a command, only.
Hence, the incoming integration event DriverAbsent is not stored in the event store. It is rather transformed by Something* into a command towards the Order aggregate. In case this command execution results in a state change, only then an OrderCanceledEvent will be emitted. And this is sufficient to restore the state in case of a replay. Correct?

  • What is this Something called? If it is a complex thing it seems to be called Saga, but what do we call this simple thing that can't fail, here?