I noticed this when our application was shutting down and it's not critical for us but it could be a problem if EventExecutors are being torn down on some ongoing basis.
Promises of EventExecutors that have been shutdown will "lie" that values/exceptions were set successfully and there is no way for the caller to know that it actually failed.
Expected behavior
Actual behavior
Steps to reproduce
Minimal yet complete reproducer code (or URL to code)
public class EventExecutorTest {
@Test
public void notifyAfterShutdown() throws Exception {
EventExecutor executor = new DefaultEventExecutor();
try {
ByteBuf data = Unpooled.buffer(0);
try {
assertEquals(1, data.refCnt());
Promise<ByteBuf> promsie = executor.newPromise();
executor.shutdownGracefully(0L, 0L, TimeUnit.MILLISECONDS).sync();
if (!promsie.trySuccess(data)) {
ReferenceCountUtil.release(data);
}
// Leaking because trySuccess(...) returned true. The same applies
// for the other Promise's setter methods.
assertEquals(0, data.refCnt());
} finally {
ReferenceCountUtil.safeRelease(data);
}
} finally {
executor.shutdownGracefully();
}
}
}
// This Exception is raised internally
java.util.concurrent.RejectedExecutionException: event executor terminated
at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:842) ~[netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:328) ~[netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:321) ~[netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:765) ~[netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.DefaultPromise.safeExecute(DefaultPromise.java:764) [netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:432) [netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:94) [netty-all-4.1.25.Final.jar:?]
at io.netty.util.concurrent.EventExecutorTest.notifyAfterShutdown(EventExecutorTest.java:31) [test/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_172]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_172]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_172]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_172]
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:108) [testng-6.11.jar:?]
at org.testng.internal.Invoker.invokeMethod(Invoker.java:661) [testng-6.11.jar:?]
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:869) [testng-6.11.jar:?]
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1193) [testng-6.11.jar:?]
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126) [testng-6.11.jar:?]
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109) [testng-6.11.jar:?]
at org.testng.TestRunner.privateRun(TestRunner.java:744) [testng-6.11.jar:?]
at org.testng.TestRunner.run(TestRunner.java:602) [testng-6.11.jar:?]
at org.testng.SuiteRunner.runTest(SuiteRunner.java:380) [testng-6.11.jar:?]
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:375) [testng-6.11.jar:?]
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340) [testng-6.11.jar:?]
at org.testng.SuiteRunner.run(SuiteRunner.java:289) [testng-6.11.jar:?]
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) [testng-6.11.jar:?]
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) [testng-6.11.jar:?]
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1301) [testng-6.11.jar:?]
at org.testng.TestNG.runSuitesLocally(TestNG.java:1226) [testng-6.11.jar:?]
at org.testng.TestNG.runSuites(TestNG.java:1144) [testng-6.11.jar:?]
at org.testng.TestNG.run(TestNG.java:1115) [testng-6.11.jar:?]
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114) [testng-remote.jar:?]
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) [testng-remote.jar:?]
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77) [testng-remote.jar:?]
// Leaking...
FAILED: notifyAfterShutdown
java.lang.AssertionError: expected:<0> but was:<1>
at org.testng.AssertJUnit.fail(AssertJUnit.java:59)
at org.testng.AssertJUnit.failNotEquals(AssertJUnit.java:364)
at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:80)
at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:245)
at org.testng.AssertJUnit.assertEquals(AssertJUnit.java:252)
at io.netty.util.concurrent.EventExecutorTest.notifyAfterShutdown(EventExecutorTest.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:108)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:661)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:869)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1193)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:744)
at org.testng.TestRunner.run(TestRunner.java:602)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:380)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:375)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340)
at org.testng.SuiteRunner.run(SuiteRunner.java:289)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1301)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1226)
at org.testng.TestNG.runSuites(TestNG.java:1144)
at org.testng.TestNG.run(TestNG.java:1115)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
Netty version
4.1.25
JVM version (e.g. java -version)
OS version (e.g. uname -a)
I noticed this when our application was shutting down and it's not critical for us but it could be a problem if EventExecutors are being torn down on some ongoing basis.
Promises of EventExecutors that have been shutdown will "lie" that values/exceptions were set successfully and there is no way for the caller to know that it actually failed.
Expected behavior
Actual behavior
Steps to reproduce
Minimal yet complete reproducer code (or URL to code)
Netty version
4.1.25
JVM version (e.g.
java -version)OS version (e.g.
uname -a)