Fix AsyncHttpEncryptionAwareConduitFactory thread leak on WinRMService close - #85
Conversation
… closing WinRMService Agent-Logs-Url: https://github.com/MetricsHub/winrm-java/sessions/266b5281-d5d0-456c-9f38-84648d52a6c0 Co-authored-by: bertysentry <32521698+bertysentry@users.noreply.github.com>
- getWebServiceClient: register the AsyncHttpEncryptionAwareConduitFactory only once instead of shutting down and replacing it on every call. The client's cached conduit keeps using the factory it was created with, so replacing the endpoint property only orphaned factory instances (which hold no threads until a conduit uses them), and shutting down the in-use factory made AsyncHTTPConduit.setupConnection silently fall back to the synchronous transport on the retry request. Reusing the factory also guarantees WinRMService.close() shuts down the instance that owns the background threads. - WinRMService.shutdownConduitFactory: make it an instance method so the static mock of WinRMService in tests cannot swallow it. - WinRMServiceTest: pass null ticketCache/authentications so the call matches the class-level createInstance stub that calls the real method (the any(Path.class) matcher does not match null, so the mocked createInstance returned null and the test failed with an NPE). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Took this over to finalize. Review findings and changes (commit 08e8b60): Kept: the Reworked: the
Instead, the factory is now registered only if absent, so the endpoint property always references the single factory the conduit actually uses, and Fixed: the new test. It failed as written for two reasons: Also merged |
AsyncHttpEncryptionAwareConduitFactoryspawns aCloseIdleConnectionThreadon construction but itsshutdown()is never called, leaving background threads running afterWinRMService.close().Changes
WinRMService.close(): AddedshutdownConduitFactory()helper that retrieves theAsyncHTTPConduitFactoryfrom the client's endpoint properties (keyed byHTTPConduitFactory.class.getName()) and callsshutdown()on it beforeclient.destroy()— for bothcmdClientandwqlClient.WinRMInvocationHandler.getWebServiceClient(): Register the conduit factory on the endpoint only once instead of replacing it on every call. During authentication retries the method is re-invoked on the same client, whose cached conduit keeps using the factory it was created with — replacing the property only orphaned factory instances, and would have leftclose()shutting down the wrong one. Reusing the factory guaranteesclose()targets the instance that owns the background threads.WinRMServiceTest: AddedtestCloseShutdownsConduitFactoriesverifying thatshutdown()is called on the registered factory for both clients whenclose()reduces the use-count to zero.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
schemas.dmtf.org/usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED --add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.xs=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED -jar /tmp/cxf-tmp-5752734876370477597/cxf-codegen6026574321731572209.jar /tmp/cxf-tmp-5752734876370477597/cxf-w2j12693372498432677126args(dns block)/usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED --add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.xs=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED -jar /tmp/cxf-tmp-14258761027604973883/cxf-codegen12271205995426713979.jar /tmp/cxf-tmp-14258761027604973883/cxf-w2j10518240929801386728args(dns block)/usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED --add-exports=java.xml/com.sun.org.apache.xerces.internal.impl.xs=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED -jar /tmp/cxf-tmp-17700549494455899307/cxf-codegen3872050582524597490.jar /tmp/cxf-tmp-17700549494455899307/cxf-w2j7804011468224100303args(dns block)www.puppycrawl.com/opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-edd81b6d958bffb3/dbs/java/working/files-to-index7616153095043599934.list --sourceArchiveDir=/tmp/codeql-scratch-edd81b6d958bffb3/dbs/java/src --outputDir=/tmp/codeql-scratch-edd81b6d958bffb3/dbs/java/trap/java(dns block)If you need me to access, download, or install something from one of these locations, you can either: