AsyncResponse ConnectionCallback does not fire in Jersey - java

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.

Related

How to invoke async controller logic after returning response using Spring?

I need to process request asynchronously in time - after receiving request I must return a response with status 200 to confirm that the request have reached it's goal, and then proceed with some magic to happen in service. I tried few ways to reach it, but every time response was sent after logic part ended in some other thread.
Is there a way to reach it using Spring? Or should I rather think about other approach to this problem?
The Spring Framework provides abstractions for asynchronous execution and scheduling of tasks
You can look at this => http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
You need to use deferredResult http://docs.spring.io/spring-framework/docs/3.2.0.BUILD-SNAPSHOT/api/org/springframework/web/context/request/async/DeferredResult.html
You will create a deferredResult object and you will return to the client. then asynchronously you will execute the logic and as soon as you finish you will inform the client that the request it´s done.
This technique is also know as "http long polling"
#RequestMapping("/")
#ResponseBody
public DeferredResult<String> square() throws JMSException {
final DeferredResult<String> deferredResult = new DeferredResult<>();
runInOtherThread(deferredResult);
return deferredResult;
}
private void runInOtherThread(DeferredResult<String> deferredResult) {
//seconds later in other thread...
deferredResult.setResult("HTTP response is: 42");
}

Request right after Response?

I am a bit lost with the following scenario:
My webservice consumes POST requests with form data. I have to reply with 200 OK or otherwise the senders thinks the request failed.
Immediately after answering with 200 I would like to proceed to call another webservice on a remote host with some of the data I have just received.
My webservice consumes the POST request with the #GET annotation. That works I can read all the form data. To call the other webservice I used the Jersey Client API. That works fine too.
I just can't figure out how to switch from switching from one call to another. Everything is programmed with Jersey 2 and deployed in Tomcat, so no real Application Server. There is no full Java EE stack available.
Am I missing some middleware? Do I need to implement a custom event-loop or some message broker?
Not sure if there's any "standard" way to handle this, but there's a CompletionCallback we can register with an AyncResponse.
CompletionCallback:
A request processing callback that receives request processing completion events.
A completion callback is invoked when the whole request processing is over, i.e. once a response for the request has been processed and sent back to the client or in when an unmapped exception or error is being propagated to the container.
The AsyncResponse is meant to handle requests asynchronously , but we can immediately call resume to treat it like it was synchronous. A simple example would be something like
#Path("/callback")
public class AsyncCallback {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void postWithAsync(#Suspended AsyncResponse asyncResponse,
SomeObject object) {
asyncResponse.register(new CompletionCallback() {
#Override
public void onComplete(Throwable error) {
if (error == null) {
System.out.println("Processing new Request");
} else {
System.out.println("Exception in Request handling");
}
}
});
Response response = Response.ok("Success").build();
// Carry on like nothing happened
asyncResponse.resume(response);
}
}
You can see more explanation at Asynchronous Server-side Callbacks

How to implement AsyncListener/ReadListener/WriteListener.onError in an async servlet?

The Servlet 3.1 API defines an asynchronous servlet API which goes down to implementing the interfaces AsyncListener, WriteListener and ReadListener. All these have an onError callback, but I cannot find any useful information about the error conditions and expected behavior for this callback.
In an example the author completes the AsyncContext in the onError callbacks:
public void onError(final Throwable t) {
ac.complete();
t.printStackTrace();
}
Is there any best practice on what the async servlet should do in case of an error?
Interestingly, the onError handlers are not called if the HTTP request is aborted by the client (tested with Jetty 9.1.3). However, in that case, there seems to be a memory leak here, since the WriteListener seems not to be cleaned up. Only the ReadListener and AsyncListener instances see a finalize() call when System.gc() is called (for testing).

camel: how can i send to an endpoint asynchronously

How can I send a message to an endpoint without waiting for that endpoint's route to be process (that is, my route should just dispatch the message and finish)?
Using wireTap or multicast is what you're after. A direct: endpoint will modify the Exchange for the next step no matter what ExchangePattern is specified. You can see by using this failing test:
public class StackOverflowTest extends CamelTestSupport {
private static final String DIRECT_INPUT = "direct:input";
private static final String DIRECT_NO_RETURN = "direct:no.return";
private static final String MOCK_OUTPUT = "mock:output";
private static final String FIRST_STRING = "FIRST";
private static final String SECOND_STRING = "SECOND";
#NotNull
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(DIRECT_INPUT)
.to(ExchangePattern.InOnly, DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
from(DIRECT_NO_RETURN)
.bean(new CreateNewString())
.end();
}
};
}
#Test
public void testShouldNotModifyMessage() throws JsonProcessingException, InterruptedException {
final MockEndpoint myMockEndpoint = getMockEndpoint(MOCK_OUTPUT);
myMockEndpoint.expectedBodiesReceived(FIRST_STRING);
template.sendBody(DIRECT_INPUT, FIRST_STRING);
assertMockEndpointsSatisfied();
}
public static class CreateNewString {
#NotNull
public String handle(#NotNull Object anObject) {
return SECOND_STRING;
}
}
}
Now if you change the above to a wireTap:
from(DIRECT_INPUT)
.wireTap(DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
and you'll see it works as expected. You can also use multicast:
from(DIRECT_INPUT)
.multicast()
.to(DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
wireTap(endpoint) is the answer.
you can use a ProducerTemplate's asyncSend() method to send an InOnly message to an endpoint...
template.asyncSend("direct:myInOnlyEndpoint","myMessage");
see http://camel.apache.org/async.html for some more details
That might depend on what endpoints etc you are using, but one common method is to put a seda endpoint in between is one option.
from("foo:bar")
.bean(processingBean)
.to("seda:asyncProcess") // Async send
.bean(moreProcessingBean)
from("seda:asyncProcess")
.to("final:endpoint"); // could be some syncrhonous endpoint that takes time to send to. http://server/heavyProcessingService or what not.
The seda endpoint behaves like a queue, first in - first out. If you dispatch several events to a seda endpoint faster than the route can finish processing them, they will stack up and wait for processing, which is a nice behaviour.
You can use inOnly in your route to only send your message to an endpoint without waiting for a response. For more details see the request reply documentation or the event message documentation
from("direct:testInOnly").inOnly("mock:result");
https://people.apache.org/~dkulp/camel/async.html
Both for InOnly and InOut you can send sync or async. Seems strange that you can send InOnly but async, but at last here it explains that it waits for Camel processing and then fire and forget.
The Async Client API
Camel provides the Async Client API in the ProducerTemplate where we have added about 10 new methods to Camel 2.0. We have listed the most important in the table below:
Method
Returns
Description
setExecutorService
void
Is used to set the Java ExecutorService. Camel will by default provide a ScheduledExecutorService with 5 thread in the pool.
asyncSend
Future
Is used to send an async exchange to a Camel Endpoint. Camel will imeddiately return control to the caller thread after the task has been submitted to the executor service. This allows you to do other work while Camel processes the exchange in the other async thread.
asyncSendBody
Future
As above but for sending body only. This is a request only messaging style so no reply is expected. Uses the InOnly exchange pattern.
asyncRequestBody
Future
As above but for sending body only. This is a Request Reply messaging style so a reply is expected. Uses the InOut exchange pattern.
extractFutureBody
T
Is used to get the result from the asynchronous thread using the Java Concurrency Future handle.
The Async Client API with callbacks
In addition to the Client API from above Camel provides a variation that uses callbacks when the message Exchange is done.
Method
Returns
Description
asyncCallback
Future
In addition a callback is passed in as a parameter using the org.apache.camel.spi.Synchronization Callback. The callback is invoked when the message exchange is done.
asyncCallbackSendBody
Future
As above but for sending body only. This is a request only messaging style so no reply is expected. Uses the InOnly exchange pattern.
asyncCallbackRequestBody
Future
As above but for sending body only. This is a Request Reply messaging style so a reply is expected. Uses the InOut exchange pattern.
These methods also returns the Future handle in case you need them. The difference is that they invokes the callback as well when the Exchange is done being routed.
The Future API
The java.util.concurrent.Future API have among others the following methods:
Method
Returns
Description
isDone
boolean
Returns a boolean whether the task is done or not. Will even return true if the tasks failed due to an exception thrown.
get()
Object
Gets the response of the task. In case of an exception was thrown the java.util.concurrent.ExecutionException is thrown with the caused exception.

Waiting for an asynchronous call to complete first and then proceed in Java

I have a situation wherein I call a method which in turn triggers a asynchronous HTTP REST call(sends the status later to another endpoint) before it proceeds further. I want the method to wait until i get the response back to the endpoint, check the status i got and proceed further. I am looking for a feasible solution in Java. Any pseudo code or implementation will be helpful
saw similar case # Lightweight way of waiting for a group of asynchronous Java calls but not much idea about the same whether it is easy to implement.
Implementation details
I have JAX-RS endpoint to handle the async response as below
#POST
#Path("/status")
#Consumes("application/xml")
public Response processConfigStatus(#Context UriInfo uriInfo, ConfigStatus configStatus)
{
// process Status got from the async REST call
return ResponseHelper.createNoContentResponse();
}
Class which handles and processes
Class ProcessData{
public void updateData()
checktStatus(uri);
update();// should wait untill the processConfigStatus() endpoint gives status
}
private checktStatus(String uri){
// makes a REST call to a URI using a JAX-RS webclient or a httpclient this returns HTTP 200 or 204 code immediatley. And then the Server process the request asynchronously and gives back the status to JAX-RS endpoint(/status).
post(uri);
}
}
Method call from another Class
ProcessData pd = new ProcessData()
pd.updateData();
How about using a CountDownLatch?
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
Just as in the link you provided, you'll have to implement a way to simply keep track of how many async calls are stilling waiting for a response and wait until that count is zero.
count = numAsyncCalls
..calling all of the RESTful services here (each call must have some sort of callback to decrement 'count' variable above..
while (count > 0)
wait around
The use of the CountDownLatch in your link looks pretty much the same as my pseudo-code

Categories