Search code examples
javamultithreadingjersey-client

JerseyClient async calls seems to leave hanging threads


I'm using jersey-client-3.0-SNAPSHOT.

I do something like:

 final Client client = createClient();

...

    Builder builder = target.request();
    for (final Entry<String, String> entry : getHeaders().entrySet()) {
        builder = builder.header(entry.getKey(), entry.getValue());
    }
    final Builder finalBuilder = builder;
    executor.submit(() -> {
        final Entity<?> entity = createPostEntity();
        futureResponse = finalBuilder.async().post(entity);
        try {
            response = futureResponse.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
            consumeResponse(response);
        } catch (ExecutionException | TimeoutException | InterruptedException | IOException e) {
            errorConsumer.accept(e);
        }
    });

    if (futureResponse != null) {
        try {
            futureResponse.cancel(true);
        } catch (final Exception e) {
            //does nothing, now we try keep closing resources
        }
    }
    if (response != null) {
        try {
            response.close();
        } catch (final Exception e) {
            //does nothing, now we try keep closing resources
        }
    }

... //wait for responses and read or whatever

client.close();

And a new thread keeps appearing each time a create and destroy one of those clients.

Is there a safe way on destroying those threads? Is this an expected behaviour? Am a doing anything wrong?


Solution

  • In asynchronous calls in Jersey client, whenever we call close() on client object, it destroys the thread used in async calling. So, it is expected behavior that whenever client.close() statement will get executed, it will destroy the thread and next time, a new thread will get created for next async call.

    Now, one of the safe way to close client object and associated thread considering error scenario is below -

        Client client = ClientBuilder.newClient();
    
        WebTarget webTarget = client.target(SERVER_URL).path(API_PATH);
    
        Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
        // set headers and other stuff
    
        AsyncInvoker asyncInvoker = invocationBuilder.async();
    
        asyncInvoker.get(new InvocationCallback<Response>() {
    
            @Override
            public void completed(Response response) {
                if (response.getStatusInfo().equals(Status.OK)) {
                   // parse the response in success scenario
                } else {
                   // parse the response if error response is received from server
                }
                client.close();
            }
    
            @Override
            public void failed(Throwable throwable) {
                System.out.println("An error occurred while calling API");
                throwable.printStackTrace();
                client.close();
            }
        });