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.
Related
TL;DR: I have a Windows service written in Java, jarred, and installed with Procrun. I am starting it with W32Service.startService(). When does the service tell Windows it has started?
I'm working with windows services written in Java. I've been jarring and using Procrun to install them, and JNA to work with them (in particular, com.sun.jna.platform.win32.W32Service).
I would like to understand in the exact behavior of the W32Service object's waitForNonPendingState() method (which is the X to my Y: understand the exact behavior of startService()).
waitForNonPendingState() is actually very straightforward: it polls the status of the service until it's either in a non-pending state or a timeout occurs. How a service transitions to a non-pending state isn't so straightforward though.
Microsoft's Service State Transitions page says:
The initial state of a service is SERVICE_STOPPED. When the SCM starts the service, it sets the service state to SERVICE_START_PENDING and calls the service's ServiceMain function. The service then completes its initialization using one of the techniques described in Service ServiceMain Function. After the service completes its initialization and is ready to start receiving control requests, the service calls SetServiceStatus to report SERVICE_RUNNING...
But that doesn't really shed any light on how the service does this. The ServiceMain remarks also just say "The Service Control Manager (SCM) waits until the service reports a status of SERVICE_RUNNING."; that's pretty much as specific as I can find.
Which brings me to my question: How does a java Windows service "know" it has finished initializing?
In other words, if I have an installed service with a main() method:
public class SampleService {
public static void main(String[] args) {
if ("start".equals(args[0]))
new SampleService();
}
public SampleService() {
// do a whole bunch of stuff
}
}
and I call:
W32Service service = serviceManager.openService("SampleService",
Winsvc.SC_MANAGER_ALL_ACCESS);
service.startService();
At what point does my SampleService tell Windows it has initialized? Through experimentation, I can see that if there's a runtime exception during construction, the service's status is never SERVICE_RUNNING, so there's something in that process which sets that status. But some of my constructors wait on queues or enter spin loops and they do set the SERVICE_RUNNING status, so I can't tell where this status is set. W32Service's documentation is less than useless on this.
Your service is not really exposed as regular service it relies on Procrun as soon as the JVM is spawned as part of the process or separately the service state is set to running. In prunsrv.c which has the service container code for procrun you can check how serviceStart() is called and what happens on success.
This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 6 years ago.
I have a Java application (running on WAS 8.5) which acts as a kind of server inventory for the client. The application has a servlet that triggers a long running process.
The process: fetches data from a third party DB, executes Java logic, writes records back to the application's own DB (these DB connections are pooled ones) .
The servlet is not load-on-startup and is manually triggered only once a month by a single Operations guy (on some particular date based on the client's choice each month). The servlet had been historically using Timer and TimerTask in this way:
public class SyncMissingServlet extends HttpServlet implements Servlet{
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
try{
SyncMissing.runSync();
}catch(Exception ex){
logger.error(new LogMessage("ERROR: "), ex);
this.sendReply(printWriter, "ERROR: " + ex.toString());
}
}
}
public class SyncMissing
{
public static void runSync() throws Exception
{
Timer t = new Timer(true);
SyncMissingTask task = new SyncMissingTask(); //SyncMissingTask is an instance of TimerTask
// Start the synchronization 5 secs from now, and run it every 30 days.
t.schedule(task, 5000, 2592000000l); //this 30 day timings never really worked out for the client,
//since the app server is restarted frequently for deployments.
}
}
There is no use of Timer.close() or TimerTask.close() in the current code.
Recently this Servlet seems to have got auto-trigerred, after a system reboot and restart of the WAS services on the system...and that's the worry.
While I couldn't explain the auto-trigger to my client, I proposed the following options:
1. drop off the use of Timer and TimerTask (the long-running process then runs on the servlet's thread itself)
2. instead of TimerTask, make it a regular Runnable and run it in a separate thread within the servlet thread.
3. make use of Java's Executor Service
4. migrate to Servlet 3.0 and turn the servlet into a Async servlet.
5. drop off the servlet altogether, and replace it with a batch job.
I understand that options 3 and 4 are really the recommended ones (or possibly option 5). But I have a feeling, that in my business scenario - Options 3 & 4 may be an overkill.
If the need is really a manual invocation of the servlet by only one user per month, are options 1 and 2 that bad?
(my client wants the quickest solution and would certainly not fund option 5)
Well, if the servlet is supposed to be run only once in a month and there is only one client triggering it, it is fine to run it in the servlet's thread itself or create a new thread inside the servlet and let that do the task. The question of load and response times arises when you have a lot of clients making simultaneous requests, at which point you might want to use an Executor service or an async servlet.
There is no need to activate a background task by invoking a servlet. Your web app has its own lifecycle. The Servlet spec provides hooks for your web app getting set-up and torn-down. Perfect place to launch and quit your background task without ever invoking a servlet by a client user.
No need to depend on a human user remembering to start the background task. Let your web app technology do the work for you.
Also, you may often hear/read "never launch threads from JSP or Servlet". This is worthy advice with regard to processing each incoming request for generating a web page. But background tasks (not directly related to a single servlet request) is a different animal; perfectly okay to have threads for background tasks as long as you handle them properly. By 'properly' I mean you explicitly end those threads appropriately, and you handle thread-safety issues. An example of a background task might be regularly polling a web service or database to refresh a cache of data.
ServletContextListener
If you want an automated task to be performed regularly within your web app, use a ServletContextListener.
That interface defines a pair of methods. One, contextInitialized, is called automatically when the web app launches, guaranteed to run before any HTTP requests are handled. The other method, contextDestroyed, runs when the web app is being torn down.
Tip: Marking your listener with a #WebListener annotation will cause your Servlet container to automatically notice it and instantiate when the web app is launched.
Beware of a nasty bug when doing development with NetBeans & Tomcat (development problem only, not a problem in deployment) where the web app does a double launch.
ScheduledExecutorService
In your custom class implementing that interface, in contextInitialized, establish a ScheduledExecutorService object to run your task repeatedly. In contextDestroyed, shutdown that executor. This is very important as the thread(s) of that executor will survive the shutdown of your web app and even the servlet container.
The ScheduledExecutorService technology supplants the Timer and TimerTask classes. These classes are especially not recommended for use in a Java Servlet environment.
You can store a reference to the executor in your listener object.
#WebListener
class MonthlyTaskRunner implements ServletContextListener {
private ScheduledExecutorService scheduledExecutorService;
void contextInitialized(ServletContextEvent see) {
// initialize your ScheduledExecutorService.
// The ScheduledExecutorService will use one or more threads for its work outside of this thread running now.
this.scheduledExecutorService = … ;
}
void contextInitialized(ServletContextEvent see) {
// Shutdown the executor along with its thread(s).
this.scheduledExecutorService.shutDown();
}
}
I and others have posted on this extensively here on Stack Overflow, such as this. So search Stack Overflow. I have posted extensive examples in the context of Vaadin web apps, but the principles apply to any servlet web app. And see the Oracle Tutorial on Executors.
Where to store a reference to your ScheduledExecutorService once instantiated? You could store in a member variable on your context listener. But a more accessible place would be as an "attribute" on the servlet context. I describe this in detail along with example code and a nifty diagram in my Answer to another Question: Start & Stop a ScheduledExecutorService in Java EE environment using servlet
YearMonth
In that executor task, get the year-month of the current date for the time zone of your business context. Compare that year-month to one recorded when the task was last performed. Record that year-month somewhere, in a file, in a database, someplace.
Schedule your ScheduledExecutorService to run more often than necessary. Rather than worry about scheduling out a month, just let it run everyday. The check to compare current YearMonth with stored year-month requires nearly no execution time. KISS.
Java includes a YearMonth class.
YearMonth ymThen = YearMonth.parse( "2016-11" ); // Retrieve that string from storage.
ZoneId z = ZoneId.of( "America/Montreal" );
YearMonth ymNow = YearMonth.now( z );
if( ymNow.isAfter( ymThen ) ) {
// … run the task
String ymOutput = ymNow.toString();
// … write that `ymOutput` string someplace in storage.
} // Else do nothing. Let the ScheduledExecutorService run again after its designated rest period.
Similar Questions
Background timer task in JSP/Servlet web application
How to run a background task in a servlet based web application?
UPDATE: I upgraded the code to Java 8 without too much of a hassle. So I would like answers tied to Spring 4/Java 8.
I am working on a task to fix performance issues (Tomcat max thread count of 200 reached at a request rate of just 400/s, request latencies building up periodically, etc) in a Tomcat/Spring 4.2.4/Java 8 web mvc application.
It is a typical web application which looks up Mysql via Hibernate for small but frequent things like user info per request, then does actual data POST/GET to another web service via RestTemplate.
The code is in Java 7 style as I just migrated to Java 8, but no new code has been written in that style yet. (I am also back using Spring after ages, so not sure what would be best).
As expected in a normal such application, the Service layer calls other services for info, and then also passes that along to a call to the DAO. So I have some dependent callbacks here.
Setup
#EnableAsync is set
The flow of our Http requests goes from Controller -> Service -> DAO -> REST or Hibernate
Sample flow
Say Controller receives POST request R and expects a DeferredResult
Controller calls entityXService.save()
EntityXService calls userService.findUser(id)
UserService calls UserDAO.findUser(id) which in turn talks to Hibernate
UserService returns a Spring ListenableFuture to the caller
EntityXService awaits the user info (using callback) in and calls EntityXDAO.save(user, R)
EntityXDAO calls AsyncRestTemplate.postForEntity(user, R)
EntityXDAO receives DeferredResult> which is our data abstraction for the response.
EntityXDAO processes the response and converts to EntityXDTO
Eventually somehow the DeferredResult is sent back through the same chain as a response.
I am getting lost at how in step 3, EntityXService asynchronously calls UserService.findUser(id) with an onSuccess callback to EntityXDAO.save(user, R). However, EntityXDAO.save(user, R) also now returns a DeferredResult from the AsyncRestTemplate.
Questions:
Is using DeferredResult a good way to get concurrency going in this application?
Is using Guava's ListenableFuture or Java 8 CompletableFuture going to help make it better in anyway, rather than using DeferredResult?
My BIGGEST question and confusion is how to arrange the DeferredResult from one service lookup to be used by another, and then finally set a DeferredResult of a completely different return type for the final response?
Is there an example of how to chain such callbacks and what is the recommended way to build such a flow? If this sounds completely wrong, is Java 7 going to be the right choice for this?
Thanks in advance!
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.
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
}
});}