3

Can I make concurrent calls using Spring JMSTemplate?

I want to make 4 external service calls in parallel and am exploring using Spring's JMSTemplate to perform these calls in parallel and wait for the execution to complete.

The other option that I am looking at is to use ExecutorService.

Is there any advantage using one over the other?

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
Punter Vicky
  • 15,954
  • 56
  • 188
  • 315
  • You wanted to make parallel calls to different JMS queues or Same queues? – Pavan Jul 01 '16 at 05:21
  • To different jms queues , Pavan – Punter Vicky Jul 01 '16 at 06:14
  • Do you want to have synchronous calls to your external server or asynchronous? That is, do you want to block your thread after sending a request and wait for the response (not being able to do other things in this thread until the server handles the request)? Or do you want a thread to emit a request and to continue doing its work (whatever it is) while waiting for the response from the server asynchronously? – Andrew Lygin Jul 01 '16 at 06:51
  • I expanded my answer so you could find the solution in both cases. – Andrew Lygin Jul 01 '16 at 07:14

2 Answers2

5

JMSTemplate is thread-safe, so making parallel calls to it is not a problem.

Messaging services are usually fast enough for most tasks and can receive your messages with minimal latency, so adding an ExecutorService doesn't seem as the first thing you usually need. What you really need is to correctly configure your JMS connections pool and give it enough open connections (four in your case) so it could handle your parallel requests with no blocking.

You only need ExecutorService in case you don't care about guaranteed delivery and your program needs extremely high speed that your messaging service cannot deliver, which is highly unlikely.

As for receiving replies from your external service, you need to use JMS Request/Reply pattern (you can find examples in this article). Happily, as you're using Spring, you could make Spring Integration do lots of work for you. You need to configure outbound-gateway to send messages and inbound-gateway to receive responses. Since version 2.2 you can also use reply-listener to simplify things on your client side. All these components are covered in the official documentation (with examples as well).

Andrew Lygin
  • 6,077
  • 1
  • 32
  • 37
  • Thanks @Andrew. Is it possible for me to use jms and wait for responses to be received ? I have used jms for asynchronous messaging in the past , however in this case my code should block until I get responses for all my 4 calls. – Punter Vicky Jul 01 '16 at 06:21
  • With regards to connection pool , my service will receive 100s of requests every minute , so I believe I should set a higher connection pool if I'm not wrong – Punter Vicky Jul 01 '16 at 06:29
  • 100s req/min is no big deal for most of modern messaging systems (if configured properly). Moreover, if you only use four threads to emit messages, there's no need in higher number of connections since they will sit idle. But you'll need some additional connections to receive responses. Let's continue the discussion in comments to your question and then I'll be able to clarify my answer. – Andrew Lygin Jul 01 '16 at 06:44
  • Great , thank you very much ! Is it possible to block at some point in the program but not as soon as the request is sent. Typically when I use Java future , I do a future. get at the point where I need response to proceed. With jms , is this something that can be done ? – Punter Vicky Jul 01 '16 at 10:23
  • Absolutely. You need to create a simple class (let's call it `RemoteService`) with a method `request(...)` that would send your requests to the server, create a `Future`, put it into some local map (concurrent) with a message ID as the key, return this `Future` to the callee and then wait for the response from server asynchronously. As soon as the response arrives, you just find the corresponding `Future` in the map (using CorrelationID from the response) and assign a value to it. – Andrew Lygin Jul 01 '16 at 13:49
3

So need to talk to more than two JMS queues (send and or receive) parallel using asynchronous methods. Best option is usng @Asynch at method level

This example contains RestTemplate , But in your case create JmsTemplate beans.

Prerequisites:- Please create proper JMS Beans to connect to the queue. Proper use of this will help to invoke two queues paralleley. Its works for sure because already I have implemented. I just giving the skeleton due to Copyright issues.

More details: Spring Boot + Spring Asynch https://spring.io/guides/gs/async-method/

Step1: Create a Service Class where JMS Queue

@EnableAsynch
public class JMSApplication {

@Autowired
JmsService jmsService;

     public void invokeMe(){
      // Start the clock
        long start = System.currentTimeMillis();

        // Kick of multiple, asynchronous lookups
        Future<Object> queue1= jmsService.findqueue1();
        Future<Object> queue2= jmsService.findqueue2();

        // Wait until they are all done
        while (!(queue1.isDone() && queue2.isDone())) {
            Thread.sleep(10); //10-millisecond pause between each check
        }

        // Print results, including elapsed time
        System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
        System.out.println(queue1.get());
        System.out.println(queue2.get());

     }
}

Step2: Write the Service Method which will contain the business logic for Jms

   @Service
   public Class JmsService{

         @Asynch
         public Object findqueue1(){
         //Logic to invoke the JMS queue 
         }

         @Asynch
         public Object findqueue2(){
         //Logic to invoke the JMS queue 
         }
    }
Pavan
  • 1,219
  • 13
  • 15