Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log when global IoExecutor or Executor instance gets closed #1337

Merged
merged 2 commits into from
Jan 28, 2021

Conversation

idelpivnitskiy
Copy link
Member

@idelpivnitskiy idelpivnitskiy commented Jan 26, 2021

Motivation:

Global instances of IoExecutor and Executor are shared across all client
and server instances by default (unless users provide custom executors).
Closing them may affect all other clients and servers that depend on them.
The only legit way of closing global executors is when everything else that
depends on it is already closed. We should notify users if they close
global instances.

Modifications:

  • Wrap global IoExecutor and Executor instances and log when users
    subscribe to their closeAsync() or closeAsyncGracefully() methods;
  • Change NettyIoExecutors#createIoExecutor methods return type to
    EventLoopAwareNettyIoExecutor;

Result:

Users who closed global IoExecutor or Executor in incorrect order and debug
issues caused by this closure will see a debug message log that will point to
the root cause.

Motivation:

Global instance of `IoExecutor` and `Executor` is shared across all client
and server instances by default (unless users provide custom executors).
Closing them may affect all other clients and servers that depends on them.
The only legit way of closing global executors if when everything else that
depends on it is already closed. We should notify users if they close
global instances.

Modifications:

- Wrap global `IoExecutor` and `Executor` instances and log when users
subscribe to their `closeAsync()` or `closeAsyncGracefully()` methods;

Result:

Users who closed global `IoExecutor` or `Executor` in incorrect order and debug
issues caused by this closure will see a debug message log that will point to
the root cause.
Copy link
Contributor

@tkountis tkountis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good 🚀
Build failures highlight that there is an expectation that the IoExecutor is also an EventLoopAwareNettyIoExecutor. This begs the question whether we should enforce this check during compile-time when we construct the DnsClient?

java.lang.ExceptionInInitializerError
	at io.servicetalk.http.netty.GlobalDnsServiceDiscoverer.globalDnsServiceDiscoverer(GlobalDnsServiceDiscoverer.java:49)
	at io.servicetalk.http.netty.DefaultSingleAddressHttpClientBuilder.forHostAndPort(DefaultSingleAddressHttpClientBuilder.java:177)
	at io.servicetalk.http.netty.HttpClients.forSingleAddress(HttpClients.java:136)
	at io.servicetalk.http.router.jersey.AbstractNonParameterizedJerseyStreamingHttpServiceTest.initServerAndClient(AbstractNonParameterizedJerseyStreamingHttpServiceTest.java:160)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.mockito.internal.junit.JUnitRule$1.evaluateSafely(JUnitRule.java:57)
	at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:48)
	at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:258)
	at io.servicetalk.concurrent.internal.ServiceTalkTestTimeout$TimeoutStatement$CallableStatement.call(ServiceTalkTestTimeout.java:170)
	at io.servicetalk.concurrent.internal.ServiceTalkTestTimeout$TimeoutStatement$CallableStatement.call(ServiceTalkTestTimeout.java:162)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalArgumentException: Incompatible IoExecutor: io.servicetalk.transport.netty.internal.GlobalExecutionContext$GlobalIoExecutor@512576ef. Not a netty based IoExecutor.
	at io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutors.toEventLoopAwareNettyIoExecutor(EventLoopAwareNettyIoExecutors.java:43)
	at io.servicetalk.dns.discovery.netty.DefaultDnsClient.<init>(DefaultDnsClient.java:135)
	at io.servicetalk.dns.discovery.netty.DefaultDnsServiceDiscovererBuilder.build(DefaultDnsServiceDiscovererBuilder.java:266)
	at io.servicetalk.dns.discovery.netty.DefaultDnsServiceDiscovererBuilder.buildARecordDiscoverer(DefaultDnsServiceDiscovererBuilder.java:201)
	at io.servicetalk.http.netty.GlobalDnsServiceDiscoverer$HostAndPortClientInitializer.<clinit>(GlobalDnsServiceDiscoverer.java:64)```

@idelpivnitskiy
Copy link
Member Author

@tkountis thanks!
EventLoopAwareNettyIoExecutor is an internal type, that's why we can not require it from users.

@idelpivnitskiy idelpivnitskiy merged commit a13ae07 into apple:main Jan 28, 2021
@idelpivnitskiy idelpivnitskiy deleted the GlobalExecutionContext branch January 28, 2021 22:54
bondolo pushed a commit to bondolo/servicetalk that referenced this pull request Jan 29, 2021
…e#1337)

Motivation:

Global instances of `IoExecutor` and `Executor` are shared across all client
and server instances by default (unless users provide custom executors).
Closing them may affect all other clients and servers that depend on them.
The only legit way of closing global executors is when everything else that
depends on it is already closed. We should notify users if they close
global instances.

Modifications:

- Wrap global `IoExecutor` and `Executor` instances and log when users
subscribe to their `closeAsync()` or `closeAsyncGracefully()` methods;
- Change `NettyIoExecutors#createIoExecutor` methods return type to
`EventLoopAwareNettyIoExecutor`;

Result:

Users who closed global `IoExecutor` or `Executor` in incorrect order and debug
issues caused by this closure will see a debug message log that will point to
the root cause.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants