A common reason cited for breaking up an existing monolithic application into microservices is ‘scalability’. A quick search through StackOverflow shows that few people really get how to do this, and there are actually no really good answers to the question of how to coordinate competing microservices.

The core question many people have is that if multiple, identical, services are competing to consume an event, once the event is consumed by one service, how do you ensure that the other non-competing services still also get invoked.

In this article I explain how to do this with a simple hypothetical example, written in NodeJS, using RabbitMQ as the message bus¹.

Scenario

Let’s imagine you are building a system that retreives images from the ‘net, OCRs them to extract any textual content, and records any meta-data associated with that image. The OCR process is slow, so you want to parallelise this aspect of the system by running a number of competing OCR services.

Just for good measure, you also want to run multiple meta-data analysis services as well.

So you write three microservices, that will be linked together via messages sent through an AMQP message bus.

Image Detector: This fetches an image and emits an 'image.detected' event via AMQP when done. Image OCR Service: This listens for the 'image.detected' event and, when it hears that event, it OCRs the image. You’ll run two competing instances of this service. Image Meta-Data Service: This listens for the 'image.detected' event as well and, when it hears it, extracts the image’s meta-data. You’ll also run two competing instances of this.

Both the ImageOCR and ImageMetaData services need to hear the 'image.detected' event, but only one of each service ought to actually handle the message.

The overall system will look like this: