[
https://issues.apache.org/jira/browse/TINKERPOP3-972?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15011244#comment-15011244
]
ASF GitHub Bot commented on TINKERPOP3-972:
-------------------------------------------
Github user pingtimeout commented on the pull request:
https://github.com/apache/incubator-tinkerpop/pull/146#issuecomment-157756815
I am not an expert in the Tinkerpop codebase but my understanding of the
code is the following:
Yes, the `CompletableFuture` can be executed in parallel with other tasks
by the executor, since [it may
be](https://github.com/apache/incubator-tinkerpop/blob/master/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java#L580-580)
multithreaded. However, I don't think it can complete if tasks are still
being executed. It calls `factory.shutdown()` which [delegates the
action](https://github.com/apache/incubator-tinkerpop/blob/master/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java#L552-552)
to Netty.
That `factory.shutdown()` closes Netty's event loop after a grace delay of
roughly 17 seconds (that's the "sensible values" described by
`EventLoopGroup::shutdownGracefully()`. A long running task that uses the
transport layer may therefore encounter an IOException, but I don't think that
is a really bad thing, considering it is the user who explicitly triggered the
`cluster.close()` without waiting for all of the pending requests to complete.
I mean, as a developer, if my code is reading a file and I call
`inputStream.close()` in another thread, I don't expect the latter call to
block indefinitely until the whole file has been read.
In the alternative approach you describe, how long would you wait for the
termination to happen?
> Cluster::close does not shut down its executor
> ----------------------------------------------
>
> Key: TINKERPOP3-972
> URL: https://issues.apache.org/jira/browse/TINKERPOP3-972
> Project: TinkerPop 3
> Issue Type: Bug
> Components: driver
> Affects Versions: 3.0.2-incubating
> Reporter: Pierre Laporte
> Assignee: stephen mallette
>
> *Context*
> Using the Gremlin driver in a Java application, I can create a {{Cluster}}
> and a {{Client}} to send some queries to my Gremlin server.
> However, my application never finishes because some Gremlin worker threads
> stay alive, even though I call {{cluster.close()}}.
> *Cause*
> Those threads are never terminated:
> {code}
> "gremlin-driver-worker-4" #25 prio=5 os_prio=31 tid=0x00007f824ca4a800
> nid=0x6a07 waiting on condition [0x0000700001df0000]
> java.lang.Thread.State: WAITING (parking)
> at sun.misc.Unsafe.park(Native Method)
> - parking to wait for <0x000000076edb9158> (a
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
> at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
> at
> java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
> at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> at java.lang.Thread.run(Thread.java:745)
> "gremlin-driver-worker-3" #23 prio=5 os_prio=31 tid=0x00007f824ca46800
> nid=0x6803 waiting on condition [0x0000700001ced000]
> java.lang.Thread.State: WAITING (parking)
> at sun.misc.Unsafe.park(Native Method)
> - parking to wait for <0x000000076edb9158> (a
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
> at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
> at
> java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
> at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> at java.lang.Thread.run(Thread.java:745)
> "gremlin-driver-worker-2" #22 prio=5 os_prio=31 tid=0x00007f824e22f800
> nid=0x6603 waiting on condition [0x0000700001bea000]
> java.lang.Thread.State: WAITING (parking)
> at sun.misc.Unsafe.park(Native Method)
> - parking to wait for <0x000000076edb9158> (a
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
> at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
> at
> java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
> at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> at java.lang.Thread.run(Thread.java:745)
> "gremlin-driver-worker-1" #21 prio=5 os_prio=31 tid=0x00007f824e21f000
> nid=0x6403 waiting on condition [0x0000700001ae7000]
> java.lang.Thread.State: WAITING (parking)
> at sun.misc.Unsafe.park(Native Method)
> - parking to wait for <0x000000076edb9158> (a
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
> at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
> at
> java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
> at
> java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
> at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> at java.lang.Thread.run(Thread.java:745)
> {code}
> *Workaround*
> This code block can solve the issue on the caller side, but relies on
> reflection and might break any time the implementation changes:
> {code:java}
> private void fixThreadLeakInGremlinCluster(Cluster cluster) {
> try {
> Method executorAccessor =
> Cluster.class.getDeclaredMethod("executor");
> executorAccessor.setAccessible(true);
> ScheduledExecutorService executor = (ScheduledExecutorService)
> executorAccessor.invoke(cluster);
> executor.shutdownNow();
> } catch (Exception e) {
> e.printStackTrace();
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)