diff --git a/book/SUMMARY.md b/book/SUMMARY.md index dc707dca..c25eba41 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -11,7 +11,8 @@ - [Messages](messaging/messages.md) - [Gateway](messaging/gateway.md) - [Inversion integration](messaging/inversion.md) - - [Implementations](messaging/implementations.md) + - [Reference Implementation](messaging/reference.md) + - [Moleculer Implementation](messaging/moleculer.md) - [Adapters](messaging/adapters.md) - [Elements](elements/README.md) - [ElementBuilder](elements/ElementBuilder.md) diff --git a/book/messaging/implementations.md b/book/messaging/implementations.md deleted file mode 100644 index 922f4b0d..00000000 --- a/book/messaging/implementations.md +++ /dev/null @@ -1,103 +0,0 @@ -# Implementations - -## The reference implementation - -> The reference implementation is defined in the NPM package [@tmorin/ceb-messaging-simple](https://www.npmjs.com/package/@tmorin/ceb-messaging-simple). - -The reference implementation relies on an in-memory and single process approach. -So that, the implementation is free of network or any other concerns related to distributed systems. - -### The SimpleGateway - -A SimpleGateway instance can be got from the following three approaches: the global instance, the factory method or the constructor. - -#### The global instance - -A global instance of the SimpleGateway is available from the static field `SimpleGateway.GOBAL`. -It's a lazy property, in fact the instance is only created once at its first get. - -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_global.ts}} -``` - -#### The factory method - -A SimpleGateway instance can be easily created using the factory method, i.e. the static method `SimpleGateway.create()`. -The method returns a fresh new SimpleGateway instance at each call. - -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_factory.ts}} -``` - -#### The constructor - -The constructor approach provides a fine grain control of the Gateway dependencies: the CommandBus, the QueryBus, the EventBus and the GatewayObserver. - -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_constructor.ts}} -``` - -### The Inversion Module - -The package provides an Inversion Module which can be used to create (optionally) and register it on the registry. - -Create a container with the default module behavior, i.e. the SimpleGateway will be created from scratch automatically: -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/implementation-inversion-default.ts}} -``` - -Create a container with a provided SimpleGateway instance: -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/implementation-inversion-global.ts}} -``` - -## The Moleculer implementation - -> The Moleculer implementation is defined in the NPM package [@tmorin/ceb-messaging-moleculer](https://www.npmjs.com/package/@tmorin/ceb-messaging-moleculer). - -The [Moleculer] implementation leverages on the features provided by the microservices framework. - -### Management of Commands and Queries - -There is one [Moleculer service] per command or query types. -For instance, the command type `CommandA` will be managed by the service `CommandA`. - -About commands, each service provides two [Moleculer actions]: `execute` and `executeAndForget`. -The first one executes the command handler and return the result. -The second one just executes the command handler at the next clock thick. -For instance, the command type `CommandA` can be executed within the Moleculer world with the actions `CommandA.execute` and `CommandA.executeAndForget`. -Each action accepts only one parameter: the command. - -About queries, each service provides only one action: `execute`. -The action executes the query handler and return the result. -For instance, the query type `QueryA` can be executed within the Moleculer world with the action `QueryA.execute`. -The action accepts only one parameter: the query. - -### Management of Events - -The Events are managed by a single [Moleculer service]: `EventBus`. -Each time an Event is published, the type of [Moleculer event] is `Event.MESSAGE_TYPE`. -For instance, when the Event `EventA` is published, the Moleculer event name is `EventBus.EventA`. - -By default, the implementation publish messaging using the _balanced_ mode. -Because of the single Moleculer service `EventBus`, it means each Event will only be handled by only one service in the cluster. - -### The Inversion Module - -The package provides an Inversion Module which can be used to create the MoleculerGateway instance and register it on the registry. - -Create a container with the default module behavior, i.e. a ServiceBroker is expected in the registry: -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/moleculer-inversion-registrykey.ts}} -``` - -Create a container with a provided ServiceBroker instance. -In that case, the provided ServiceBroker will be registered in the registry. -```typescript -{{#include ../../packages/ceb-book-samples/src/messaging/moleculer-inversion-instance.ts}} -``` - -[Moleculer]: https://moleculer.services -[Moleculer service]: https://moleculer.services/docs/0.14/actions.html -[Moleculer actions]: https://moleculer.services/docs/0.14/actions.html -[Moleculer event]: https://moleculer.services/docs/0.14/events.html diff --git a/book/messaging/moleculer-balanced-microlith.png b/book/messaging/moleculer-balanced-microlith.png new file mode 100644 index 00000000..1ad30255 Binary files /dev/null and b/book/messaging/moleculer-balanced-microlith.png differ diff --git a/book/messaging/moleculer-balanced-monolith.png b/book/messaging/moleculer-balanced-monolith.png new file mode 100644 index 00000000..23b7b837 Binary files /dev/null and b/book/messaging/moleculer-balanced-monolith.png differ diff --git a/book/messaging/moleculer.md b/book/messaging/moleculer.md new file mode 100644 index 00000000..400f3066 --- /dev/null +++ b/book/messaging/moleculer.md @@ -0,0 +1,59 @@ +# The Moleculer implementation + +> The Moleculer implementation is defined in the NPM package [@tmorin/ceb-messaging-moleculer](https://www.npmjs.com/package/@tmorin/ceb-messaging-moleculer). + +The [Moleculer] implementation leverages on the features provided by the microservices framework. + +## Management of Commands and Queries + +There is one [Moleculer service] per command or query types. +For instance, the command type `CommandA` will be managed by the service `CommandA`. + +About commands, each service provides two [Moleculer actions]: `execute` and `executeAndForget`. +The first one executes the command handler and return the result. +The second one just executes the command handler at the next clock thick. +For instance, the command type `CommandA` can be executed within the Moleculer world with the actions `CommandA.execute` and `CommandA.executeAndForget`. +Each action accepts only one parameter: the command. + +About queries, each service provides only one action: `execute`. +The action executes the query handler and return the result. +For instance, the query type `QueryA` can be executed within the Moleculer world with the action `QueryA.execute`. +The action accepts only one parameter: the query. + +## Management of Events + +The Events are managed by a single [Moleculer service]: `EventBus`. +Each time an Event is published, the type of the [Moleculer event] is `EventBus.`. +For instance, when the Event `EventA` is published, the Moleculer event name is `EventBus.EventA`. + +By default, the implementation publish messages using the _balanced_ mode. +That means, each _balanced_ event will be processed by only one `EventBus` Moleculer service instance within the cluster. + +The default mode works well for monoliths where the logic is replicated in each node of the cluster. + +![Event Balancer and Monolith](moleculer-balanced-monolith.png) + +However, for Microliths or even Microservices, the `EventBus` instances have to arrange in logical groups. +The group name of `MoleculerEventBus` instances can be provided by constructor. + +![Event Balancer and Microlith](moleculer-balanced-microlith.png) + +## The Inversion Module + +The package provides an Inversion Module which can be used to create the MoleculerGateway instance and register it on the registry. + +Create a container with the default module behavior, i.e. a ServiceBroker is expected in the registry: +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/moleculer-inversion-registrykey.ts}} +``` + +Create a container with a provided ServiceBroker instance. +In that case, the provided ServiceBroker will be registered in the registry. +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/moleculer-inversion-instance.ts}} +``` + +[Moleculer]: https://moleculer.services +[Moleculer service]: https://moleculer.services/docs/0.14/actions.html +[Moleculer actions]: https://moleculer.services/docs/0.14/actions.html +[Moleculer event]: https://moleculer.services/docs/0.14/events.html diff --git a/book/messaging/moleculer.puml b/book/messaging/moleculer.puml new file mode 100644 index 00000000..a53f836c --- /dev/null +++ b/book/messaging/moleculer.puml @@ -0,0 +1,89 @@ +@startuml moleculer-balanced-monolith +!include ../reference.puml +!global $LIB_BASE_LOCATION="../../.gdiag/plantuml-libs" +!global $IMAGE_BASE_PATH="../../.gdiag/plantuml-libs/" +Title("Event Balancer and Monolith", "The Moleculer implementation") +package node_a as "node 1" { + card component_a [ + CommandA (Meleculer Service) + -- + emit("EventBus.EventA", ...) + ] + card eventbus_a [ + EventBus (Meleculer Service) + --listeners-- + EventBus.EventA + EventBus.EventB + ] +} +package node_b as "node 2" { + card eventbus_b [ + EventBus (Meleculer Service) + --listeners-- + EventBus.EventA + EventBus.EventB + ] + card component_b [ + CommandA (Meleculer Service) + -- + emit("EventBus.EventA", ...) + ] +} +package node_c as "node 3" { + card eventbus_c [ + EventBus (Meleculer Service) + --listeners-- + EventBus.EventA + EventBus.EventB + ] + card component_c [ + CommandA (Meleculer Service) + -- + emit("EventBus.EventA", ...) + ] +} +component_a --> eventbus_b : send to only one EventBus +node_a -[hidden]- node_b +node_b -[hidden]- node_c +@enduml + +@startuml moleculer-balanced-microlith +!include ../reference.puml +!global $LIB_BASE_LOCATION="../../.gdiag/plantuml-libs" +!global $IMAGE_BASE_PATH="../../.gdiag/plantuml-libs/" +Title("Event Balancer and Microliths", "The Moleculer implementation") +rectangle context_a as "Bounded Context A" { + card eventbus_a [ + EventBus (Meleculer Service) + group: Bounded Context A + --listeners-- + EventBus.EventA + ] + card component_a [ + CommandA (Meleculer Service) + -- + emit("EventBus.EventA", ...) + ] +} +rectangle context_b_1 as "Bounded Context B" { + card eventbus_b_1 [ + EventBus (Meleculer Service) + group: Bounded Context B + --listeners-- + EventBus.EventA + EventBus.EventB + ] +} +rectangle context_b_2 as "Bounded Context B" { + card eventbus_b_2 [ + EventBus (Meleculer Service) + group: Bounded Context B + --listeners-- + EventBus.EventA + EventBus.EventB + ] +} +component_a --> eventbus_b_1 : send to only one EventBus for the Bounded Context B +component_a -r-> eventbus_a : send to only one EventBus for the Bounded Context A +eventbus_b_1 -[hidden]r- eventbus_b_2 +@enduml diff --git a/book/messaging/reference.md b/book/messaging/reference.md new file mode 100644 index 00000000..96f330df --- /dev/null +++ b/book/messaging/reference.md @@ -0,0 +1,50 @@ +# The reference implementation + +> The reference implementation is defined in the NPM package [@tmorin/ceb-messaging-simple](https://www.npmjs.com/package/@tmorin/ceb-messaging-simple). + +The reference implementation relies on an in-memory and single process approach. +So that, the implementation is free of network or any other concerns related to distributed systems. + +## The SimpleGateway + +A SimpleGateway instance can be got from the following three approaches: the global instance, the factory method or the constructor. + +### The global instance + +A global instance of the SimpleGateway is available from the static field `SimpleGateway.GOBAL`. +It's a lazy property, in fact the instance is only created once at its first get. + +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_global.ts}} +``` + +### The factory method + +A SimpleGateway instance can be easily created using the factory method, i.e. the static method `SimpleGateway.create()`. +The method returns a fresh new SimpleGateway instance at each call. + +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_factory.ts}} +``` + +### The constructor + +The constructor approach provides a fine grain control of the Gateway dependencies: the CommandBus, the QueryBus, the EventBus and the GatewayObserver. + +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/implementation-create_constructor.ts}} +``` + +## The Inversion Module + +The package provides an Inversion Module which can be used to create (optionally) and register it on the registry. + +Create a container with the default module behavior, i.e. the SimpleGateway will be created from scratch automatically: +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/implementation-inversion-default.ts}} +``` + +Create a container with a provided SimpleGateway instance: +```typescript +{{#include ../../packages/ceb-book-samples/src/messaging/implementation-inversion-global.ts}} +``` diff --git a/book/reference.puml b/book/reference.puml index b6d67ac4..0ba1ddf4 100644 --- a/book/reference.puml +++ b/book/reference.puml @@ -39,6 +39,10 @@ skinparam { RectangleBorderColor #2e3440 RectangleBorderThickness 1 + NodeFontColor #2e3440 + NodeBorderColor #2e3440 + NodeBorderThickness 1 + PackageFontName Architects Daughter PackageFontStyle normal PackageBorderColor #2e3440