From e4e9364af42bcab3335e960ea5768fae5ab9885c Mon Sep 17 00:00:00 2001 From: Akshay Joshi Date: Tue, 9 Dec 2025 07:57:16 -0800 Subject: [PATCH] fix: ensure gRPC channel options preserved during channel refresh The BigtableDataClient periodically refreshes its gRPC channel. However, when create_channel() is called during the refresh process, it doesn't include the unlimited message size options that are set during initial channel creation in __init__. This causes responses larger than 4 MB to fail with a ResourceExhausted error post-channel-refresh. --- .../services/bigtable/transports/grpc.py | 13 +++++++++---- .../services/bigtable/transports/grpc_asyncio.py | 9 ++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py b/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py index 8ddbf15a2..178dd6dd5 100644 --- a/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py +++ b/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py @@ -42,6 +42,11 @@ _LOGGER = std_logging.getLogger(__name__) +# Allow for large rows in responses. +GRPC_CLIENT_OPTIONS = [ + ("grpc.max_send_message_length", -1), + ("grpc.max_receive_message_length", -1), +] class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor): # pragma: NO COVER def intercept_unary_unary(self, continuation, client_call_details, request): @@ -256,10 +261,6 @@ def __init__( scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], ) self._interceptor = _LoggingClientInterceptor() @@ -307,6 +308,9 @@ def create_channel( and ``credentials_file`` are passed. """ + if "options" not in kwargs: + kwargs["options"] = GRPC_CLIENT_OPTIONS + return grpc_helpers.create_channel( host, credentials=credentials, @@ -315,6 +319,7 @@ def create_channel( default_scopes=cls.AUTH_SCOPES, scopes=scopes, default_host=cls.DEFAULT_HOST, + options=GRPC_CLIENT_OPTIONS, **kwargs, ) diff --git a/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py b/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py index 3e6b70832..9dd76b181 100644 --- a/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py +++ b/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py @@ -35,7 +35,7 @@ from google.cloud.bigtable_v2.types import bigtable from .base import BigtableTransport, DEFAULT_CLIENT_INFO -from .grpc import BigtableGrpcTransport +from .grpc import BigtableGrpcTransport, GRPC_CLIENT_OPTIONS try: from google.api_core import client_logging # type: ignore @@ -163,6 +163,9 @@ def create_channel( aio.Channel: A gRPC AsyncIO channel object. """ + if "options" not in kwargs: + kwargs["options"] = GRPC_CLIENT_OPTIONS + return grpc_helpers_async.create_channel( host, credentials=credentials, @@ -306,10 +309,6 @@ def __init__( scopes=self._scopes, ssl_credentials=self._ssl_channel_credentials, quota_project_id=quota_project_id, - options=[ - ("grpc.max_send_message_length", -1), - ("grpc.max_receive_message_length", -1), - ], ) self._interceptor = _LoggingClientAIOInterceptor()