having multiple subscribers to events published via SpringAMQP event bus

Hi,

I have a scenario where we have multiple Bounded Contexts, each of these contexts runs as a separate web application. All of these contexts use the Axon framework.

If an event is produced in one of these BC’s, the expectation is that it should be published to all of the BC’s, then the subscribing bounded context will decide if any action needs to be taken based on the event or not.

For this we use the Fanout exchange, using the fanout exchange and a single queue, i have observed that, once a event listeners picks the message off the queue, none of the other listeners able able to get a copy of the message.

So this configuration leads to a scenario where only one of the BC’s can react to the event, as none of the other BC’s are notified.

So we have tried a alternate configuration which works for us, just wanted to confirm if that is the “best practice”

Configure the exchange of each BC to publish the message on multiple queue’s (one queue per BC), each BC Axon terminal listens to only one queue (the queue specific to itself)

so if we have 2 BC saying BC PatientCare and BC PatientAdmission.

The the exchange in both of these application will publish on both PatientCare and PatientAdmission.

The Axon terminal on BC PatientCare will listen only to the PatientCare Queue and similarly the Axon terminal on BC PatientAdmission will listen only to the PatientAdmission Queue.

Please let me know if this sounds ok, or whether we should consider topics or some other mechanism.

Thanks
Sudarshan

Hi Sudarshan,

Not sure if this fits for your use case but what we usually do is setup a fanout exchange on the publishing side (one of the BCs in your case) and let the interested parties subscribe to this exchange by connecting a queue to it. These subscribers could be other BCs but could also be other external systems. The publishing BC doesn’t and shouldn’t care how the events are routed past the exchange.

Of course, this should be set up in “all” directions. The publishing BCs should all set up an exchange while the subscribing BCs subscribe to all the BCs they’re interested in.

Depending on your requirements it might be handy to use a topic exchange as this allows you to route the messages in a fine grained way but reading your e-mail it seems that the fanout exchange would suffice (for now).

Read the RabbitMQ documentation for a more detailed PubSub example: http://www.rabbitmq.com/tutorials/tutorial-three-java.html

Regards,

Dennis Laumen

E: dennis@dennislaumen.nl
I: www.dennislaumen.nl

In the fanout exchange i need to specify the queues to which the exchange binds with in this case, i will need to specify multiple queues as we have multiple BC’s, is my understanding correct ?

Hi Sudarshan,

In the fanout exchange i need to specify the queues to which the exchange binds with in this case, i will need to specify multiple queues as we have multiple BC’s, is my understanding correct ?

Yes, that is correct. The fanout just broadcasts all messages it receives to all bound queues. In our projects with RabbitMQ we prefer to bind the queues on the subscriber side as this allows the publishing side to be unaware of all the subscribers. This allows you to scale up the subscriber side (add new applications/BCs, add new instances of existing applications/BCs) without having to touch the publishing side.

I hope this helps. Read this article for an explanation of all the concepts, this will clear up a lot and help you make the right decisions for your system: http://www.rabbitmq.com/tutorials/amqp-concepts.html.

Hi,

Thanks for the link. I have gone through it. I think we need something like what you have mentioned.

I am however a little confused with the below comment

" In our projects with RabbitMQ we prefer to bind the queues on the subscriber side as this allows the publishing side to be unaware of all the subscribers"

In our case we can’t really differentiate a application as publisher or subscriber … as all the applications are both subscribers and publishers based on the context. I mean they all both publish events for actions done within their BC and subscribe for event emitted from other BC’s.

So right now my exchange looks like this

Publishing to all BC’s

<rabbit:fanout-exchange id="eventBusExchange"
name="axonDomainEventsBusExchange"
durable="false"
auto-delete=“true” >
rabbit:bindings
<rabbit:binding queue=“patientAdminQueue”/>
<rabbit:binding queue=“patientCareQueue”/>
</rabbit:bindings>
</rabbit:fanout-exchange>

<axon:cluster id=“cluster” default=“true” >
axon:meta-data


<amqp:configuration queue-name=“patientAdminQueue” exclusive=“false” />

</axon:meta-data>
</axon:cluster>

Subscribing to only one queue, that of the “home BC” … I am not sure how i can subscribe to multiple queues in the Axon configuration. Would be great if you could give me some hints on that too :slight_smile:

Just to summarize, I mainly have 2 questions

  1. Do you think your comment can apply in my scenario ?
  2. “bind the queues on the subscriber side” ---- What does this exactly mean ? Is the exchange unaware of the queues ? … I sample configuration would be great.

Hi Sudarshan,

Assuming your requirements are similar to ours on this topic, both BCs should have their own exchange to publish events to (e.g. BoundedContextAEventsExchange and BoundedContextBEventsExchange). These exchanges can be defined in the application which publishes the message.

Both BCs could also be interested in messages from other BCs. If this is the case they should redefine the exchanges and bind their queues to these.

Although I don’t have any example configs at hand it could look something like this (if both BCs are interested in each others messages):

Config for Bounded Context A:

  • BoundedContextAEventsExchange

  • BoundedContextBEventsExchange

  • BoundedContextAQueue bound to BoundedContextBEventsExchange

Config for Bounded Context B:

  • BoundedContextAEventsExchange

  • BoundedContextBQueue bound to BoundedContextAEventsExchange

  • BoundedContextBEventsExchange

As you can see, we configure our exchanges in multiple places: the publishing side and the subscribing side. If there’s a mismatch between the two your AMQP implementation will throw an error. Of course, the names of the exchanges and queues are examples. I prefer to give them a more meaningful name.

Again, your mileage may vary, these are my experiences and they might not match your requirements.

Regards,

Dennis

Hi Dennis,

Thanks a lot, this does help me a lot, gets me thinking. But i think I have even more questions now :slight_smile:

I think i am missing something a little basic here ?,

As i understand the terminal can be associated with only 1 Exchange.

<amqp:terminal id="terminal"
connection-factory="connectionFactory"
serializer="serializer"
exchange-name="axonDomainEventsBusExchange"
durable="false"
transactional=“false” wait-for-publisher-ack=“true”>
</amqp:terminal>

So via Axon Event Bus we could only publish to only one Exchange (per application) , which in turn can send the message on multiple queues right. This is my understanding based on which i have the below questions

Config for Bounded Context A:

- BoundedContextAEventsExchange ---- (What role is this exchange playing here, is it associated to any terminal, Do you configure One terminal per Exchange also ?)

- BoundedContextBEventsExchange ---- ( Do you publish the messges on BoundedContextBEventsExchange and then expect the other BC’s to use BoundedContextBEventsExchange and BoundedContextAQueue to read the events emitted by BC A ?)
- BoundedContextAQueue bound to BoundedContextBEventsExchange

Do you have one Exchange per BC ? Assuming BC’s can talk to each other

Hi Sudarshan,

I was mostly talking about the RabbitMQ configuration. We do a lot of projects with non-trivial RabbitMQ configurations but haven’t needed this in combination with multiple bounded contexts and Axon. I would assume one would use multiple event buses here but I’m guessing Allard has a way more insightful answer for you ;-).

Regards,

Dennis

Thanks dennis for the help, Axon allows only one event bus per spring context, defining multiple spring contexts just for this would be a overkill in our case

In general, you’ll have a context file that defines the event bus (including the terminal that points to an Exchange). All BC’s can use this configuration file.
Each application will define a number of Clusters, where each Cluster will connect to each own Queue. This way, applications don’t have to be aware of which queues are connected to the exchange.

I use a Topic Exchange by default, as it makes it possible to define which events go to which queue. The application that defines the queue (the reading side), defines the binding that is used between the queue and the exchange.

Hope this clarifies things.
Cheers,

Allard

I am not still sure how to configure this up :).

I think the high level idea is that the publisher should not be aware of the subscribing queues, this allowing new subscribers to be added into the mix, without changing any of the publishers, please correct me if I am wrong.
I have a requirement where in each BC needs to subscribe to events published in that BC and also in other external BC’s.

I am not sure if i have fully understood your hints here :slight_smile:

But based on what I have understood this is what i have come up, And it meets the two requirements I put down above , it would be great if you can have a look at it

So now my exchange look like this.

BC Patient Administration

Exchange

Cluster

So now this BC is aware of only 1 queue.

All the BC’s use the same exchange to bind their respective queues. So once all the apps are up, the exchange has been bound to multiple queues. So when a message is published to the exchange it is sent out on all the queues. Each App is subscribing to its dedicated queue and picks messages of it.

BC PatientCare

<rabbit:fanout-exchange id="eventBusExchange"
name="axonDomainEventsBusExchange"
durable="false"
auto-delete=“true” >
rabbit:bindings
<rabbit:binding queue=“patientCareQueue”/>
</rabbit:bindings>
</rabbit:fanout-exchange>

It seems your assumptions were correct. The configuration looks fine.
I would advise using the topic exchange, though. It allows you to define a filter on the binding for each queue. This way, you can be more specific about which events you would like to appear on each queue. It’s just an optimization, though.

Cheers,

Allard

Thanks.