[JAVA-1271] Java driver does not clean up thread resources (sometimes) Created: 11/Jun/14  Updated: 19/Oct/16  Resolved: 19/Oct/16

Status: Closed
Project: Java Driver
Component/s: Error Handling
Affects Version/s: 2.12.0
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Chris LeCompte Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Tomcat 7.0.27



 Description   

In the case of a RuntimeException such as a ClassNotFoundException, the Java driver may not clean up all of its resources, in particular the non-daemon threads used for pool eviction (the PooledConnectionProvider.sizeMaintenanceTimer). This can cause web containers such as Tomcat to fail to shut down properly. The scenario is as follows:

1. Deploy a web application which deploys a MongoClient connected to a 3 node replica set.
2. Access the application
3. Undeploy the application in Tomcat

Even though MongoClient.close is called by the application, some threads will remain. Any replica set polling threads other than the primary along with threads for maintaining the pools. What happens here is the following:

1. MongoClient.close() is called
2. ...
3. ConcurrentPool.close() is called
4. In closing the pool tries to instantiate a CLDIterator. Since the jar containing the class has been removed a ClassNotFoundException is raised which fails termination of remaining threads.

The PooledConnectionProvider should ensure that all threads created are shut down regardless of failures in the pool.close method. Likewise the other close methods should insulate themselves from such failures. Also, the threads Timer threads spawned for pool eviction should probably be set as daemon threads to avoid shutdown issues.



 Comments   
Comment by Jeffrey Yemin [ 19/Oct/16 ]

I don't see a way to fix this in the general case, as a ClassNofFoundException could potentially be thrown at any level, even before we get to the PooledConnectionProvider.close() method. So insulating that method against failure doesn't guarantee that it will get called in the first place.

Since a Tomcat upgrade has mitigated the issue for you, and as no one else has reported this, I'm going to close as Won't Fix. If it comes up for other users we can re-open it.

Comment by Chris LeCompte [ 12/Jun/14 ]

The application is calling MongoClient.close() as part of a destroy method of a singleton bean in a spring context. The problem wasn't that classes were being unloaded but not loaded in the first place and since the file handle has been removed (the original webapp deleted) the loading of the class fails. There is no stack trace since the exception is swallowed up by:

try

{ _connector.close(); }

catch (final Throwable t)

{ /* nada */ }

in Mongo.close(). An upgrade of tomcat seems to have mitigated although presumably it could still surface in other albeit rare cases. It would probably make more sense to shut down the maintenance timer before closing the pool as well since there's a bit of a race condition between shutting down the pool completely and the running of the maintenance task.

Comment by Jeffrey Yemin [ 12/Jun/14 ]

It's not clear to me why Tomcat starts unloading classes before MongoClient.close() completes. Where is the application calling MongoClient.close() from? Do you have a stack trace?

Generated at Thu Feb 08 08:54:12 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.