I'm trying to shutdown my application gracefully.So when the application shutdown is triggered, I need to make the shutdown process wait for configured number of seconds, during this time I would still service few requests.
I have been trying to use wait/sleep in the destroy() method, but the context is already destroyed at this point. My understanding is that destroy() would be called by the container. Is it possible to control the destroy method and delay the start of the shutdown process?
Thanks.
Your given approach will not work.The reason is destroy() method. Every servlet will has their own destroy() method.These method is called when the servlet are being unloaded by the container, not when your application is being shutdown.The servlets can be unload when the container will has no use of a servlet.You can have your application running and still your servlet may get unloaded by the container because the container may hav edecided that these servlet are not needed.
Solution: What you may need is a ServletContextListener. ServletContext is associated with your whole application,not just with a single servlet. When your applicaion is being loaded,the contextInitialized() of ServletContextListener is invoked and when your application is being unloaded, contextDestroyed() is invoked.So in contextDestroyed(),you can sleep the threa and perform other task.
#WebListener
public class MyContextListener implements ServletContextListener
{
public void contextInitialized(ServletContextEvent event)
{
System.out.println("\n \n \n \n ServletContext is being initialized..... \n \n \n");
}
//Perform cleanups like removing DB connection.closing session etc. while closing appliction
public void contextDestroyed(ServletContextEvent event)
{
try{
//Sleep this thread.
Thread.sleep(10000);
} catch(Exception ex){ ex.printStackTrace(System.err); }
}
}
Related
I've a spring web app running in a Tomcat server. In this there is a piece of code,in one of the Spring beans, which waits for a database connection to become available. My scenario is that while waiting for a database connection, if the Tomcat is shutdown, I should stop waiting for a DB connection and break the loop.
private Connection prepareDBConnectionForBootStrapping() {
Connection connection = null;
while (connection == null && !Thread.currentThread().isInterrupted()) {
try {
connection = getConnection();
break;
} catch (MetadataServerException me) {
try {
if (!Thread.currentThread().isInterrupted()) {
Thread.sleep(TimeUnit.MINUTES.toMillis(1));
} else {
break;
}
} catch (InterruptedException ie) {
logger.error("Thread {} got interrupted while wating for the database to become available.",
Thread.currentThread().getName());
break;
}
}
}
return connection;
}
The above piece of code is executed by one of the Tomcat's thread and it's not getting interrupted when shutdown is invoked. I also tried to achieve my scenario by using spring-bean's destroy method, but to my surprise the destroy method was never called. My assumption is that Spring application context is not getting fully constructed - since, I've the above waiting loop in the Spring bean - and when shutdown is invoked corresponding context close is not getting invoked.
Any suggestions?
Tomcat defines a life-cycle for Web applications (well, it's a kind of common specification aspect and not just tomcat specific, but anyway...)
So there is a way to hook into this process and terminate the loop or whatever.
In spring its very easy, because if tomcat shuts down gracefully, tomcat attempts to "undeploy" the WAR before actually exiting the process. In servlet specification in order to do that, a special web listener can be defined and invoked (you can see javax.servlet.ServletContextListener API for more information)
Now spring actually implements such a listener and once invoked, it just closes the application context.
Once this happens, your #PreDestroy methods will be called automatically. This is already a spring stuff, tomcat has nothing to do with that.
So bottom line, specify #PreDestroy method on your bean that would set some flag or something and it would close the logic that attempts to close the connection.
Of course all the stated above doesn't really work if you just kill -9 <tomcat's pid> But in this case the whole jvm stops so the bean is irrelevant.
Is it necessary to shutdown an ExecutorService at some point if it runs in a Tomcat container for a Servlet. If yes, then where should I call the shutdown? I tried adding it after the submit() call but when I fire another request to the Servlet from a client browser, I get a RejectedExecutionException which is probably because I did a shutdown? I am trying to understand how it works in a Servlet within Tomcat and how I should use it.
I am doing the following in my webApplication (which seems to work fine without any shutdown):
// In configuration class
#Bean (name = "executorService")
public ExecutorService executorService() {
return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
}
// In some other class
#Qualifier("executorService")
#Autowired
private ExecutorService executorService;
....
private void load() {
executorService.submit(new Runnable() {
#Override
public void run() {
doSomethingInTheBackground();
}
});
// If I enable this I will get a RejectedExecutionException
// for a next request.
// executorService.shutdown();
}
The idea behind the ExecutorService is to reuse threads. Creating threads is expensive and usually it is more efficient to create a thread once and then use that same thread multiple times. This is exactly what an ExecutorService does: it manages a pool of (possibly idle) threads and assigns work to them when you call its submit methods.
In a typical application you therefore do not want to shutdown the ExecutorService. You should however shut the ExecutorService down properly if your application is terminated. Since you are using Spring you don't have to worry about that:
By default, beans defined using Java config that have a public close or shutdown method are automatically enlisted with a destruction callback. [See the documentation.]
That means, if you close the ApplicationContext, Spring will automatically shutdown the ExecutorService for you.
I am trying to detect an application stop event (in Websphere 8.0) to invoke a servlet's static method. I wonder if there's a straightforward way to find out if the application has been ordered to stop.
This is the scenario:
I have one servlet, WorkerServlet, running a loop like this
while(!forceStop){...} in its doGet(). While the application is
up, this loop is continuously running.
When the container stops the
application (because of any event such as republish, stop, restart
the application/server) I would like to invoke the static method WorkerServlet.forceStop(){forceStop = true;}.
This way, WorkerServlet's loop would finish and the servlet could be destroyed by the container right away. The current behaviour is that the container waits for 60 seconds before forcing the destroy which is unacceptable during development time.
I have tried different approaches but none of them works
A ServletContextListener.contextDestroyed(). Not called until all servlets are destroyed
A Spring ApplicationListener to detect when de application context is going to be destroyed. Not called until all servlets are destroyed.
Another servlet with a destroy() method that invokes WorkerServlet.forceStop(). The container doesn't destroy() this servlet since there's another one running a request.
So, is there any other way to detect the container's app shutdown event so that I can invoke that static method?
The only workaround I found was to use a startup bean. Fortunately Webshpere's EJB container is stopped before the servlet container:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Singleton
#Startup
public class WorkerServletStopper {
#PreDestroy
public void preDestroy(){
WorkerServlet.forceStop();
}
}
I have a Servlet app which spawns worker threads in the init() method. These workers continually do transactional jobs i.e. it's important that each job, if started, is completed or else not started.
I hoped that I could use the destroy() method to stop these worker Threads in a graceful way, i.e. making sure they were finished with whatever last/current job before ending the destroy() method and terminating the Servlet.
The destroy() is triggered when a Chef scripts executes service tomcat7 stop
But from my logs/tests, the destroy() method on my Servlet does not block/complete. It is triggered, but then after a few moments, tomcat shuts down and I don't receive confirmation that the Threads stopped in a graceful way.
public void destroy() {
log.info("Signaling worker to stop current job/not begin another.");
this.worker.stop();
while(this.worker.isProcessingJob()) {
Thread.sleep(3 * 1000);
}
log.info("Worker successfully stopped");
log.info("destroy() complete");
super.destroy();
}
In many cases I don't see the last two logs, i.e. Tomcat goes down when my code is in while-loop waiting for this.worker to complete it's current job.
Is this expected behavior? Is there some way to tell tomcat to stop, but also allow my Servlet's destroy() method to block/complete?
This is a follow up to my earlier question.
Tomcat 5.0.28 had a bug where the Servlet's destroy() method was not being invoked by the container on a shutdown. This is fixed in Tomcat 5.0.30, but if the Servlet's destroy() method had a System.exit(), it would result in the Tomcat windows service throwing the Error 1053 and refusing to shutdown gracefully (see above link for more details on this error)
Anybody has any idea on whether:
Calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads is a good idea?
Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet.
Calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads is a good idea?
It is absolutely not a good idea - it is a horrible idea. The destroy() method is called when the servlet is taken out of service, which can happen for any number of reasons: the servlet/webapp has been stopped, the webapp is being undeployed, the webapp is being restarted etc.
System.exit() shuts down the entire JVM! Why would you want to forcibly shutdown the entire server simply because one servlet is being unloaded?
Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet.
Probably to prevent such dangerous behavior like this.
You shouldn't write code that assumes that your code/application is the only thing running on the server.
You're asking two questions:
Question 1: Is calling System.exit() inside a Servlet's destroy() method to forcefully kill any non-daemon threads a good idea?
Calling System.exit() inside ANY servlet-related method is always 100% incorrect. Your code is not the only code running in the JVM - even if you are the only servlet running (the servlet container has resources it will need to cleanup when the JVM really exits.)
The correct way to handle this case is to clean up your threads in the destroy() method. This means starting them in a way that lets you gently stop them in a correct way. Here is an example (where MyThread is one of your threads, and extends ServletManagedThread):
public class MyServlet extends HttpServlet {
private List<ServletManagedThread> threads = new ArrayList<ServletManagedThread>();
// lots of irrelevant stuff left out for brevity
public void init() {
ServletManagedThread t = new MyThread();
threads.add(t);
t.start();
}
public void destroy() {
for(ServletManagedThread thread : threads) {
thread.stopExecuting();
}
}
}
public abstract class ServletManagedThread extends Thread {
private boolean keepGoing = true;
protected abstract void doSomeStuff();
protected abstract void probablySleepForABit();
protected abstract void cleanup();
public void stopExecuting() {
keepRunning = false;
}
public void run() {
while(keepGoing) {
doSomeStuff();
probablySleepForABit();
}
this.cleanup();
}
}
It's also worth noting that there are thread/concurrency libraries out there that can help with this - but if you really do have a handful of threads that are started at servlet initialization and should run until the servlet is destroyed, this is probably all you need.
Question 2: Why does Tomcat 5.0.30 and (later versions including Tomcat 6.x.x) fail to shutdown properly if there's a System.exit() in the destroy() method of the Servlet?
Without more analysis, it's hard to know for certain. Microsoft says that Error 1053 occurs when Windows asks a service to shutdown, but the request times out. That would make it seem like something happened internally to Tomcat that got it into a really bad state. I would certainly suspect that your call to System.exit() could be the culprit. Tomcat (specifically, Catalina) does register a shutdown hook with the VM (see org.apache.catalina.startup.Catalina.start(), at least in 5.0.30). That shutdown hook would get called by the JVM when you call System.exit(). The shutdown hook delegates to the running services, so each service could potentially be required to do alot of work.
If the shutdown hooks (triggered by your System.exit()) fail to execute (they deadlock or something like that,) then it is very easy to understand why the Error 1053 occurs, given the documentation of the Runtime.exit(int) method (which is called from System.exit()):
If this method is invoked after the
virtual machine has begun its shutdown
sequence then if shutdown hooks are
being run this method will block
indefinitely. If shutdown hooks have
already been run and on-exit
finalization has been enabled then
this method halts the virtual machine
with the given status code if the
status is nonzero; otherwise, it
blocks indefinitely.
This "indefinite blocking" behavior would definitely cause an Error 1053.
If you want a more complete answer than this, you can download the source and debug it yourself.
But, I would be willing to bet that if you properly handle your thread management issue (as outlined above,) your problems will go away.
In short, leave the System.exit() call to Tomcat - that's not your job.
Calling System.exit() inside a
Servlet's destroy() method to
forcefully kill any non-daemon threads
is a good idea?
Not a good idea. You will forcefully kill all threads, which might include part of Tomcat that is currently shutting down the system. This will cause Tomcat to un-gracefully shutdown. This can also prevent shutdown handlers from running which can lead to all sorts of problems.
Why does Tomcat 5.0.30 and (later
versions including Tomcat 6.x.x) fail
to shutdown properly if there's a
System.exit() in the destroy() method
of the Servlet.
A lot of code executes after a Servlet destory. The Context destroy and all of its other listeners for one... other servlets. Other applications. Tomcat itelf. By calling System.exit, you prevent all of that from running.
A better question is what are thse non-daemon threads, why are they running, and who starts them?
When writing thread shutdown code like Jared's, I normally make the "keepGoing" member and "stopExecuting()" method static so that all threads get the signal to go down with one shutdown call. Good idea or no?