For asynchronous programming, Jersey (JAX-RS) 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.
Sounds great, but I can never get this to fire.
Here's some code:
@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? Is ConnectionCallback implemented in Jersey? (It's optional in the JAX-RS spec, but the Jersey docs talk about it as though it's implemented.)
Any input would be appreciated.
ConnectionCallback is indeed implemented in Jersey. And 'onDisconnect' callback is also invoked. You can take a look at the following code in Jersey:
https://github.com/jersey/jersey/blob/a6ff4d50da13d45ad90fd7375a15a31afa02e489/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java#L723
https://github.com/jersey/jersey/blob/b7907e279010e7035a7a3e529993d22f77a21e08/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java#L246-L252
These are thrown in case of IOException while writing response. So, to answer your question, there is no polling or similar mechanism that keeps checking whether the client is connected, rather the onDisconnect method is called only when there is an IOException which usually occurs while writing response.
Update 1:
Also I would like to quote your own question:
"This callback will be executed only if the connection was prematurely terminated or lost while the response is being written to the back client"
So, unless you try to write to that stream, your callback will never be fired. To be clear, it's not meant to be called when there is no response to write or when the response is 202, rather it's meant to be invoked when the connection was terminated prematurely while response is being written.
I am afraid there is no workaround to this problem unless you write some low level network programming with polling of some sort. But I wouldn't recommend you to go for this.
I suggest that you rethink the way you want to handle this failure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With