Search code examples
javamultithreadingjax-rsjersey-2.0jersey-client

Correct handling of background calls in jersey


I have to do some background calls to a web service within a web application. The response of the call is not really time-critical and barely interesting for me. It changes only in rare cases, where I will react to it by throwing a exception, or logging the failure or something. My conrete question now refers to the correct handling of such asynch calls in Jersey Client 2.

Option 1 uses the async calls from jersey, but then starts a thread for each response. Option 2 would immediatly start a thread and use jersey from inside this thread.

Generally which option would be more adviseable?

Option 1

private static final  ExecutorService executorService = Executors.newFixedThreadPool(20);

--

Client client = ClientBuilder.newClient();
WebTarget target = client.target("somehost").path("somepath");

final AsyncInvoker asyncInvoker = target.request().async();

final Future<Response> responseFuture = asyncInvoker.post(Entity.json(myjsonobject));
executorService.execute(new Worker(responseFuture));

-- Worker Thread

  public class Worker implements Runnable {

     private Future<Response> futureResponse;

     public Worker(Future<Response> futureResponse){
         this.futureResponse = futureResponse;
     }

     @Override
     public void run() {
         try {
          final Response response = futureResponse.get();
          if(response.getStatus() == 500)
             doSomething();
         } catch(Exception e) {
             e.printStackTrace();
         }
      }
 }

Option 2

private static final  ExecutorService executorService = Executors.newFixedThreadPool(20);

--

   executorService.execute(new Worker());

-- Worker Thread

  public class Worker implements Runnable {

     public Worker(){
     }

     @Override
     public void run() {
         try {
             Client client = ClientBuilder.newClient();
             WebTarget target = client.target("somehost").path("somepath");
             ClientResponse response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.json(myjsonobject), ClientResponse.class);
             if(response.getStatus() == 500) {
                  doSomething();
             }
          } catch(Exception e) {
                  e.printStackTrace();
          }
     }
 }

Solution

  • Instead of trying to implement a "non-blocking" Future.get() (with another thread), you can simply make use of the InvocationCallback, passing an instance to the get method. For example

    Future<Response> future = target.request().async().get(new InvocationCallback<Response>(){
        @Override
        public void completed(Response response) {
            System.out.println(response.readEntity(String.class));
            response.close();
            client.close();
        }
    
        @Override
        public void failed(Throwable throwable) { /** Log exception **/ }
    });
    

    See more at Asynchronous Client Callbacks