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

Better Netty Logging and Error Reporting. #3261

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

scottweaver
Copy link
Contributor

Added support to enable internal Netty log output.

Replaced contrived PrematureChannelException in NettyClientDriver with the actual underlying Netty exception.

Added support to enable internal Netty log output.

Replaced contrived 'PrematureChannelException' with the actual underlying Netty exception.
@987Nabil
Copy link
Contributor

@scottweaver The idea is good and needed. But I think the changes in the traits are not binary compatible.
Mima should give you some hints once it ran 🙂
Also I'd like @kyri-petrou to have a look.

Copy link
Collaborator

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

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

Left some comments below, but my main concern is the failing MiMA checks. Since zio-http is in a stable version now, we need to ensure backwards binary compatibility at the very least for classes / methods that are publicly accessible and could be used by users.

@scottweaver
Copy link
Contributor Author

Left some comments below, but my main concern is the failing MiMA checks. Since zio-http is in a stable version now, we need to ensure backwards binary compatibility at the very least for classes / methods that are publicly accessible and could be used by users.

The two things I see readily exposed to the end user, correct me id I missed something, are the additions of enableInternalLogging and onFailure to ClientDriver.requestOnChannel and enableInternalLogging added to ZClient#Config.

For the later, Config has a default value set for the new enableInternalLogging so that should limit its impact.

For the former, I would argue that requestOnChannel is used exclusively by zio-http internals and is ONLY public so that alternative implementations other than Netty could be created.

While it is not outside the realm of possibility someone, somewhere has actually done that, I would argue the vast majority of users have never even looked at the ClientDriver class much less even considered creating their own custom implementation.

@987Nabil
Copy link
Contributor

987Nabil commented Jan 5, 2025

Left some comments below, but my main concern is the failing MiMA checks. Since zio-http is in a stable version now, we need to ensure backwards binary compatibility at the very least for classes / methods that are publicly accessible and could be used by users.

The two things I see readily exposed to the end user, correct me id I missed something, are the additions of enableInternalLogging and onFailure to ClientDriver.requestOnChannel and enableInternalLogging added to ZClient#Config.

For the later, Config has a default value set for the new enableInternalLogging so that should limit its impact.

For the former, I would argue that requestOnChannel is used exclusively by zio-http internals and is ONLY public so that alternative implementations other than Netty could be created.

While it is not outside the realm of possibility someone, somewhere has actually done that, I would argue the vast majority of users have never even looked at the ClientDriver class much less even considered creating their own custom implementation.

While that might be true, I don't want to break compat if it is not absolutely necessary.
For requestOnChannel, please add default values, put the values at the end of the parameter list and use unroll. And for Config actually just the same 🙂

Added support to enable internal Netty log output.

Replaced contrived 'PrematureChannelException' with the actual underlying Netty exception.
@scottweaver
Copy link
Contributor Author

@987Nabil I went ahead and added Unroll and modified the methods.

The promise argument bit is mighty ugly, but it is what I came up for a first attempt. I welcome any input to clean that up.

This set of changes improves on the initial pass in a couple of ways.

There is no longer a need to await on the 'onFailure' promise, reasons provided below.

All non-websocket channel handling operations now live inside 'ClientInboundHandler'.  This includes the logic for 'exceptionCaught' which is responsible for properly completing 'onComplete', 'onResponse' and 'onFailure' when an exception occurs during Netty channel pipeline processing.

The 'ChannelInterface.interrupt' implementation now handles completion up of the 'onResponse' and 'onFailure' promises in the case where 'onComplete' is interrupted.

The close future listener has been completely removed as its responsibilities are covered by the 'ClientInboundHandler' and the 'ChannelInterface'. Interesting discovery for me was that the listener actually gets invoked BEFORE the 'exceptionCaught' method of 'ClientInboundHandler'.  This is what lead be to the decision to completely remove the listener all together.
@scottweaver
Copy link
Contributor Author

I have removed the concerning await portion of the code, gonna put the commit comments here as a summary for the new implementation:

This set of changes improves on the initial pass in a couple of ways.

There is no longer a need to await on the 'onFailure' promise, reasons provided below.

All non-websocket channel handling operations now live inside 'ClientInboundHandler'. This includes the logic for 'exceptionCaught' which is responsible for properly completing 'onComplete', 'onResponse' and 'onFailure' when an exception occurs during Netty channel pipeline processing.

The 'ChannelInterface.interrupt' implementation now handles completion up of the 'onResponse' and 'onFailure' promises in the case where 'onComplete' is interrupted.

The close future listener has been completely removed as its responsibilities are covered by the 'ClientInboundHandler' and the 'ChannelInterface'. Interesting discovery for me was that the listener actually gets invoked BEFORE the 'exceptionCaught' method of 'ClientInboundHandler'. This is what lead be to the decision to completely remove the listener all together.

@scottweaver
Copy link
Contributor Author

scottweaver commented Jan 9, 2025

Well, I "fixed" some of the mima compat issues in my local env.

Unroll is working fine for requestOnChannel, however, it fails to rewrite ZClient.Config with a compiler crash.

I am wondering if Unroll doesn't like the nested case class?

Nvm, user error. I forgot to include the default value :(

@@ -35,6 +35,7 @@ private[netty] final class ClientInboundHandler(
jReq: HttpRequest,
onResponse: Promise[Throwable, Response],
onComplete: Promise[Throwable, ChannelState],
onFailure: Promise[Nothing, Throwable],
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is this Promise used? I can't find any usage of await or poll on it, so AFAICT we're only completing it without really using it?

Comment on lines -76 to -82
val closeListener: GenericFutureListener[ChannelFuture] = { (_: ChannelFuture) =>
// If onComplete was already set, it means another fiber is already in the process of fulfilling the promises
// so we don't need to fulfill `onResponse`
nettyRuntime.unsafeRunSync {
onComplete.interrupt && onResponse.fail(NettyClientDriver.PrematureChannelClosure)
}(Unsafe.unsafe, trace): Unit
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This existed in order to account for cases that the error is not propagated via the pipeline, e.g., if the server drops the connection unexpectedly or if we errored before reaching the ClientInboundHandler.

Have you tested what happens in those cases? Are we still fulfilling the promises or are we risking the application hanging?

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.

3 participants