CQRS – Calling External Services from Sagas/Process Manager

cqrsdomain-driven-design

In my domain where I am applying CQRS, there are some external service calls in order to some validation. I am a bit puzzled about where to put these calls. I am considering to put these calls to my Process manager on the other hand AFAIK the process manager should be a simple state machine that reacts on events and dispatch commands to other aggregates. I can think of two solutions:

1-) One solution is to make these calls and depending on the service call, transition to another state by self publishing an event. Though I don't like the idea Process manager publishes events.

2-) I can wrap my service calls behind another interface and that service call itself can raise the event. Though I don't like this idea since an event should be persisted before publishing.

How should I tackle this problem?

Best Answer

Short answer: call the external services from the Saga but invert the dependency by using an Interface

Unlike Aggregates, which must be pure (no dependency to anything that touches the infrastructure, nor abstract neither concrete), Sagas are domain models that may call external services. But because they are also from the Domain layer, they may not depend on the Infrastructure. You manage to do that inverting the dependency, by defining an Interface in the Domain layer with an implementation in the Infrastructure. In this way, the Domain owns the interface and not the Infrastructure.

In other words, you must use an Anti-corruption layer when communicating with external models, and that is that Interface for.

Btw, in this way you increase the Saga's testability, for free.

1-) One solution is to make these calls and depending on the service call, transition to another state by self publishing an event. Though I don't like the idea Process manager publishes events.

Me neither, only Aggregates should generate domain events.

2-) I can wrap my service calls behind another interface and that service call itself can raise the event. Though I don't like this idea since an event should be persisted before publishing.

This feels weird.