Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send parallel GET requests and wait for result responses?

I'm using apache http client within spring mvc 3.2.2 to send 5 get requests synchronously as illustrated.

How can I send all of these asynchronously (in parallel) and wait for the requests to return in order to return a parsed payload string from all GET requests?

public String myMVCControllerGETdataMethod() {    // Send 1st request     HttpClient httpclient = new DefaultHttpClient();    HttpGet httpget = new HttpGet("http://api/data?type=1");       ResponseHandler<String> responseHandler = new BasicResponseHandler();    String responseBody = httpclient.execute(httpget, responseHandler);     // Send 2st request     HttpClient httpclient2 = new DefaultHttpClient();    HttpGet httpget2 = new HttpGet("http://api/data?type=2");       ResponseHandler2<String> responseHandler2 = new BasicResponseHandler();    String responseBody2 = httpclient.execute(httpget, responseHandler2);     // o o o more gets here     // Perform some work here...and wait for all requests to return    // Parse info out of multiple requests and return    String results = doWorkwithMultipleDataReturned();     model.addAttribute(results, results);    return "index";  } 
like image 261
genxgeek Avatar asked Jul 21 '13 23:07

genxgeek


People also ask

How do I make a concurrent API call?

Code for concurrent API call: tags); // make concurrent api calls const requests = tags. map((tag) => axios. get("https://api.hatchways.io/assessment/blog/posts?tag=" + tag) ); try { // wait until all the api calls resolves const result = await Promise. all(requests); // posts are ready.


2 Answers

Just in general, you need to encapsulate your units of work in a Runnable or java.util.concurrent.Callable and execute them via java.util.concurrent.Executor (or org.springframework.core.task.TaskExecutor). This allows each unit of work to be executed separately, typically in an asynchronous fashion (depending on the implementation of the Executor).

So for your specific problem, you could do something like this:

import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.FutureTask; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;  @Controller public class MyController {     //inject this     private Executor executor;      @RequestMapping("/your/path/here")     public String myMVCControllerGETdataMethod(Model model) {         //define all async requests and give them to injected Executor         List<GetRequestTask> tasks = new ArrayList<GetRequestTask>();         tasks.add(new GetRequestTask("http://api/data?type=1", this.executor));         tasks.add(new GetRequestTask("http://api/data?type=2", this.executor));         //...         //do other work here         //...         //now wait for all async tasks to complete         while(!tasks.isEmpty()) {             for(Iterator<GetRequestTask> it = tasks.iterator(); it.hasNext();) {                 GetRequestTask task = it.next();                 if(task.isDone()) {                     String request = task.getRequest();                     String response = task.getResponse();                     //PUT YOUR CODE HERE                     //possibly aggregate request and response in Map<String,String>                     //or do something else with request and response                     it.remove();                 }             }             //avoid tight loop in "main" thread             if(!tasks.isEmpty()) Thread.sleep(100);         }         //now you have all responses for all async requests          //the following from your original code         //note: you should probably pass the responses from above         //to this next method (to keep your controller stateless)         String results = doWorkwithMultipleDataReturned();         model.addAttribute(results, results);         return "index";     }      //abstraction to wrap Callable and Future     class GetRequestTask {         private GetRequestWork work;         private FutureTask<String> task;         public GetRequestTask(String url, Executor executor) {             this.work = new GetRequestWork(url);             this.task = new FutureTask<String>(work);             executor.execute(this.task);         }         public String getRequest() {             return this.work.getUrl();         }         public boolean isDone() {             return this.task.isDone();         }         public String getResponse() {             try {                 return this.task.get();             } catch(Exception e) {                 throw new RuntimeException(e);             }         }     }      //Callable representing actual HTTP GET request     class GetRequestWork implements Callable<String> {         private final String url;         public GetRequestWork(String url) {             this.url = url;         }         public String getUrl() {             return this.url;         }         public String call() throws Exception {             return new DefaultHttpClient().execute(new HttpGet(getUrl()), new BasicResponseHandler());         }     } } 

Note that this code has not been tested.

For your Executor implementation, check out Spring's TaskExecutor and task:executor namespace. You probably want a reusable pool of threads for this use-case (instead of creating a new thread every time).

like image 107
superEb Avatar answered Oct 04 '22 10:10

superEb


You should use AsyncHttpClient. You can make any number of requests, and it will make a call back to you when it gets a response. You can configure how many connections it can create. All the threading is handled by the library, so it's alot easier than managing the threads yourself.

take a look a the example here: https://github.com/AsyncHttpClient/async-http-client

like image 44
Alper Akture Avatar answered Oct 04 '22 09:10

Alper Akture