How about Request-Reply API calls in Messaging?

Amir Vosough
5 min readAug 12, 2020

While I was migrating my pet project from REST-based communication between micro-services to async message-based architecture, I came across an interesting problem. While I believe there are simple solutions for this, I was also thinking of a more generic way of handling these scenarios and would love to hear your thoughts on this.

Let’s start with a our simple case. We have two different micro-services “Order” micro-service which will focus on Orders and “User Profile” micro-service which is the expert on Users and their information. Now, let’s say along the way, Order needs to get the User information for the one who submitted the Order. In the REST-based world, Order micro-service will probably call a REST API from User Profile micro-service and gets the User’s information, something like this:

Using a REST to call an API

This is familiar territory. But let’s move this to messaging world. How would you deliver this functionality with messaging? One option is to use Request-Replies using JMS Queues with the help of reply-to feature. If you google “JMS queue request reply” you will see lots of examples for this. There are two ways of delivering request-reply with JMS Queues, either the requester has a fixed queue in which case it will use a correlation-id to tell the API provider how to return the reply or the requester will create a temporary queue which is the queue that it expects to get the reply message for a specific request, in this case, the requester will only need to specify “reply-to” queue header. Both scenarios are rather simple and are supported by Spring Messaging. With this solution our previous diagram will be transformed to this:

Using Request-Reply JMS Queues to call an API

As you can see not much has changed, only the transfer media has changed and if you have followed my previous article, you probably have a good idea how to minimize the side effects of this transformation.

However, when I tried to do this with spring cloud streams, I couldn’t find a good way of achieving request-reply in spring cloud streams. The RabbitMQ binder uses topics usually, and I don’t think the binder cares about “correlation-id” and “reply-to” headers. While I was investigating these, it suddenly hit me, I am trying to introduce problems in my application that was supposed to be solved by switching to an async message-based architecture!

  • The first problem was that the default Spring implementation of request-reply with JMS was sync. So if we use those, we are introducing “wait” which will waste CPU. This could be solved by using the Async Templates from Spring Integration or RabbitMQ or AMQP or…
  • How to pass headers from incoming message to outgoing reply when all of this is supposed to be handled by Spring Cloud Streams?
  • Does Spring Cloud Stream even work with JMS Queues or is that an anti-pattern for their model?
  • We still depend on a specific instance of our Order micro-service to take care of the reply message when it’s ready:
Only micro-service #2 can handle the reply message of User Profile

The first bullet point is not really a problem (unless you don’t know about async “requirements”). But the rest stands. If I want to focus on why we are facing this problem, it probably comes from the fact that Order micro-service is keeping some “states” which is needed to continue the processing of submitted order after the reply message comes back. The handling of this “state” is probably almost invisible to you because usually JVM will keep it somewhere as it sees you’re using it on the lambda or the anonymous class which should handle the reply message.

I think given the situation, the best way to solve all these problems is to pass the “states” to the User Profile micro-service and expect it to come back with the not-so-called reply. This means when Order micro-service finds out it needs User’s information, it will send this Order to the User Profile asking it to fill the User details. User Profile then sends back Order+User details as a new message on a topic and now any Order micros-service instance should be able to handle this message:

Order sent to User Profile, Order+User details is sent back to Order

Now this is more like async messaging! This solution is more scalable because as mentioned, any instance of Order micro-service can handle it. It solves all those problems, but it comes with a cost. Now, User Profile micro-service needs to know about the Order micro-service. Previously, User Profile was providing a generic service where any micro-service could pass the username and get back the user profile, but now we will have to implement different versions for different callers, a function that receives an Order and returns Order+User details, another function which receives Payment and returns Payment+User details, etc. This could be considered as an acceptable cost for what we gained, but I was thinking what if we could deliver a generic service where no matter what the input is, we will always add something to it and return it to a given destination.

While I was discussing this with my wife, we came up with the name “Incremental Messaging” for this kind of messaging, and as far as I know, there’s no easy way to do this with Spring Cloud Streams. Additionally not all messaging serializations could support this. So my first suggestion would be, using JSON, implement something like this:

@Bean
public Function<ObjectNode, ObjectNode> addUserInfo() {
return jsonNodes -> {
jsonNodes.set("userDetails", new TextNode("Boblob Law"));
return jsonNodes;
};
}

This function as you can see, gets a JSON object as input, adds a new property to it, and returns the modified object. The next challenge is, how can we send this message to the destination which was specified by the requester? Either using incoming message headers in the destination configuration of our application, or worst case scenario, we could have multiple function definitions in our configuration corresponding to each input/output. This is not possible as far as I know either.

What do you think about “Incremental Messaging”? have you faced similar cases or know a better way of doing this? If so, please share your experience with me!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response