Open alexdupre opened 4 years ago
Hi @alexdupre , if you want a single channel/client to live for the entire app, you can:
live
method and use the layer in the app as needed.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.
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.
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.
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).
Scenario:
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 withIO.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?