grpc / grpc-dart

The Dart language implementation of gRPC.
https://pub.dev/packages/grpc
Apache License 2.0
861 stars 271 forks source link

ClientChannel has no way to trigger a connection to the server if no RPC is being invoked #723

Open eladm-ultrawis opened 4 months ago

eladm-ultrawis commented 4 months ago

When using grpc C++, creating a channel immediately creates a connection to the server. I can monitor the ConnectionState and make sure I have a valid connection to the server.

However, when using dart, I could not find a way to force the channel to connect.

 GrpcClient() : channel = createChannel() {
    stub = ultraproto.TelemetryServiceClient(channel);
    // this is never triggered!
    channel.onConnectionStateChanged
        .listen((event) => onConnectionStateChanged(event));

It seems that unless I am explicitly call to one of the stub RPC methods, the channel onConnectionStateChanged event is never triggered.

Questions:

  1. Is this a bug?
  2. Is this behavior documented somewhere?
  3. is there a way to force the channel to connect?
mosuem commented 4 months ago

The method createCall on the ClientChannel is what creates a connection - so as long as you don't send a request, the connection is not established, so no state changes to it can be recorded.

To answer your questions:

  1. No, I would say this is expected behavior. If you have arguments to establish a connection first, I am open to discuss or review a PR.
  2. No, it is not. I was looking into the spec, but it doesn't really say much about this. Even exposing the connection state is an optional feature, and not implemented in all languages.
  3. Sending a request. If you control both sides, maybe add an empty testConnection service to the proto definition?
eladm-ultrawis commented 4 months ago

@mosuem thanks for the answer.

I think there are arguments in favor of being able to trigger a channel to connect.

My experience with the C++ implementation of grpc is that once you create a channel, the channel is the connection. you do not have to do anything in order to make it connect or recover from a lost connection. I am not saying this must be the default behavior, but that we should have the following:

  1. a channel option to make the channel connect automatically upon creation
  2. a channel option to automatically recover from a lost connection
  3. connect / disconnect methods
mosuem commented 4 months ago

In our case the server is not always available. And when it becomes available, we would like to react by initiating a bunch of requests.

This would mean more than just connecting on channel creation - it means periodically sending requests, checking if one goes through, and then doing something.

When the server is lost, it seems that the channel does not recover the connection automatically. we have to trigger a request in order to recover.

Again, this means that the connection needs to be tested somehow. Maybe KEEPALIVE pings might help with your use case? Otherwise, I still think that having a special message in your protocol could solve this.

eladm-ultrawis commented 4 months ago

@mosuem I have the keep alive mechanism in place, but still no recovery in case we have a lost connection. I currently implement a special (dummy) message to trigger recovery, but it feels a bit hacky. I believe this aspect of the API should be at least documented as I learned about this the hard way.

mosuem commented 4 months ago

More documentation is always better! Could you send a PR? I am happy to review it.