git checkout lesson-6
Ecotone
provides abstractions for asynchronous execution.User should be able to place order for different products.
Order
aggregate.PlaceOrderCommand
with ordered product IdsOrderedProduct
value object, which will describe, cost and identifier of ordered productOrder
aggregateplaceOrder
- Place order method make use of QueryBus
to retrieve cost of each ordered product.
You could find out, that we are not using application/json
for product.getCost
query, ecotone/jms-converter
can handle array
transformation, so we do not need to use json
.placeOrder
that will hide QueryBus
implementation from the domain, or you may get this data from data store
directly. We do not want to complicate the solution now, so we will use QueryBus
directly. Repository
, as our exiting one can handle any new aggregate arriving in our system.order.place Command Handler
to run asynchronously using RabbitMQ
now.
Let's start by adding extension to Ecotone
, that can handle RabbitMQ:
ConnectionFactory
to our Dependency Container.
AmqpConnectionFactory
under the class name Enqueue\AmqpLib\AmqpConnectionFactory.
This will help Ecotone resolve it automatically, without any additional configuration.AMQP Backed Channel
(RabbitMQ Channel), in order to do it, we need to create our first Application Context.
Application Context is a non-constructor class, responsible for extending Ecotone
with extra configurations, that will help the framework act in a specific way. In here we want to tell Ecotone
about AMQP Channel
with specific name.
Let's create new class App\Infrastructure\MessagingConfiguration.
ServiceContext
- Tell that this method returns configuration. It can return array of objects or a single object.order.place
Command Handler, that it should run asynchronously using our neworders
channel. Asynchronous
annotation with channelName
used for asynchronous endpoint.
Endpoints using Asynchronous
are required to have endpointId
defined, the name can be anything as long as it's not the same as routing key (order.place)
. ecotone:list
orders.
Name comes from the message channel name.
You may wonder why it is not place_order_endpoint,
it's because via single asynchronous channel we can handle multiple endpoints, if needed. This is further explained in asynchronous section.orderId
in our testing command, so we can place new order.bin/console ecotone:quickstart
we should get an exception:order.place
Command Handler to run asynchronously, so we need to run our asynchronous endpoint
in order to handle Command Message
. If you did not received and exception, it's probably because orderId
was not changed and we already registered such order.
Let's run our asynchronous endpointQuery Handler
and check, if the order really exists now.AddUserIdService Interceptor
to perform the action before sending it to asynchronous channel.
This Interceptor is registered as Before Interceptor
which is before execution of our Command Handler, but what we want to achieve is, to call this interceptor before message will be send to the asynchronous channel. For this there is Presend
Interceptor available.
Change Before
annotation to Presend
annotation and we are done.Presend
interceptor, we can validate messages, before they will go asynchronous, to prevent sending incorrect messages.
git checkout lesson-7