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

Manual channel handling in client #111

Open
alexdupre opened this issue Aug 31, 2020 · 4 comments
Open

Manual channel handling in client #111

alexdupre opened this issue Aug 31, 2020 · 4 comments

Comments

@alexdupre
Copy link

Scenario:

  • client consumes multiple services from the same server endpoint
  • client connects concurrently to multiple servers in a dynamic way (number or servers and their ip addresses can change at runtime)
  • rpc calls to each server may span several minutes and fibers
  • connections are established with TLS

I'm quite new to zio and zio-grpc, so I might have missed some obvious things, but as far as I've seen the current implementation is not able to share a channel between two service clients, and doesn't seem to have a friendly way to keep a channel open for more than a use block but not for the entire app. The result is that the overhead in establishing multiple TLS connections (while one persistent connection per server would be enough) becomes evident. With the plain java API and scalapb wrapper this is possible, because the channel can be created/shutdown independently from the client. My current workaround is to use the scalapb async wrapper with IO.fromFuture to have the best from both worlds.

Is my analysis correct? Is this something your are going to improve or should I stick with my workaround?

@thesamet
Copy link
Contributor

Hi @alexdupre , if you want a single channel/client to live for the entire app, you can:

  1. [Recommended: create the client at the top level as a layer using the live method and use the layer in the app as needed.
  2. create the client at the top level using the generated Client.managed, and have your entire app live inside the client's _.use() method.

Having the channel created and shutdown independently from the client can violate resource safety since the client can be called after the channel is shutdown.

You are correct that currently there's no way for two clients to share a single channel, but we can probably change that by introducing a function of the form: ZManagedChannel => Managed[Throwable, (ClientA, ClientB)] - but I'm not sure if it's needed given that each client can have their own dedicated channels if they are singletons.

Let me know if getting the clients created at the top level helps, or I must have misunderstood what you're trying to do.

@alexdupre
Copy link
Author

As far as I've understood the use of the layer with live (and similarly your second alternative with managed) is ok if you need to connect to a single server, ie. there is a static 1:1 service/server relationship. In that case each service would have its own channel, but the same channels are used in the entire application.

In my case I have a dynamic set of servers (all implementing the same set of services) and I need to connect to a different subset of them from time to time, so I need a dynamic set of clients. The sub-optimal things I'm seeing are two:

  1. the channel cannot be shared between services, so each service establishes a new TLS connection...the introduction of the function you proposed may help
  2. even if the server has long idle timeout, the connection is dropped by the client at the end of the _.use() method, so each use block establishes a new connection...and I cannot create the client at the top application level because there is a set of servers that continuously changes at runtime.

What I'm probably looking for at a higher abstraction level is a sort of channel manager that all service clients can use.

@thesamet
Copy link
Contributor

thesamet commented Aug 31, 2020

A single channel can represent a set of underlying TLS connections that change over time, see Java docs. You can implement your own Channel interface that switches between servers as you need and shares the underlying TCP connection.

In other words, a single Channel and a single Client created as a top level layer can still end up talking to any number of servers which you can freely control.

@alexdupre
Copy link
Author

A single channel can be used to communicate with multiple servers in a load-balancing or fail-over scenario, it doesn't seem the right way to communicate with different servers when you need to target a specific one (ie. when each server is a separate entity with different state).

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

No branches or pull requests

2 participants