grpc / grpc-dart

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

channel.shutdown() depends on race condition? #628

Open wzslr321 opened 1 year ago

wzslr321 commented 1 year ago

grpc package version: 3.1.0

When I create a gRPC call inside try catch block, it randomly can not close the channel and blocks the entire application.

final channel = ClientChannel(
      '192.168.0.100',
      port: 50051,
      options: ChannelOptions(
        credentials: const ChannelCredentials.insecure(),
        codecRegistry:
            CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]),
      ),
    );
final client = UsersClient(channel);

try {
      final response = await client
          .loginUser(
            LoginUserRequest(
              username: email,
              password: password,
            ),
          );

      return right(response);
    } on GrpcError catch (err) {
      if(kDebugMode) {
        debugPrint(err.toString());
      }
      await channel.shutdown(); // blocks here randomly
      return left(const CallFailure.serverError());
    }
}

I tried different variations of this code - initializing response outside of try catch etc. None of these seems to matter - it sometimes close the channel and return failure in catch block, sometimes it just prints error and blocks the application.

It seems similar to race condition to me. I figured out a solution, which seems to be valid, though I still think this design is an issue, and requires a change, or at least some information in documentation.

 try {
      final response = await compute(
        client.loginUser,
        LoginUserRequest(
          username: email,
          password: password,
        ),
      );

      return right(response);
    } on GrpcError catch (err) {
      if (kDebugMode) {
        debugPrint(err.toString());
      }
      return left(const CallFailure.serverError());
    } finally {
      await channel.shutdown();
   }
 }

Running in isolation seems to fix the problem.

Repro steps

  1. step1
  2. step2
  3. step3

Expected result:

Actual result:

Details

<Include any other relevant details, logs, etc.>