We have noticed the following behaviour of manager application: sometimes when reloading context, it is stopped and than it is not started. It happens when server is heavily loaded. We think, that the reason of it is the following: org.apache.catalina.core.StandardContext, method reload() ... try { stop(); } catch (LifecycleException e) { log.error(sm.getString("standardContext.stoppingContext"), e); } try { start(); } catch (LifecycleException e) { log.error(sm.getString("standardContext.startingContext"), e); } ... Method stop() can throw a runtime exception (org.apache.catalina.session.StandardSession): public void removeAttribute(String name, boolean notify) { // Validate our current state if (!isValid()) throw new IllegalStateException (sm.getString("standardSession.removeAttribute.ise")); removeAttributeInternal(name, notify); } Is it possible to catch this exception: try { stop(); } catch (LifecycleException e) { log.error(sm.getString("standardContext.stoppingContext"), e); } catch (IllegalStateException illegalStateException) { log.error(sm.getString("standardContext.stoppingContext"), illegalStateException); } Stack trace is provided: java.lang.IllegalStateException: removeAttribute: Session already invalidated at org.apache.catalina.session.StandardSession.removeAttribute (StandardSession.java:1144) at org.apache.catalina.session.StandardSession.removeAttribute (StandardSession.java:1119) at org.apache.catalina.session.StandardSession.writeObject (StandardSession.java:1401) at org.apache.catalina.session.StandardSession.writeObjectData (StandardSession.java:899) at org.apache.catalina.session.StandardManager.doUnload (StandardManager.java:539) at org.apache.catalina.session.StandardManager.unload (StandardManager.java:485) at org.apache.catalina.session.StandardManager.stop (StandardManager.java:687) at org.apache.catalina.core.StandardContext.stop (StandardContext.java:4474) at org.apache.catalina.core.StandardContext.reload (StandardContext.java:3015) at org.apache.catalina.manager.ManagerServlet.reload (ManagerServlet.java:1014) at org.apache.catalina.manager.HTMLManagerServlet.reload (HTMLManagerServlet.java:477) at org.apache.catalina.manager.HTMLManagerServlet.doGet (HTMLManagerServlet.java:100) at javax.servlet.http.HttpServlet.service(HttpServlet.java:697) at javax.servlet.http.HttpServlet.service(HttpServlet.java:810) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:237) at org.apache.catalina.core.ApplicationFilterChain.doFilter (ApplicationFilterChain.java:157) at org.apache.catalina.core.StandardWrapperValve.invoke (StandardWrapperValve.java:214) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:104) at org.apache.catalina.core.StandardPipeline.invoke (StandardPipeline.java:520) at org.apache.catalina.core.StandardContextValve.invokeInternal (StandardContextValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke (StandardContextValve.java:152) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:104) at org.apache.catalina.authenticator.AuthenticatorBase.invoke (AuthenticatorBase.java:540) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:102) at org.apache.catalina.valves.RequestFilterValve.process (RequestFilterValve.java:287) at org.apache.catalina.valves.RemoteAddrValve.invoke (RemoteAddrValve.java:84) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:102) at org.apache.catalina.core.StandardPipeline.invoke (StandardPipeline.java:520) at org.apache.catalina.core.StandardHostValve.invoke (StandardHostValve.java:137) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:104) at org.apache.catalina.valves.ErrorReportValve.invoke (ErrorReportValve.java:117) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:102) at org.apache.catalina.core.StandardPipeline.invoke (StandardPipeline.java:520) at org.apache.catalina.core.StandardEngineValve.invoke (StandardEngineValve.java:109) at org.apache.catalina.core.StandardValveContext.invokeNext (StandardValveContext.java:104) at org.apache.catalina.core.StandardPipeline.invoke (StandardPipeline.java:520) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929) at org.apache.coyote.tomcat5.CoyoteAdapter.service (CoyoteAdapter.java:160) at org.apache.coyote.http11.Http11Processor.process (Http11Processor.java:793) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnectio n(Http11Protocol.java:702) at org.apache.tomcat.util.net.TcpWorkerThread.runIt (PoolTcpEndpoint.java:571) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run (ThreadPool.java:644) at java.lang.Thread.run(Thread.java:534)
Could somebody please comment this bug? It was opened two weeks ago ... I think, code should be changed to: try { stop(); } catch (LifecycleException e) { log.error(sm.getString("standardContext.stoppingContext"), e); } catch (IllegalStateException illegalStateException) { }
Ok, I'll comment: I think not, this case requires user intervention. How about trying to find the cause of the exception instead ? (which I don't get, but was the only reason why I didn't close your bug as INVALID in the first place)
Yes, I agree, I have to find a reason of this behavior. But please imagine the situation: server is loaded with 500 – 1000 sessions or even more. And there is a necessity of reloading context. And if this situation occurs, application will not be available for several minutes, because the only thing we can do – restart tomcat. It is very convenient – possibility of context reload, but now we afraid reload context because if this happens, it is the same as tomcat restart. I am sorry, I do not know tomcat structure well enough. I may be wrong, but I have a hypothesis how this can happen. There is background thread that calls StoreBase.processExpires() method. This method walks through sessions and it may call StandardSession.recycle() or StandardSession.expire(). Both of this methods may set the following fields of Session object: expiring to false; isValid to false; accessCount to 0; Suppose, we reloading context - in StandardManager.doUnload we walk through sessions and call writeObjectData on each session, which will call writeObject method. It calls removeAttribute method, which may throw a runtime exception, if isValid() == false. isValid() == false if expiring == false; isValid == false; accessCount == 0; Suppose, at the same time background thread sets this fields to expiring = false; isValid = false; accessCount = 0; Than we will have this situation. I do not know is this hypothesis true or not. I may be wrong, but it is important for us that is why I am moving a suggestion. Could you please tell your opinion?
I would probably -1 catching this exception, as I'd like tomcat's lifecycle handling code to handle lifecycle exceptions only, and leave other things higher up the hierarchy. If you really need this functionality, at least for the time being, I suggest extending StandardContext with your own context. This is why Tomcat is open- source and why we have the className attribute on the Context element: it's trivial to extend and customize. If over time you can't find a cause and are convinced your fix is essential to the global tomcat community, we can reopen this bug and/or re-discuss this issue on the tomcat-dev list. So for now I'm closing it. If you do customize StandardContext and it works, please post your findings to tomcat-user, to see if others find it helpful.