gianm commented on code in PR #19567:
URL: https://github.com/apache/druid/pull/19567#discussion_r3975177321


##########
processing/src/main/java/org/apache/druid/java/util/http/client/NettyHttpClient.java:
##########
@@ -371,9 +401,13 @@ private void handleExceptionAndCloseChannel(final 
Throwable t, final boolean clo
 
             if (!retVal.isDone()) {
               if (t instanceof ReadTimeoutException) {
-                // ReadTimeoutException thrown by ReadTimeoutHandler is a 
singleton with a misleading stack trace.
-                // No point including it: instead, we replace it with a fresh 
exception.
-                retVal.setException(new 
ReadTimeoutException(StringUtils.format("[%s] Read timed out", requestDesc)));
+                // ReadTimeoutHandler fires ReadTimeoutException.INSTANCE, a 
shared singleton whose stack
+                // trace was captured once at class load and points at 
whichever code first touched Netty's
+                // class initializer. Emit a fresh instance so the stack trace 
reflects this actual timeout.
+                if (log.isDebugEnabled()) {
+                  log.debug("[%s] Read timed out", requestDesc);
+                }
+                retVal.setException(new ReadTimeoutException());

Review Comment:
   Hmm. It seems like `ReadTimeoutException` in Netty 4 doesn't have a stack 
trace (it inherits a no-op `fillInStackTrace` from `TimeoutException`). I guess 
it means we should either stick with the builtin `ReadTimeoutException` from 
`ReadTimeoutHandler` or create a new one that has a good message.
   
   If you go with a solution that uses `new ReadTimeoutException()` or 
`ReadTimeoutException.INSTANCE` (i.e. no nice message) then at least update the 
`HttpResponseHandler` in `DirectDruidClient` to interpolate `e` rather than 
`e.getMessage()` into `"Query[%s] url[%s] failed with exception msg [%s]"`. 
Maybe only if `e.getMessage()` is null, just to avoid chaanging too many 
messages. That way intead of seeing `exception msg [null]` for a timeout it'd 
be `exception msg [io.netty.handler.timeout.ReadTimeoutException: null]` (I 
think).



##########
processing/src/main/java/org/apache/druid/java/util/http/client/pool/ChannelResourceFactory.java:
##########
@@ -208,62 +222,46 @@ public void operationComplete(ChannelFuture f2)
       sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
       sslEngine.setSSLParameters(sslParameters);
       sslEngine.setUseClientMode(true);
-      final SslHandler sslHandler = new SslHandler(
-          sslEngine,
-          SslHandler.getDefaultBufferPool(),
-          false,
-          timer,
-          sslHandshakeTimeout
-      );
+      final SslHandler sslHandler = new SslHandler(sslEngine);
+      sslHandler.setHandshakeTimeoutMillis(sslHandshakeTimeout);
 
-      // https://github.com/netty/netty/issues/160
-      sslHandler.setCloseOnSSLException(true);
-
-      final ChannelFuture handshakeFuture = 
Channels.future(connectFuture.getChannel());
-      connectFuture.getChannel().getPipeline().addLast(ERROR_HANDLER_NAME, new 
ConnectionErrorHandler(handshakeFuture));
-      connectFuture.addListener(
-          new ChannelFutureListener()
-          {
-            @Override
-            public void operationComplete(ChannelFuture f)
-            {
-              if (f.isSuccess()) {
-                final ChannelPipeline pipeline = f.getChannel().getPipeline();
-                pipeline.addFirst("ssl", sslHandler);
-                sslHandler.handshake().addListener(
-                    new ChannelFutureListener()
-                    {
-                      @Override
-                      public void operationComplete(ChannelFuture f2)
-                      {
-                        if (f2.isSuccess()) {
-                          handshakeFuture.setSuccess();
-                        } else {
-                          handshakeFuture.setFailure(
-                              new ChannelException(
-                                  StringUtils.format("Failed to handshake with 
host[%s]", hostname),
-                                  f2.getCause()
-                              )
-                          );
-                        }
-                      }
-                    }
-                );
-              } else {
-                handshakeFuture.setFailure(
-                    new ChannelException(
-                        StringUtils.format("Failed to connect to host[%s]", 
hostname),
-                        f.getCause()
-                    )
-                );
-              }
-            }
-          }
+      final Channel sslChannel = connectFuture.channel();
+      final ChannelPromise handshakePromise = sslChannel.newPromise();
+      sslChannel.eventLoop().execute(
+          () -> sslChannel.pipeline().addLast(ERROR_HANDLER_NAME, new 
ConnectionErrorHandler(handshakePromise))
       );
+      connectFuture.addListener((ChannelFuture f) -> {
+        if (f.isSuccess()) {
+          final ChannelPipeline pipeline = f.channel().pipeline();
+          pipeline.addFirst("ssl", sslHandler);
+          sslHandler.handshakeFuture().addListener(f2 -> {
+            if (f2.isSuccess()) {
+              handshakePromise.setSuccess();

Review Comment:
   This `setSuccess` and the following two `setFailure` should I think all be 
`trySuccess` / `tryFailure` to avoid blowing up on an already-completed promise.



##########
processing/src/main/java/org/apache/druid/java/util/http/client/NettyHttpClient.java:
##########
@@ -125,49 +119,28 @@ public <Intermediate, Final> ListenableFuture<Final> go(
     final Channel channel;
     final String hostKey = getPoolKey(url);
     final ResourceContainer<ChannelFuture> channelResourceContainer = 
pool.take(hostKey);
+    // ResourcePool.take is documented as blocking, but a null return is 
possible on pool exhaustion or shutdown;
+    // fail fast rather than NPE on the awaitUninterruptibly() below.
+    if (channelResourceContainer == null) {
+      return Futures.immediateFailedFuture(
+          new ChannelException(StringUtils.format("Connection pool exhausted 
or timed out for host[%s]", hostKey))

Review Comment:
   This message is inaccurate: `pool.take(hostKey)` is only null if `pool` is 
closed. (Which shouldn't happen unless the client itself is closed, and would 
lead to an `ERROR` being logged anyway.)
   
   Although, I think the container can have a null inside, i.e., 
`channelResourceContainer.get()` can be null in some other cases, such as an 
interrupt happening on the thread. It may be worth checking for that (one line 
down).



##########
processing/src/main/java/org/apache/druid/java/util/http/client/NettyHttpClient.java:
##########
@@ -371,9 +401,13 @@ private void handleExceptionAndCloseChannel(final 
Throwable t, final boolean clo
 
             if (!retVal.isDone()) {
               if (t instanceof ReadTimeoutException) {
-                // ReadTimeoutException thrown by ReadTimeoutHandler is a 
singleton with a misleading stack trace.
-                // No point including it: instead, we replace it with a fresh 
exception.
-                retVal.setException(new 
ReadTimeoutException(StringUtils.format("[%s] Read timed out", requestDesc)));
+                // ReadTimeoutHandler fires ReadTimeoutException.INSTANCE, a 
shared singleton whose stack
+                // trace was captured once at class load and points at 
whichever code first touched Netty's
+                // class initializer. Emit a fresh instance so the stack trace 
reflects this actual timeout.
+                if (log.isDebugEnabled()) {
+                  log.debug("[%s] Read timed out", requestDesc);

Review Comment:
   There is no need to use `log.isDebugEnabled()` here, it's only valuable if 
it saves computation. The same check is in `log.debug`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to