grpc/grpc-dotnet

GrpcChannelOptions: Can't configure HTTP/3 with client load balancing

johncrim opened this issue · 4 comments

What version of gRPC and what language are you using?

C#
Grpc.Net.Client 2.61.0

What operating system (Linux, Windows,...) and version?

Windows 11 + Linux Ubuntu-22.04

What runtime / compiler are you using (e.g. .NET Core SDK version dotnet --info)

targeting .NET 7 on

  dotnet --info
.NET SDK:
 Version:           8.0.202
 Commit:            25674bb2f4
 Workload version:  8.0.200-manifests.8cf8de6d

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22631
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.202\

Host:
  Version:      8.0.3
  Architecture: x64
  Commit:       9f4b1f5d66

.NET SDKs installed:
  6.0.420 [C:\Program Files\dotnet\sdk]
  8.0.202 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

What did you do?

While configuring a GRPC client, trying to use HTTP/3 and a load balancer, I'm not able to configure the GrpcChannelOptions to both use HTTP/3 and the load balancer, b/c it is rejected by GrpcChannel.ValidateHttpHandlerSupportsConnectivity().

Here's the code I'm using:

    private static void ConfigureInternalGrpcChannel(GrpcChannelOptions options)
    {
	    // Setup load balancing
		var serviceConfig = new ServiceConfig();
		serviceConfig.LoadBalancingConfigs.Add(new RoundRobinConfig());
		options.ServiceConfig = serviceConfig;
			
        var httpHandler = new SocketsHttpHandler()
                          {
                              EnableMultipleHttp2Connections = true,
                              SslOptions = new SslClientAuthenticationOptions()
                                           {
                                               // Use internal server cert validation
                                               RemoteCertificateValidationCallback = serverCertValidator.ValidateCertificate,
                                               CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
                                               ClientCertificates = clientCertificateLoader.ClientCertificates.Certificates,
                                               LocalCertificateSelectionCallback = CertificateSelectionAdapter
                                           },
                          };

        options.Credentials = ChannelCredentials.SecureSsl;

        // The only way to specify HTTP/3 is to do it on the HttpClient
        var httpClient = new HttpClient(httpHandler);
        httpClient.DefaultRequestVersion = HttpVersion.Version30;
        httpClient.DefaultVersionPolicy  = HttpVersionPolicy.RequestVersionExact;
        options.HttpClient               = httpClient;
        options.DisposeHttpClient        = true;
    }

What did you expect to see?

GRPC channel successfully connected

What did you see instead?

InvalidOperationException: Channel is configured with an HTTP transport doesn't support client-side load balancing or connectivity state tracking. The underlying HTTP transport must be a SocketsHttpHandler with no SocketsHttpHandler.ConnectCallback configured. The HTTP transport must be configured on the channel using GrpcChannelOptions.HttpHandler. 

System.InvalidOperationException:
   at Grpc.Net.Client.GrpcChannel.ValidateHttpHandlerSupportsConnectivity (Grpc.Net.Client, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad)
   at Grpc.Net.Client.GrpcChannel..ctor (Grpc.Net.Client, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad)
   at Grpc.Net.Client.GrpcChannel.ForAddress (Grpc.Net.Client, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad)

I can certainly skip the new HttpClient() and set options.HttpHandler = httpHandler, but then I don't have a way to specify HTTP/3. Thanks in advance for any suggestions.

Unfortunatly HTTP/3 and client-side load balancing can't be used together.

Thanks for the reply @JamesNK - is that a technological limitation (eg does it also affect other GRPC clients and servers), or a limitation on the .NET libs for now?

It's a limitation of SocketsHttpHandler.

Thanks - your prompt response was amazing, too.