users@jersey.java.net

[Jersey] cannot get AsyncResponse CompletionCallback to fire

From: Ric Bernat <ric_at_brinydeep.net>
Date: Sat, 08 Nov 2014 08:34:26 -0800

For asynchronous programming, Jersey provides a ConnectionCallback
callback that is to be executed when a connection is broken. From the
Jersey docs:

> As some async requests may take long time to process the client may
> decide to terminate its connection to the server before the response
> has been resumed or before it has been fully written to the client. To
> deal with these use cases a ConnectionCallback can be used. This
> callback will be executed only if the connection was prematurely
> terminated or lost while the response is being written to the back
> client. Note that this callback will not be invoked when a response is
> written successfully and the client connection is closed as expected.

https://jersey.java.net/documentation/latest/async.html#d0e8863

Sounds great, but I can never get this to fire.

I am running Jersey 2.13 on Tomcat 7.0.53. Clients are connecting
directly to Tomcat (no Apache).

Here is the web service:

     @GET
     @Produces(MediaType.TEXT_PLAIN)
     @ManagedAsync
     @Path("/poll")
     public void poll(@Suspended final AsyncResponse asyncResponse) {
         asyncResponse.register(new CompletionCallback() {
             @Override
             public void onComplete(Throwable throwable) {
                 logger.info("onComplete called.");
             }
         });

         asyncResponse.register(new ConnectionCallback() {
             @Override
             public void onDisconnect(AsyncResponse disconnected) {
                 logger.info("onDisconnect called.");
             }
         });

         asyncResponse.setTimeout(POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS);
         asyncResponse.setTimeoutHandler(new TimeoutHandler() {
             @Override
             public void handleTimeout(AsyncResponse asyncResponse) {
                 logger.info("handleTimeout called.");
asyncResponse.resume(Response.status(Response.Status.OK).entity("TIMEOUT").build());
             }
         });
     }

The other two callbacks shown, CompletionCallback and TimeoutHandler,
fire just fine, without fail. If the specified timeout duration is
reached, TimeoutHandler fires. If an AsyncResponse instance is resumed,
CompletionCallback fires.

However, with ConnectionCallback, I can close, kill, or otherwise stop
the client that is sitting connected to the web service shown above, and
ConnectionCallback never gets fired.

Am I missing something?

Any input would be appreciated.