Event Sourcing + CQRS: Update Read Model and perform external integration on event


I’m exploring Event Sourcing and the CQRS patterns and doubt where to put external integrations that are not strictly part of the Command/Query model

Image a scenario where you have:

  • A Command X Microservice: Expose an API that, when triggered by the user, appends an event to the event store. Every time that an event is appended to the event store, a listener (catchup sub) is triggered. The listener executes a Rest API that updates the QUERY side.

  • A Query X Microservice: Expose an API, called by the listener in the Command Side each time an event is appended to the event store, that updates the Query model according to the event.

Let’s imagine that, in addition to the Query Model update, you also need to call another system (ex. another microservice, through a REST API call, or through a message broker) for other purposes. For example, imagine that your COMMAND/QUERY microservices are participating in a SAGA with other microservices.

  • Is it right to put the external integration on the Command Side (Command X Microservice)? (I’m confident that it is)
  • Assuming that the Command Side is the right choice, where to implement physically the integration logic?
    • In the same listener in charge of updating the Query Model?
    • In a dedicated listener?

My idea is that the right choice is to implement the external integration in a dedicated listener (catchup sub) of the Command side. This will grant the atomicity of each listener making it easier to handle the “retry logic”.

Is there something that I’m missing? Are any other considerations to take in mind?

Thank you

You indeed typically have a full logical decoupling between components in the system.
I.e components that would update read models, components that integrate with external systems.
That decomposition is a logical one that has to do with what’s it’s doing.
Event though the boilerplate code might look very similar.

how you host those components, in a single process with one subscription that fans out internally or multiple process is another choice.