Skip to content

fix: disable gRPC client-side load balancing on channels (#33) - #40

Open
Doremi203 wants to merge 1 commit into
yandex-cloud:masterfrom
Doremi203:fix/disable-grpc-load-balancing
Open

fix: disable gRPC client-side load balancing on channels (#33)#40
Doremi203 wants to merge 1 commit into
yandex-cloud:masterfrom
Doremi203:fix/disable-grpc-load-balancing

Conversation

@Doremi203

Copy link
Copy Markdown

Problem

Since Grpc.Net.Client 2.44, gRPC enables client-side load balancing, which routes every call through BalancerHttpHandler. The SDK builds its channels without an explicit HttpClient, so all calls go through the balancer.

In environments where the balancer's connection handling is involved (e.g. behind an HTTP proxy), this breaks and surfaces as either:

  • InvalidOperationException: Unable to get subchannel from HttpRequestMessage, or
  • Grpc.Core.RpcException: Status(StatusCode="Internal", ... HTTP/2 error code 'COMPRESSION_ERROR' (0x9))

The failure happens on the very first call — endpoint discovery via ApiEndpointService (api.cloud.yandex.net) — so the SDK is effectively unusable for any service (Lockbox, etc.) in such environments.

Fixes #33.

Root cause

The SDK always connects to a single resolved endpoint, so gRPC client-side load balancing is unnecessary — but it is on by default in Grpc.Net.Client >= 2.44 whenever the channel is created without an explicit HttpClient.

Fix

Supply an explicit HttpClient to GrpcChannelOptions, which disables client-side load balancing and uses a plain HTTP/2 connection. This is one of the documented workarounds for grpc/grpc-dotnet#2254 and mirrors the fix accepted in the YDB .NET SDK (ydb-platform/ydb-dotnet-sdk#219).

return GrpcChannel.ForAddress($"https://{endpoint}", new GrpcChannelOptions
{
    Credentials = credentials,
    HttpClient = new HttpClient(),
    DisposeHttpClient = true
});

All channels (the API-endpoint channel and every per-service channel) go through this single GetChannel, so the one-line change covers the whole SDK.

Notes / verification

  • The SDK's full build runs a multi-stage code-generation pipeline (protos → Generated.cs) that I couldn't bootstrap locally, so I verified the change by compiling the modified GetChannel against the SDK's transitive Grpc.Net.Client 2.61.0 on netstandard2.0, and by running it end-to-end against Lockbox from a downstream .NET 9 service (the exact HttpClient + GrpcChannelOptions shape), where it resolves the COMPRESSION_ERROR.
  • Credentials (TLS + the auth-token CallCredentials interceptor) is preserved; only the transport handler changes.

I hereby agree to the terms of the CLA available at: https://yandex.ru/legal/cla/?lang=en

Grpc.Net.Client >= 2.44 enables client-side load balancing, which routes
calls through BalancerHttpHandler. Behind an HTTP proxy this breaks and
surfaces as "Unable to get subchannel from HttpRequestMessage" or an
HTTP/2 COMPRESSION_ERROR, making the SDK unusable for any call to Yandex
Cloud (e.g. Lockbox) in such environments.

The SDK always connects to a single resolved endpoint, so load balancing
is unnecessary. Supplying an explicit HttpClient to GrpcChannelOptions
disables it and uses a plain HTTP/2 connection.

Fixes yandex-cloud#33. See grpc/grpc-dotnet#2254; mirrors ydb-platform/ydb-dotnet-sdk#219.
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

Successfully merging this pull request may close these issues.

bug: Grpc requests go via proxy on Grpc.NET.Client >= 2.44

1 participant