I have a situation that seems to fit the Async Servlet 3.0 / Comet situation but all I need to do is return a 200 response code (or other) after accepting the incoming parameters.
Is there a way for a HttpServlet to complete the http request/response handshake and yet continue processing?
Something like...
doPost( req, response ) {
// verify input params...
response.setStatus( SC_OK );
response.close();
// execute long query
}
EDIT: Looking at the javax.servlet package - the proper phrasing to my question is
How do I commit a response?
as in Servlet.isCommitted()
Here's how I've handled this situation:
When the app starts up, create an ExecutorService with Executors.newFixedThreadPool(numThreads) (there are other types of executors, but I suggest starting with this one)
In doPost(), create an instance of Runnable which will perform the desired processing - your task - and submit it to the ExecutorService like so: executor.execute(task)
Finally, you should return the HTTP Status 202 Accepted, and, if possible, a Location header indicating where a client will be able to check up on the status of the processing.
I highly recommend you read Java Concurrency in Practice, it's a fantastic and very practical book.
On possibility for your servlet to accept a request for processing in the background, is for the servlet to hand off processing to a separate thread which then executes in the background.
Using Spring, you can invoke a separate Thread using the a TaskExecutor. The advantage of using spring over standard JDK 5 java.util.concurrent.Executor is that if you're on application servers that need to use managed threads (IBM websphere or Oracle weblogic), you can use the WorkManagerTaskExecutor to hook into the CommonJ work managers.
Another alternative would be to move the long query logic into a Message Driven Bean or Message Driven POJO (Spring JMS can help here) and let the servlet simply post a message on a JMS queue. That would have the advantage that should the load on your web container become too great because of your long running query, you could easily move the MDB onto a different (dedicated) system.
You can continue processing in a separate Thread.
The response is commited once you return from doPost() method.
This example can help
void doPost(){
// do something
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
// processing after response
}
});}
Related
I am currently on a Project that builds Microservices, and are trying to move from the more traditional Spring Boot RestClient to Reactive Stack using Netty and WebClient as the HTTP Client in order to connect to backend systems.
This is going well for backends with REST APIs, however I'm still having some difficulties implementing WebClient to services that connect to SOAP backends and Oracle databases, which still uses traditional JDBC.
I managed to find some workaround online regarding JDBC calls that make use of parallel schedulers to publish the result of the blocking JDBC call:
//the method that is called by #Service
#Override
public Mono<TransactionManagerModel> checkTransaction(String transactionId, String channel, String msisdn) {
return asyncCallable(() -> checkTransactionDB(transactionId, channel, msisdn))
.onErrorResume(error -> Mono.error(error));
}
...
//the actual JDBC call
private TransactionManagerModel checkTransactionDB(String transactionId, String channel, String msisdn) {
...
List<TransactionManagerModel> result =
jdbcTemplate.query(CHECK_TRANSACTION, paramMap, new BeanPropertyRowMapper<>(TransactionManagerModel.class));
...
}
//Generic async callable
private <T> Mono<T> asyncCallable(Callable<T> callable) {
return Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(transactionManagerJdbcScheduler);
}
and I think this works quite well.
While for SOAP calls, what I did was encapsulating the SOAP call in a Mono while the SOAP call itself is using a CloseableHttpClient which is obviously a blocking HTTP Client.
//The method that is being 'reactive'
public Mono<OfferRs> addOffer(String transactionId, String channel, String serviceId, OfferRq request) {
...
OfferRs result = adapter.addOffer(transactionId, channel, generateRequest(request));
...
}
//The SOAP adapter that uses blocking HTTP Client
public OfferRs addOffer(String transactionId, String channel, JAXBElement<OfferRq> request) {
...
response = (OfferRs) getWebServiceTemplate().marshalSendAndReceive(url, request, webServiceMessage -> {
try {
SoapHeader soapHeader = ((SoapMessage) webServiceMessage).getSoapHeader();
ObjectFactory headerFactory = new ObjectFactory();
AuthenticationHeader authHeader = headerFactory.createAuthenticationHeader();
authHeader.setUserName(username);
authHeader.setPassWord(password);
JAXBContext headerContext = JAXBContext.newInstance(AuthenticationHeader.class);
Marshaller marshaller = headerContext.createMarshaller();
marshaller.marshal(authHeader, soapHeader.getResult());
} catch (Exception ex) {
log.error("Failed to marshall SOAP Header!", ex);
}
});
return response;
...
}
My question is: Does this implementation for SOAP calls "reactive" enough that I won't have to worry about some calls being blocked in some part of the microservice? I have already implemented reactive stack - calling a block() explicitly will throw an exception as it's not permitted if using Netty.
Or should I adapt the use of parallel Schedulers in SOAP calls as well?
After some discussions i'll write an answer.
Reactor documentation states that you should place blocking calls on their own schedulers. Thats basically to keep the non-blocking part of reactor going, and if something comes in that blocks, then reactor will fallback to traditional servlet behaviour which means assigning one thread to each request.
Reactor has very good documentation about schedulers their types etc.
But short:
onSubscribe
When someone subscribes, reactor will go into something called the assembly phase which means it will basically from the subscribe point start calling the operators backwards upstream until it finds a producer of data (for example a database, or another service etc). If it finds a onSubscribe-operator somewhere during this phase it will place this entire chain on its own defined Scheduler. So one good thing to know is that placement of the onSubscribe does not really matter, as long as it is found during the assembly phase the entire chain will be affected.
Example usage could be:
We have blocking calls to a database, slow calls using a blocking rest client, reading a file from the system in a blocking manor etc.
onPublish
if you have onPublish somewhere in the chain during the assembly phase the chain will know that where it is placed the chain will switch from the default scheduler to the designated scheduler at that specific point. So onPublish placement DOES matter. As it will switch at where it is placed. This operator is more to control that you want to place something on a specific scheduler at specific point in the code.
Examples usage could be:
You are doing some heavy blocking cpu calculations at a specific point, you could switch to a Scheduler.parallell() that will guarantee that all calculations will be placed on separate cores do do heavy cpu work, and when you are done you could switch back to the default scheduler.
Above example
Your soap calls should be placed on its own Scheduler if they are blocking and i think onSubscribe will be enough with a usage of a Schedulers.elasticBound() will be fine to get traditional servlet behaviour. If you feel like you are scared of having every blocking call on the same Scheduler, you could pass in the Scheduler in the asyncCallable function and split up calls to use different Schedulers.
How to implement one-way operation in Web Services (using Java or Spring annotations)?
I have tried to add one way as given below
#WebService
public interface DanduServices {
#Oneway
public void saveDanduInformation(#WebParam(name = "serv") ServDTO Serv, #WebParam(name = "dandu") DanduDTO danduDto);
but it is still request-response not asynchronus or one way.
Could anyone suggest to make a operation one-way in service endpoint and let other operations behave as per request-response?
You need to think in terms of the protocol as well though. In HTTP when you send a request you wait for a response, if no response comes back after an amount of time then you will receive a time-out error. So when you talk about one-way (you should rather say async request maybe) you really need to specify exactly what you mean. Do you want to have confirmation that your message was received i.e. have the server respond back with an OK status code and go off and complete it's task but you not wait for the task to be completed? Then you would need to spawn another thread. Spring has AOP for this the same way it has for transactions with #Transactional. Instead you annotated your method with #Async and return a Future<Something>. You'll also need #EnableAsync in your config. Refer to this article for an example Hot To Do #Async
If you don't even care about if the server received your request you don't want to use TCP/HTTP but instead UDP which is used in VOIP (phone over internet) for instance and is quicker, but it will depend on your client.
I am working on a project that works in two flavors with and without multi tenancy.
The project exposes a REST service which I would like to be asynchronous.
So my basic service looks like
#Component
#Path("/resouce")
#Consumes(MediaType.APPLICATION_JSON)
public class ResouceEndpoint {
#POST
#ManagedAsync
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
resouce.insert (event);
asyncResponse.resume( Response.status(Response.Status.NO_CONTENT).build());
}
}
That works fine without multi tenancy and I get the benefits of the internal Jersey executor service for free. See #ManagedAsync
When I switch to multi tenancy I add a filter on the request that resolve the tenant id and place it on the thread local (in our case the HTTP thread).
When the processing chain hits the "add()" method above the current thread is the one provided by the Jersey executor service, so it does not include my tenant id.
I could think only on the following options to work around this issue.
Extend the ResouceEndpoint to MutliTenantResouceEndpoint and drop the #ManagedAsync
Using my own thread executor
public class MutliTenantResouceEndpoint extends ResouceEndpoint {
#POST
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
final String tenantId = getTeantIdFromThreadLocal();
taskExecutor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
setTeantIdToThreadLocal(tenantId);
browserEventsAnalyzer.insertEvent(event);
Response response = Response.status(Response.Status.NO_CONTENT).build();
asyncResponse.resume(response);
return null;
}
});
}
}
But this way I need to manage my own thread executor and it feel's like I am missing something here.
Any suggestion on a different approach?
Here are a handful of recommendations, in order.
For context, I've been using Jersey for 2 years, and faced this exact problem 18 months ago.
1. Stop using #ManagedAsync
If you have control over the http server that Jersey is running on, I would recommend you stop using #ManagedAsync.
Instead of setting up Jersey to return it's http handling thread immediately and offload real request work to a managed executor service thread, use something like Grizzly for your http server, and configure it to have a larger worker thread pool. This accomplishes the same thing, but pushes the async responsibility down a layer, below Jersey.
You'll run into many pain points over the course of a year if you use #ManagedAsync for any medium-to-large project. Here are some of them off the top of my head:
If any ContainerRequestFilter's hits an external service (e.g. an auth filter hits your security module, which hits the database) you will lose the benefits you thought you were gaining
If your DB chokes and that auth filter call takes 5 seconds, Jersey hasn't offloaded work to the async thread yet, so your main thread needed to receive a new conn is blocked
If you set up logback's MDC in a filter, and you want that context throughout your request, you'll need to set up the MDC again on the managed async thread
Resource methods are cryptic to new comers and ugly to read because:
they need an extra parameter
they return void, hiding their real response type
they can "return" anywhere, without any actual return statements
Swagger or other API doc tools cannot automatically document async resource endpoints
Guice or other DI frameworks may have trouble dealing with certain scope bindings and/or providers in async resource endpoints
2. Use #Context and ContainerRequest properties
This would involve involved calling requestContext.setProperty("tenant_id", tenantId) in your filter, then calling calling requestContext.getProperty("tenant_id") in your resource with a #Context injected request.
3. Use HK2 AOP instead of Jersey filters
This would involve setting up an HK2 binding of InterceptionService which has a MethodInterceptor that checks for managed async resource methods and manually executes all RequestScoped bound ContainerRequestFilters. Instead of your filters being registered with Jersey, you'd register them with HK2, to be run by the method interceptor.
I can add more detail and code samples to options 2/3 if you'd like, or give additional suggestions, but it would first be helpful to see more of your filter code, and I again suggest option 1 if possible.
First of all I want to say that English is not my first language, so excuse me if I make some obvious mistakes or something is not clear enough. The question:
Recently I've been moved to a new project where we are developing a Java EE application that provides some REST services via Jersey+Hibernate. Prior to this I only had experience with Java SE, but there was someone experienced already laying the foundations so I had my time to learn from his code and using Google and SO a lot.
The thing is, among those REST services there is one that can take a lot of time to complete, and the team decided to implement it in a non-blocking way. We will define two services: with the first one the client sends the data to process, then we return an acknowledgement and start the processing while the client can continue with other things; and the second one allows the client to check later if their job is done.
While investigating how to implement this the best way possible, my aforementioned colleague discovered the AsyncServlet feature of Servlets 3.0, and had a proof of concept implemented before I arrived, which later he evolved into a locally working (but very dirty) version of the service. He says he had to drop Jersey for this, since Servlets 3.0 weren't compatible with the version of Jersey we work with, and finally decided to implemented a plain servlet.
At the end, he got something like this (I don't have the code right now since I'm at home and writing by memory, but I'll try to write it as clear as possible and try to fix any big mistakes tomorrow morning):
A servlet which handles the new requests in doPost() and the checking in doGet():
#WebServlet(asyncSupported = true)
//...
void doGet(HttpServletRequest req, HttpServletResponse res) {
/*
* ...
* We query the previous "job request" here in the DB
* ...
*/
}
void doPost(HttpServletRequest req, HttpServletResponse res) {
/*
* ...
* We convert the JSON request to an entity and then start the asynchronous
* "worker" thread
* ...
*/
AsyncContext ctx = req.startAsync(req, res);
ctx.start(new WorkerThread(ctx, someOtherDataFromRequest);
}
And a worker thread that implements Runnable and the first thing it does is to call ctx.complete() on the AsyncContext that was sent to him in the constructor. My colleague reasoning is, if the worker notifies the parent right away he has completed, the parent can commit the response back to the client and then start his own processing with the other data passed to him in the constructor:
public class WorkerThread implements Runnable {
public WorkerThread(AsyncContext ctx, SomeOtherData data){
//...
}
public void run() {
ctx.complete();
// ... Now start doing the heavy processing with data
}
}
Well, as I said this works on his local test server (Tomcat 7), but a few days ago I was asked to clean his code and when ran on my machine which has a JBoss EAP 6.1, I found that it doesn't work as expected, since the parent servlet does not commit the response until the worker dies (we have different servers because the production machines are new and the higher ups haven't decided which server to install yet and changed their minds a bunch of times, bureaucracy...)
I did a bunch of tries and I'm pretty sure I didn't remove any key element of the async processing while cleaning, as my version compiles and runs fine. At the end I got a test case where the worker just sleeps 10 seconds, then writes at the log; in Tomcat the response reaches the client almost instantly then at 10s the log is written; while in JBoss the client has to wait the full 10s to receive the response.
Then, I started investigating the AsyncServlet feature, and I think he got the idea the wrong way, this feature seems to be directed to asynchronous internal processing and not as we want to use it, but I can't understand why it does work on his Tomcat. From the javadocs of the complete() method I understand the JBoss behavior is the correct one:
If this method is called before the container-initiated dispatch that called startAsync has returned to the container, then the call will not take effect (and any invocations of AsyncListener#onComplete(AsyncEvent) will be delayed) until after the container-initiated dispatch has returned to the container.
So, my question is if the AsyncServlet features are intended for our use case, and, if not, if there are any other cleaner ways to get our desired behavior (bonus points if they are compatible with Jersey). I'm thinking on just spawning a thread and not using the asyncontext at all, but sounds quite risky...
Thanks and sorry for the wall of text
This response may be a little too late but have you looked at using AsyncResource which comes with Jersey 2.0
https://jersey.java.net/documentation/latest/async.html
Also, you said "the parent servlet does not commit the response until the worker dies". How did you prove this ? Perhaps you have different settings for your Tomcat Server and Jboss server (Different threadpool size / different number of connections ?)
Also, from your description it looks like you have everything you need in SomeOtherData. So you could use an ExecutorService instead , add a runnable on to it that just takes SomeOtherData in its constructor and immediately call complete on the context in the doPost itself rather than doing it in the worker.
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