Search code examples
rabbitmqmessage-queuesoaesbmicroservices

Using routing key to communicate services


Take the following sample requirement:

Service A does some work. That work is done periodically and no one asks Service A to do it. It's done automatically.

Service B needs to query data produced by Service A. Service A resides in a different server than Service B.

That is, Service B won't be able to get data if Service A doesn't provide some way of asking it for the data.

I want to require Service A data the SOA way using RabbitMQ: when Service B requires some data, it sends a message to a given exchange and its written to some queue. Then, Service A processes the message and publishes the answer to some other exchange. Finally, Service B listens the answer message and the cycle ends.

My question

I need some way to both publish and consume messages identified by the operation that requested data to Service A, and I also need that each started operation could be identified by an unique identifier.

My question is about how to publish a message and be able to receive an answer for a particular invocation of an operation.

I just want to validate that RabbitMQ routing keys are the answer to this requirement. For example, Service A sends a message with a routing key 072e6ee1-6046-4c3b-bade-9077c863637b. There's a consumer in Service B which consumes any message ignoring the routing key, but once it produces a result, it does publishing a message to an exchange with the same routing key . Therefore, Service A receives message because it's bound to the whole routing key.

Is it a possible right usage of routing keys?


Solution

  • Finally, RabbitMQ already provides a solution to solve my scenario: Remote Procedure Calls tutorial.

    At the end of the day, a message can have correlation id and a reply to fields:

    • Correlation id. An arbitrary value used to uniquely-identify an operation across many exchanges/queues.

    • Reply to. An arbitrary string to define on which exchange or queue you want to put the result of a given operation. The target exchange/queue will be the callback information that will be received by the operation.

    Thus, Service A sends a message to a given exchange with a correlation id and a reply to value. It gets subscribed to reply to exchange. When Service B processes the message it publishes a message to the reply to exchange and Service A receives the whole result.

    BTW, I still have some concerns about this model, because you need to receive callback messages from other operations while you wait for the result, and whenever you consume a message that's not marked with desired correlation id, you simply don't process it and you wait for the next one, and so on, until you get what you want.

    Maybe it might be a good idea that callback messages would be queued with a time-to-live so if who started an operation isn't waiting for the callback anymore, a given callback message would be automatically dropped.

    Another approach would be throwing the callback information as a document or record in a SQL/NoSQL database, and poll the database with an indexed query by callback identifier...

    If I find some other approach using RabbitMQ I'll update my answer.