Details
-
Bug
-
Resolution: Unresolved
-
Major
-
None
-
11.1.2
-
None
-
Unknown
-
Description
Steps to reproduce:
Use one of the examples on the https://extensions.xwiki.org/xwiki/bin/view/Extension/JIRA/JIRA%20Module#HExamples and call them several times while taking a thread dump of XWiki's Java process in between.
Expected result:
The number of threads named "httpclient-io:thread-1" and "I/O dispatcher" doesn't grow.
Actual result:
Every time a client is retrieved, one thread named httpclient-io:thread-1 and ten threads named I/O dispatcher followed by a continuously increasing number are created.
In the thread dump, you can see the following stack traces for them:
"httpclient-io:thread-1" #30727 java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPoll.wait(Native Method) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) - locked on sun.nio.ch.Util$2@60789986 - locked on sun.nio.ch.EPollSelectorImpl@6c886242 at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:343) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:221) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64) at java.lang.Thread.run(Thread.java:840)
"I/O dispatcher 470" #30725 java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPoll.wait(Native Method) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:118) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:129) - locked on sun.nio.ch.Util$2@56f0d60 - locked on sun.nio.ch.EPollSelectorImpl@66e4a471 at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:141) at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:255) at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591) at java.lang.Thread.run(Thread.java:840)
After some time, this exhausts the number of threads that are available from the operating system and will bring the XWiki instance down.
As a workaround, it is possible to call close() on the returned REST client which terminates the started threads again. In Groovy, a .withCloseable() block can be used to automatically close the client. While this could be considered a best practice, it feels too easy to miss and I think it would actually be much better for performance if all clients could share a single connection pool instead of starting a new one for every client.