https://bz.apache.org/bugzilla/show_bug.cgi?id=63210

            Bug ID: 63210
           Summary: Tomcat failing to shutdown if EvictionTimer thread is
                    running
           Product: Tomcat 9
           Version: 9.0.x
          Hardware: PC
                OS: Mac OS X 10.1
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: k...@gameldar.com
  Target Milestone: -----

Created attachment 36463
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=36463&action=edit
stacktrace showing servlet initialization in 8.0.53

If a query is executed against a DataSource during the Servlet init phase when
timeBetweenEvictionRunsMillis is defined on the DataSource when you try and
shutdown Tomcat it will shutdown everything but the commons-pool-evictor-thread
is left waiting and will not shut down (regardless of the value set in the
timeBetweenEvictionRunsMillis).

I found this issue as part of upgrading a webapp from working with Tomcat
8.0.53 to 9.0.16. It is caused by a change of behaviour between the two
versions due to initialization of the Servlets happening in a different way
between the two versions, namely that the Servlet initialization in Tomcat
8.0.53 happens in a separate thread, whereas with 9.0.x it happens on the main
thread.

This means that when the EvictionTimer thread is started it inherits the daemon
flag from the parent thread (as it isn't explicitly set) which is false in
9.0.x and true in 8.0.53 and therefore when the main thread exits after
shutdown in 9.0.x the common-pool-evictor-thread continues and stops
termination of Tomcat.

There is a workaround for this - by manually closing the underlying datasource
during the Servlet destroy method.

There are potentially two issues here:
1. The EvictionTimer thread should be marked as setDaemon after it is created
(in the EvictorTimerFactory) this way it'll be killed when Tomcat is shutdown.
See the attached diff which I've confirmed fixes the issue.

2. The resources are not actually being closed if they are loaded via a
reference in the context.

#2 here is perhaps the bigger issue - this may be an issue for more than just
the EvictionTimer, but it was the one I hit.


Full Replication steps:
1. Put the attached test.war into the base tomcat direct

This war file was a simple webapp based upon:

https://www.journaldev.com/2513/tomcat-datasource-jndi-example-java

You'll need to create the database with the tables as described in that
example. For reference I was using PostgreSQL.

I've modified the source of the servlet however as attached (TestServlet.java)
- namely it is now loading the JNDI DataSource during the Servlet.init() method
and executing the same getEmployees query in the init method to ensure
datasource pool initialized at that point.

2. create the context for the webapp - put the attached test.xml into
conf/Catalina/localhost/test.xml.
Note this is using a Resource for the DataSource and setting the
timeBetweenEvictionRunsMillis="60000".

You'll need to change the database configuration (url, driverClassname) in the
Resource to point to your database.

3. Create the database and populate the tables (see the attached link)
4. Start up Tomcat using bin/start.sh
5. Connect to http://localhost:8080/test/ to confirm the servlet is loaded and
working
6. Shutdown Tomcat using bin/shutdown.sh

It'll say it is shutdown - and to ensure that it isn't stuck in the eviction
wait time wait at least 60 seconds - but if you look at your processes you'll
see the Tomcat instance is still running with a similar list of threads as seen
in the attached jstack.log.  



The Servlet is producing the stacktrace during the init that shows the
difference between the 9.0.x startup and the 8.0.53 startup (full stack traces
are attached).

8.0.53 startup looks like:
26-Feb-2019 10:26:18.071 INFO [localhost-startStop-1]
org.apache.catalina.core.ApplicationContext.log java.lang.Exception
        at test.TestServlet.init(TestServlet.java:28)
        at javax.servlet.GenericServlet.init(GenericServlet.java:158)
        at
org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:118
       // snip

        at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834) 


Whereas the 9.0.16 stacktrace traces back to the Bootstrap main method:

Feb. 26, 2019 8:42:08 AM org.apache.catalina.core.ApplicationContext log
INFO: java.lang.Exception
        at test.TestServlet.init(TestServlet.java:28)
        at javax.servlet.GenericServlet.init(GenericServlet.java:158)
        at
org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1123)
        // snip
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to