I have two separate, isolated Domain-Driven Design contexts, and have a feature that needs to be implemented to integrate them together in some way.
Both of these are broken down in a Hexagonal/Ports and Adapters style. The feature is implemented using an Event Subscriber, with an event messaging mechanism for communication.
The feature is that an upstream Event, triggered from an Aggregate change, will trigger an Aggregate change in the downstream model.
The book Implementing Domain-Driven Design mentions a couple of things with regards to cross-context event publishing.
Forwarding the Event via a messaging infrastructure would allow asynchronous delivery to out-of-band subscribers. Each of those asynchronous subscribers could arrange to modify an additional Aggregate instance in one or more separate transactions. (Vernon, p. 302)
The use of any such messaging mechanism between Bounded Contexts requires that we adopt a commitment to eventual consistency. It can't be fought. (Vernon, p. 303)
Subscriber systems may not even be running when the publisher sends messages through the exchange. Each subscriber is responsible for handling messages in its own time frame, ensuring that it properly carries out any necessary domain behavior on its own model (Vernon, p. 317)
With regards to the Ports and Adapters architecture, the book mentions
There is not a strict definition of what a Port means, making it a flexible concept. In whatever way Ports are partitioned, client requests arrive, and the respective Adapter transforms their input. It then invokes an operation on the application or sends the application an event. Control is thus transferred to the inside.
Based on this, the Subscriber is responsible for retrieving the Event from the upstream Context, and somehow translating that into a command for the downstream Application Service. This makes it seem like the Subscriber should exist as an Infrastructure Adapter to the downstream Context, through the "upstream Context, messaging mechanism" port. After all, it's fetching an upstream Event, and doing something in the local/downstream context. Although, it is not doing so like a passive subscriber; this needs to actively seek out the client input (the upstream Events).
However, something needs to trigger this Subscriber to fetch the Events. After all, the Subscriber may not be running when the Event is published, for whatever reason, so it's the responsibility of the Subscriber to be, or stay, up-to-date. There's some amount of timing or scheduling that needs to happen in order for the retrieval to occur. This makes it seem more like an operational concern (frequency, timing), and should therefore be in the Application Layer, and not necessarily an Adapter. If this is really an Application Service, or a Synchronizer, then perhaps it should instead retrieve the upstream Events, translate them into appropriate downstream commands, and publish those Commands through a separate Command Adapter, which would interact with the downstream Application Service, instead of interacting with the Application Service directly.
With that all out of the way, is a component that
- is interested in Events from an upstream source,
- provides an integration not directly owned by either context,
- is not required by either context to operate correctly,
- causes an Aggregate to be modified in a separate downstream transaction,
- translates an upstream event into a downstream command,
- actively retrieves the events from the upstream context, based on a recurring trigger,
- does not passively receive the events it's interested in,
- may not be running or available when the upstream event occurs,
- may exist in a third, different context, than the upstream or downstream,
an Application Service, an Adapter, an Infrastructure Service, or something else entirely?
Reasons why it might be
- an Application Service
- it has some operational concerns (event polling, frequency, scheduling)
- an Adapter
- it's a new client which needs to feed input into the downstream context
- reacts to upstream events to trigger something in the downstream context
- receives its input through a specific port (messaging mechanism)
- an Infrastructure Service
- exists outside of the Application Layer and Domain Model
- calls existing Application Service methods
Reasons why it might not be
- an Application Service
- is not the direct client of the Domain Model
- relies on existing Application Service to function
- an Adapter
- actively retrieves events from upstream, instead of passively reacting to them being delivered
- an Infrastructure Service
- does not implement any interface in the Application Layer or Domain Model
These contradictions kind of signal to me that it's "something else" but what exactly it is, and where exactly it lives, I'm not sure.
For clarification, the question is about what this type of component is, based on its interactions with others. A comment said this could be a Client or Consumer. But these aren't terribly specific, and don't provide a lot of insight into its interactions with its surroundings. Any code that calls other code is a Client or Consumer. But the Direct Client of the Domain Model is the Application Service. This provides context to its interactions with its surroundings. The Domain Model can call some code on an implementation of an interface in the Domain Model. Here, the Domain Model is the Client of an Infrastructure Service. Some Event can come through a messaging mechanism, and call some method on the Application Service. Here, the Event Subscriber is an Adapter, that passively receives the Event from the Port, and becomes a Client for the Application Service.