Skip to content

Conversation

armiol
Copy link
Contributor

@armiol armiol commented Sep 8, 2017

This PR introduces IntegrationBus and ability to exchange messages between BoundedContexts.

Highlights:

  • IntegrationBus along with TransportFactory are introduced and represent a mechanism of inter-BoundedContext communication. Each BoundedContext may produce events and rejections in which other contexts are interested (the latter are downstream in this case). The messages of interest are brought to their subscribers/reactors via a customizable Transport, inspired by Publish-Subscribe messaging systems.

  • React(external = true) and Subscribe(external = true) now allow to process events and rejections that are fired by another bounded context. Handler methods marked external play an anticorruption layer role (see ACL pattern in "Domain-Driven Design" by Eric Evans and "Implementing Domain-Driven Design" by Vaughn Vernon) .

  • TransportFactory and MessageChannel concepts are introduced. There is also a naïve in-memory transport implementation for test purposes.

In addition, BoundedContextId is introduced to identify bounded contexts. It is an improvement to a String used for identification previously.

IntegrationBus

This bus is available as a part of single BoundedContext. In a multi-component environment messages may travel across components from one bounded context to another.

IntegrationBus is always based upon some transport (see more on that below), that delivers the messages from and to it. For several bounded contexts to communicate, their integration buses have to share the transport. Typically that would be a single messaging broker.

The messages from external components received by the IntegrationBus instance via the transport are propagated into the bounded context. They are dispatched to the subscribers and reactors marked with external = true on per-message-type basis.

IntegrationBus is also responsible for publishing the messages, born within the current BoundedContext, to external collaborators. To do that properly, the bus listens to a special document message called RequestForExternalMessages, that describes the needs of other parties.

E.g. bounded context Projects has the external event handler method in the projection as follows:

public class ProjectListView extends Projection<...> {

    @Subscribe(external = true)
    public void on(UserDeleted event) {
        // Remove the projects that belong to this user.
        // ...
    }

    // ...
}

Upon a registration of the corresponding repository the integration bus of Projects context sends out a RequestForExternalMessages saying that an Event of UserDeleted is needed from other parties.

Let's say the second bounded context is Users. Its integration bus will receive the RequestForExternalMessages request sent out by Projects. To handle it properly it will create a bridge between Users's event bus (which may eventually be transmitting UserDeleted event) and an external transport. Once UserDeleted is published locally in Users context, it will be received by this bridge (as well as other local dispatchers), and published to the external transport.

The integration bus of Projects context will receive the UserDeleted external message. The event will be dispatched to the external event handler of ProjectListView projection.

TransportFactory and MessageChannel

This PR introduces an initial implementation of Publish-Subscribe Channel pattern.

The TransportFactory allows to create channels for outgoing messages (Publishers) and incoming messages (Subscribers). Each channel serves messages of a single type.

In scope of this PR an in-memory implementation is provided, which is only suitable for the publishers and subscribers located within the same JVM. In the nearest future a Google Cloud-based implementation will be added to Spine.

The framework version is set to 0.9.65-SNAPSHOT.

To be delivered in the following PRs:

  • Google PubSub-based implementation of Transport along with proper integration tests.
  • RabbitMQ-based implementation of Transport along with proper integration tests.

Alex Tymchenko added 30 commits July 21, 2017 22:05
…her` concept. Use `Ack` instead of `IsSent`: handle the renaming.
Define the basic communication protocol.
# Conflicts:
#	core/src/main/java/io/spine/core/EventClass.java
#	core/src/main/java/io/spine/core/RejectionClass.java
#	server/src/main/java/io/spine/server/BoundedContext.java
#	server/src/main/java/io/spine/server/entity/EventDispatchingRepository.java
#	server/src/main/java/io/spine/server/outbus/CommandOutputBus.java
#	server/src/main/java/io/spine/server/projection/ProjectionRepository.java
#	server/src/main/java/io/spine/server/reflect/EventSubscriberMethod.java
#	server/src/main/java/io/spine/server/reflect/MethodMap.java
#	server/src/main/java/io/spine/server/rejection/DispatcherRejectionDelivery.java
#	server/src/test/java/io/spine/server/reflect/EventSubscriberMethodShould.java
…geType` messages received (identify the subscribers in a unique way for that).
Use this property to route messages between `IntegrationBus` instances.
the local bus subscriptions upon `RequestedMessageTypes` message handling.
# Conflicts:
#	core/src/main/java/io/spine/core/Events.java
#	server/src/main/java/io/spine/server/reflect/EventSubscriberMethod.java
…grationBus` to `EventBus` and `RejectionBus`.

Add an `external` attribute to `Rejection` message — to comply the adapter contract.
…e top-level class to ease code readability and improve structure.
Address `weather` - > `whether` typos in the related classes.
# Conflicts:
#	server/src/main/java/io/spine/server/event/EventReactorMethod.java
#	server/src/main/java/io/spine/server/event/EventSubscriberMethod.java
#	server/src/main/java/io/spine/server/model/MessageHandlerMap.java
#	server/src/main/java/io/spine/server/procman/ProcessManager.java
#	server/src/main/java/io/spine/server/procman/ProcessManagerRepository.java
#	server/src/main/java/io/spine/server/projection/Projection.java
#	server/src/main/java/io/spine/server/projection/ProjectionRepository.java
#	server/src/main/java/io/spine/server/reflect/MethodRegistry.java
#	server/src/main/java/io/spine/server/rejection/RejectionSubscriberMethod.java
#	server/src/test/java/io/spine/server/commandbus/AbstractCommandBusTestSuite.java
…odel` classes; cache them to use more effectively.
…re tests for `IntegrationBus` `@React`ing.
@armiol
Copy link
Contributor Author

armiol commented Sep 15, 2017

@alexander-yevsyukov comments are addressed. PTAL again.

@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
… and adjust Javadocs accordingly. Make those `final`.
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
Copy link
Contributor

@alexander-yevsyukov alexander-yevsyukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@SpineEventEngine SpineEventEngine deleted a comment Sep 15, 2017
@armiol armiol merged commit 96c970c into master Sep 15, 2017
@armiol armiol deleted the integration-bus branch September 15, 2017 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants