1717
1818import time
1919from functools import wraps
20- from grpc import StatusCode
2120
2221from google .cloud .bigtable .data ._metrics .data_model import ActiveOperationMetric
2322from google .cloud .bigtable .data ._metrics .data_model import OperationState
@@ -63,21 +62,28 @@ def wrapper(self, continuation, client_call_details, request):
6362
6463 return wrapper
6564
65+
6666@CrossSync .convert
67- async def _get_metadata (source ) -> dict [str , str | bytes ] | None :
67+ async def _get_metadata (source ) -> dict [str , str | bytes ] | None :
6868 """Helper to extract metadata from a call or RpcError"""
6969 try :
7070 if CrossSync .is_async :
7171 # grpc.aio returns metadata in Metadata objects
7272 if isinstance (source , AioRpcError ):
73- metadata = list (source .trailing_metadata ()) + list (source .initial_metadata ())
73+ metadata = list (source .trailing_metadata ()) + list (
74+ source .initial_metadata ()
75+ )
7476 else :
75- metadata = list (await source .trailing_metadata ()) + list (await source .initial_metadata ())
77+ metadata = list (await source .trailing_metadata ()) + list (
78+ await source .initial_metadata ()
79+ )
7680 else :
7781 # sync grpc returns metadata as a sequence of tuples
78- metadata : Sequence [tuple [str . str | bytes ]] = source .trailing_metadata () + source .initial_metadata ()
82+ metadata : Sequence [tuple [str .str | bytes ]] = (
83+ source .trailing_metadata () + source .initial_metadata ()
84+ )
7985 # convert metadata to dict format
80- return {k :v for k ,v in metadata }
86+ return {k : v for k , v in metadata }
8187 except Exception :
8288 # ignore errors while fetching metadata
8389 return None
@@ -96,6 +102,12 @@ class AsyncBigtableMetricsInterceptor(
96102 async def intercept_unary_unary (
97103 self , operation , continuation , client_call_details , request
98104 ):
105+ """
106+ Interceptor for unary rpcs:
107+ - MutateRow
108+ - CheckAndMutateRow
109+ - ReadModifyWriteRow
110+ """
99111 metadata = None
100112 try :
101113 call = await continuation (client_call_details , request )
@@ -113,36 +125,49 @@ async def intercept_unary_unary(
113125 async def intercept_unary_stream (
114126 self , operation , continuation , client_call_details , request
115127 ):
116- async def response_wrapper (call ):
117- # only track has_first response for READ_ROWS
118- has_first_response = (
119- operation .first_response_latency_ns is not None
120- or operation .op_type != OperationType .READ_ROWS
121- )
122- encountered_exc = None
123- try :
124- async for response in call :
125- # record time to first response. Currently only used for READ_ROWs
126- if not has_first_response :
127- operation .first_response_latency_ns = (
128- time .monotonic_ns () - operation .start_time_ns
129- )
130- has_first_response = True
131- yield response
132- except Exception as e :
133- # handle errors while processing stream
134- encountered_exc = e
135- raise
136- finally :
137- if call is not None :
138- metadata = await _get_metadata (encountered_exc or call )
139- if metadata is not None :
140- operation .add_response_metadata (metadata )
141-
128+ """
129+ Interceptor for streaming rpcs:
130+ - ReadRows
131+ - MutateRows
132+ - SampleRowKeys
133+ """
142134 try :
143- return response_wrapper (await continuation (client_call_details , request ))
135+ return self ._streaming_generator_wrapper (
136+ operation , await continuation (client_call_details , request )
137+ )
144138 except Exception as rpc_error :
145139 metadata = await _get_metadata (rpc_error )
146140 if metadata is not None :
147141 operation .add_response_metadata (metadata )
148142 raise rpc_error
143+
144+ @staticmethod
145+ @CrossSync .convert
146+ async def _streaming_generator_wrapper (operation , call ):
147+ """
148+ Wrapped generator to be returned by intercept_unary_stream
149+ """
150+ # only track has_first response for READ_ROWS
151+ has_first_response = (
152+ operation .first_response_latency_ns is not None
153+ or operation .op_type != OperationType .READ_ROWS
154+ )
155+ encountered_exc = None
156+ try :
157+ async for response in call :
158+ # record time to first response. Currently only used for READ_ROWs
159+ if not has_first_response :
160+ operation .first_response_latency_ns = (
161+ time .monotonic_ns () - operation .start_time_ns
162+ )
163+ has_first_response = True
164+ yield response
165+ except Exception as e :
166+ # handle errors while processing stream
167+ encountered_exc = e
168+ raise
169+ finally :
170+ if call is not None :
171+ metadata = await _get_metadata (encountered_exc or call )
172+ if metadata is not None :
173+ operation .add_response_metadata (metadata )
0 commit comments