0

I am trying to send two post requests. Both should sent at same time (in my below current code maybe it does one after another) and should wait for maximum 80ms for response, if no response for request, consider response as null.

public void SendRequests(String requestString){

    TimeLimiter limiter1 = new SimpleTimeLimiter();
    Response response1 = null;
    System.out.println("Request Sent to 1");
    try{
        response1 = limiter1.callWithTimeout(new Callable<Response>() {
        public Response call() {

            //assume sendPost1 method will send POST request to some server and return response from server

            return sendPost1(requestString);
        }
      }, 80, TimeUnit.MILLISECONDS, true);
    }catch(Exception te){
        te.printStackTrace();
    }

    TimeLimiter limiter2 = new SimpleTimeLimiter();
    Response response2 = null;
    System.out.println("Request Sent to 2");
    try{
        response2 = limiter2.callWithTimeout(new Callable<Response>() {
            public Response call() {

                //assume sendPost2 method will send POST request to some server and return response from server


                return sendPost2(requestString);
            }
        }, 80, TimeUnit.MILLISECONDS, true);
    }catch(Exception te){
        te.printStackTrace();
    }

    //Do some process using response1 and response2

    }
}

I am looking for some ways to send 2 post requests at same time and wait for the 80ms for the response, if no response then consider response as null.

@Gray I tried your solution as per below. First for few minute, my servlet response time is 2ms-10ms, but after that, suddenly, it increases to 200-300ms.

@WebServlet("/incomingTraffic")
public class ServletClass  extends HttpServlet {
Gson gson;
private static URL url1;
private static URL url2;

public Exchanger() {
    super();
}
public void init(ServletConfig config) throws ServletException {
    gson = new Gson();

    try{

    url1 = new URL( Constants.URL1 );
    url2 = new URL( Constants.URL2 );

    }catch(Exception e){

    } 

}

public void destroy() {
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.getWriter().append("Served at: ").append(request.getContextPath());
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    ServletInputStream inputStream = request.getInputStream();
    Reader reader = new InputStreamReader(inputStream);

    //Request class is POJO
    final Request requestString = gson.fromJson(reader, Request.class);

    reader.close();
    //long start = System.currentTimeMillis();
    TimeLimiter limiter = new SimpleTimeLimiter();

    //Response class is POJO
    Response response1 = null;
    Response response2 = null;

    final ExecutorService threadPool = Executors.newCachedThreadPool();

    Future<Response> future1 = threadPool.submit(new Callable<Response>() {
        public Response call() {
            return sendPost1(requestString);
        }
    });
    Future<Response> future2 = null;

    if(Some Condition Satisfy){
        future2 = threadPool.submit(new Callable<Response>() {
            public Response call() {
                return sendPost2(requestString);
            }
        });
    }
    threadPool.shutdown();

    long start = System.currentTimeMillis();
    try {
        response1 = future1.get(80, TimeUnit.MILLISECONDS);
    } catch (ExecutionException ee) {
       // job threw exception
    } catch (InterruptedException ie) {
       // this (main?) thread was interrupted, good pattern to re-interupt
       Thread.currentThread().interrupt();
    } catch (TimeoutException te) {
       // wait timed out, maybe this is right?
        response1 = null;
       // try to interrupt the thread
       future1.cancel(true);
    }

    if(requestString.getImp().get(0).getVideo() != null){
    // wait for 80 MILLISECONDS minus how long we've been waiting for 2nd request
    long end = System.currentTimeMillis();
    //System.out.println(start+" - "+end);
    long wait = 80 + start - end;
    if (wait < 0) {
       wait = 0;
    }

    try {
        response2 = future2.get(wait, TimeUnit.MILLISECONDS);
    } catch (ExecutionException ee) {
       // job threw exception
    } catch (InterruptedException ie) {
       // this (main?) thread was interrupted, good pattern to re-interrupt
       Thread.currentThread().interrupt();
    } catch (TimeoutException te) {
       // wait timed out, maybe this is right?
        response2 = null;
       // try to interrupt the thread
       future2.cancel(true);
    }
    }
    try {
        threadPool.awaitTermination(80, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {

    }

    if(response1 == null && response2 == null){
        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
    }else {
        response.setContentType("application/json");
        PrintWriter output = response.getWriter();
        response.setStatus(HttpServletResponse.SC_OK);
        if(Some Condition){
            response.getWriter().write(gson.toJson(response1));
        }
        else{
            response.getWriter().write(gson.toJson(response1));
        }
    }
        output.flush();
        output.close();
    }
}

protected Response sendPost2(Request request){
    Response response = null;
    String str = gson.toJson(request);
    HttpURLConnection conn = null;
    try{
        conn= (HttpURLConnection) url2.openConnection();           
        conn.setDoOutput( true );
        conn.setInstanceFollowRedirects( false );
        conn.setRequestMethod( "POST" );
        conn.setRequestProperty( "Content-Type", "application/json");
        conn.setRequestProperty("Connection", "keep-alive");
        conn.setRequestProperty( "Content-Length", Integer.toString(str.length()));

        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(str);
        wr.flush();
        wr.close();

        int responseCode = conn.getResponseCode();

        if(responseCode != 200){
            return null;
        }

        Reader reader = new InputStreamReader(conn.getInputStream());
        response = gson.fromJson(reader, Response.class);
        conn.disconnect();
    }catch(Exception e){
        e.printStackTrace();
        conn.disconnect();
    }

    return response;
}

protected Response sendPost1(Request request){
    Response response = null;
    String str = gson.toJson(request);
    HttpURLConnection conn = null;
    try{
        conn= (HttpURLConnection) url1.openConnection();           
        conn.setDoOutput( true );
        conn.setInstanceFollowRedirects( false );
        conn.setRequestMethod( "POST" );
        conn.setRequestProperty( "Content-Type", "application/json");
        conn.setRequestProperty("Connection", "keep-alive");
        conn.setRequestProperty( "Content-Length", Integer.toString(str.length()));

        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(str);
        wr.flush();
        wr.close();

        int responseCode = conn.getResponseCode();

        if(responseCode != 200){
            return null;
        }

        Reader reader = new InputStreamReader(conn.getInputStream());
        response = gson.fromJson(reader, Response.class);
        conn.disconnect();

    }catch(Exception e){
        e.printStackTrace();
        conn.disconnect();
    }

    return response;
}

}

Nik
  • 3
  • 3

1 Answers1

0

I am looking for some ways to send 2 post requests at same time and wait for the 80ms for the response, if no response then consider response as null.

You can certainly submit both as Callable<Response> jobs to a fixed or cached thread pool and then wait for them to complete. Something like:

final ExecutorService threadPool = Executors.newCachedThreadPool(NUM_THREADS);
...
Future<Response> future1 = threadPool.submit(new Callable<>() { ... });
Future<Response> future2 = threadPool.submit(new Callable<>() { ... });
// once you have submitted the last job you can shutdown the pool
threadPool.shutdown();

long start = System.currentTimeMillis();
try {
   response1 = future1.get(80, TimeUnit.SECONDS);
} catch (ExecutionException ee) {
   // job threw exception
} catch (InterruptedExeception ie) {
   // this (main?) thread was interrupted, good pattern to re-interupt
   Thread.currentThread().interrupt();
} catch (TimeoutException te) {
   // wait timed out, maybe this is right?
   response1 = null;
   // try to interrupt the thread
   future1.cancel(true);
}

// wait for 80 seconds minus how long we've been waiting for 2nd request
long wait = System.currentTimeMillis() - start - 80000;
if (wait < 0) {
   wait = 0;
}
try {
   response2 = future2.get(wait, TimeUnit.MILLISECONDS);
} catch (ExecutionException ee) {
   // job threw exception
} catch (InterruptedExeception ie) {
   // this (main?) thread was interrupted, good pattern to re-interrupt
   Thread.currentThread().interrupt();
} catch (TimeoutException te) {
   // wait timed out, maybe this is right?
   response2 = null;
   // try to interrupt the thread
   future2.cancel(true);
}

This will work fine but the trick is going to be interrupting the 2 requests. Just interrupting the thread doesn't kill any network sockets or database connections. You'll have to ensure that the job can test for interrupt status on its own otherwise you might leak threads.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • I tried your solution. My system has POST requests coming in at rate of 1500/second. and, I forward each request to 2 servers with 80ms timeout for both requests to response, as mentioned in above question. While I was looking at server, for first few requests, total processing time was between 2ms to 10ms but after few minutes, my processing time went up to 200ms to 500ms. What could be the reason? – Nik Jun 16 '17 at 02:27