Shut down leaked executors and Hibernate SessionFactory on close - #37
Shut down leaked executors and Hibernate SessionFactory on close#37klemela wants to merge 3 commits into
Conversation
ZipSessionServlet and FileStorageDiscovery each created a cached thread pool that was never shut down. OidcResourceTest built its own HibernateUtil but never closed its SessionFactory.
storageDiscovery.close() shared a try block with httpServer.stop() and authService.close(), so a failure in either left the executor running, i.e. the leak survived exactly the case it was added for. Give each step its own try/catch instead. The executor shutdown still runs after httpServer.stop(), because requests reach FileStorageDiscovery.updateInBackgroundIfNecessary() and would get a RejectedExecutionException. The null checks keep close() usable from main() when startServer() failed before these fields were assigned, which the single broad catch used to handle implicitly.
|
Pushed
The executor shutdown deliberately stays after The null checks preserve behaviour the single broad
|
destroy() shuts down the executor, so executor.submit() can throw RejectedExecutionException while an export is still running. Only RestException was caught, so it escaped packageSession: the latch was never counted down and the keep-alive thread kept writing spaces to the client, and the temporary zip dataset was left in the session. A rejected zip task is now an ordinary error instead, which deletes the dataset and sends the errors in the json like every other failure. The upload got its own errors.isEmpty() check, because it must not read a pipe that no thread is writing to. Release the keep-alive and the pipe in a finally, which covers unchecked exceptions from anywhere in the method. Closing the read end also unblocks the zip thread when the upload failed while it was still writing: nobody reads the pipe after that, but PipedOutputStream.write waits forever, because the reader thread stays alive in the Jetty pool. The keep-alive submit is intentionally left unguarded. It runs before anything is written, so a rejection there still fails the request cleanly, which is better than importing or exporting a session with no keep-alive when the router closes the connection in 30 seconds.
|
Pushed
A rejected zip task is now an ordinary entry in The keep-alive and the pipe are released in a The keep-alive |
ZipSessionServlet and FileStorageDiscovery each created a cached
thread pool that was never shut down. OidcResourceTest built its own
HibernateUtil but never closed its SessionFactory.
Test plan
No dedicated test: each of these is created once for the life of its
owning process (SessionWorker, FileBroker, the test JVM), so the leak
only matters if that owner is created/destroyed repeatedly, which
doesn't happen in normal use or in the test suite. Verified with the
full suite still passing.