Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 253284f

Browse files
committed
replace custom metadata with contextvars
2 parents 1d26452 + d9de44d commit 253284f

11 files changed

Lines changed: 38 additions & 315 deletions

File tree

google/cloud/bigtable/data/_async/_mutate_rows.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ async def _run_attempt(self):
188188
),
189189
timeout=next(self.timeout_generator),
190190
retry=None,
191-
metadata=[self._operation_metric.interceptor_metadata],
192191
)
193192
async for result_list in result_generator:
194193
for result in result_list.entries:

google/cloud/bigtable/data/_async/_read_rows.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ def _read_rows_attempt(self) -> CrossSync.Iterable[Row]:
159159
self.request,
160160
timeout=next(self.attempt_timeout_gen),
161161
retry=None,
162-
metadata=[self._operation_metric.interceptor_metadata],
163162
)
164163
chunked_stream = self.chunk_stream(gapic_stream)
165164
return self.merge_rows(chunked_stream)

google/cloud/bigtable/data/_async/client.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,6 @@ def __init__(
972972
)
973973

974974
self._metrics = BigtableClientSideMetricsController(
975-
client._metrics_interceptor,
976975
handlers=[],
977976
project_id=self.client.project,
978977
instance_id=instance_id,
@@ -1382,7 +1381,6 @@ async def execute_rpc():
13821381
),
13831382
timeout=next(attempt_timeout_gen),
13841383
retry=None,
1385-
metadata=[operation_metric.interceptor_metadata],
13861384
)
13871385
return [(s.row_key, s.offset_bytes) async for s in results]
13881386

@@ -1519,7 +1517,6 @@ async def mutate_row(
15191517
),
15201518
timeout=attempt_timeout,
15211519
retry=None,
1522-
metadata=[operation_metric.interceptor_metadata],
15231520
)
15241521
return await CrossSync.retry_target(
15251522
target,
@@ -1657,7 +1654,6 @@ async def check_and_mutate_row(
16571654
),
16581655
timeout=operation_timeout,
16591656
retry=None,
1660-
metadata=[op.interceptor_metadata],
16611657
)
16621658
return result.predicate_matched
16631659

@@ -1712,7 +1708,6 @@ async def read_modify_write_row(
17121708
),
17131709
timeout=operation_timeout,
17141710
retry=None,
1715-
metadata=[op.interceptor_metadata],
17161711
)
17171712
# construct Row from result
17181713
return Row._from_pb(result.row)

google/cloud/bigtable/data/_async/metrics_interceptor.py

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
from functools import wraps
2020
from grpc import StatusCode
2121

22-
from google.cloud.bigtable.data._metrics.data_model import (
23-
OPERATION_INTERCEPTOR_METADATA_KEY,
24-
)
2522
from google.cloud.bigtable.data._metrics.data_model import ActiveOperationMetric
2623
from google.cloud.bigtable.data._metrics.data_model import OperationState
2724
from google.cloud.bigtable.data._metrics.data_model import OperationType
@@ -49,22 +46,8 @@ def _with_operation_from_metadata(func):
4946

5047
@wraps(func)
5148
def wrapper(self, continuation, client_call_details, request):
52-
found_operation_id: str | None = None
53-
try:
54-
new_metadata: list[tuple[str, str]] = []
55-
if client_call_details.metadata:
56-
# find operation key from metadata
57-
for k, v in client_call_details.metadata:
58-
if k == OPERATION_INTERCEPTOR_METADATA_KEY:
59-
found_operation_id = v
60-
else:
61-
new_metadata.append((k, v))
62-
# update client_call_details to drop the operation key metadata
63-
client_call_details.metadata = new_metadata
64-
except Exception:
65-
pass
66-
67-
operation: "ActiveOperationMetric" = self.operation_map.get(found_operation_id)
49+
operation: "ActiveOperationMetric" | None = ActiveOperationMetric.get_active()
50+
6851
if operation:
6952
# start a new attempt if not started
7053
if (
@@ -108,31 +91,6 @@ class AsyncBigtableMetricsInterceptor(
10891
An async gRPC interceptor to add client metadata and print server metadata.
10992
"""
11093

111-
def __init__(self):
112-
super().__init__()
113-
self.operation_map = {}
114-
115-
def register_operation(self, operation):
116-
"""
117-
Register an operation object to be tracked my the interceptor
118-
119-
When registered, the operation will receive metadata updates:
120-
- start_attempt if attempt not started when rpc is being sent
121-
- add_response_metadata after call is complete
122-
123-
The interceptor will register itself as a handeler for the operation,
124-
so it can unregister the operation when it is complete
125-
"""
126-
self.operation_map[operation.uuid] = operation
127-
operation.handlers.append(self)
128-
129-
def on_operation_complete(self, op):
130-
if op.uuid in self.operation_map:
131-
del self.operation_map[op.uuid]
132-
133-
def on_operation_cancelled(self, op):
134-
self.on_operation_complete(op)
135-
13694
@CrossSync.convert
13795
@_with_operation_from_metadata
13896
async def intercept_unary_unary(

google/cloud/bigtable/data/_async/mutations_batcher.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ async def add_to_flow_with_metrics(
195195
try:
196196
value = await inner_generator.__anext__()
197197
except CrossSync.StopIteration:
198-
metric.cancel()
199198
return
200199
metric.flow_throttling_time_ns = time.monotonic_ns() - flow_start_time
201200
yield value, metric

google/cloud/bigtable/data/_metrics/data_model.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
# limitations under the License.
1414
from __future__ import annotations
1515

16-
from typing import Tuple, cast, TYPE_CHECKING
16+
from typing import ClassVar, Tuple, cast, TYPE_CHECKING
17+
1718

1819
import time
1920
import re
2021
import logging
2122
import uuid
23+
import contextvars
2224

2325
from enum import Enum
2426
from functools import lru_cache
@@ -54,8 +56,6 @@
5456

5557
INVALID_STATE_ERROR = "Invalid state for {}: {}"
5658

57-
OPERATION_INTERCEPTOR_METADATA_KEY = "x-goog-operation-key"
58-
5959

6060
class OperationType(Enum):
6161
"""Enum for the type of operation being performed."""
@@ -169,14 +169,12 @@ class ActiveOperationMetric:
169169
# time waiting on flow control, in nanoseconds
170170
flow_throttling_time_ns: int = 0
171171

172-
@property
173-
def interceptor_metadata(self) -> tuple[str, str]:
174-
"""
175-
returns a tuple to attach to the grpc metadata.
176172

177-
This metadata field will be read by the BigtableMetricsInterceptor to associate a request with an operation
178-
"""
179-
return OPERATION_INTERCEPTOR_METADATA_KEY, self.uuid
173+
_active_operation_context: ClassVar[contextvars.ContextVar] = contextvars.ContextVar("active_operation_context")
174+
175+
@classmethod
176+
def get_active(cls):
177+
return cls._active_operation_context.get(None)
180178

181179
@property
182180
def state(self) -> OperationState:
@@ -190,6 +188,9 @@ def state(self) -> OperationState:
190188
else:
191189
return OperationState.ACTIVE_ATTEMPT
192190

191+
def __post_init__(self):
192+
self._active_operation_context.set(self)
193+
193194
def start(self) -> None:
194195
"""
195196
Optionally called to mark the start of the operation. If not called,
@@ -200,6 +201,7 @@ def start(self) -> None:
200201
if self.state != OperationState.CREATED:
201202
return self._handle_error(INVALID_STATE_ERROR.format("start", self.state))
202203
self.start_time_ns = time.monotonic_ns()
204+
self._active_operation_context.set(self)
203205

204206
def start_attempt(self) -> ActiveAttemptMetric | None:
205207
"""
@@ -214,6 +216,7 @@ def start_attempt(self) -> ActiveAttemptMetric | None:
214216
return self._handle_error(
215217
INVALID_STATE_ERROR.format("start_attempt", self.state)
216218
)
219+
self._active_operation_context.set(self)
217220

218221
try:
219222
# find backoff value before this attempt
@@ -365,13 +368,6 @@ def end_with_success(self):
365368
"""
366369
return self.end_with_status(StatusCode.OK)
367370

368-
def cancel(self):
369-
"""
370-
Called to cancel an operation without processing emitting it.
371-
"""
372-
for handler in self.handlers:
373-
handler.on_operation_cancelled(self)
374-
375371
@staticmethod
376372
def _exc_to_status(exc: BaseException) -> StatusCode:
377373
"""

google/cloud/bigtable/data/_metrics/handlers/_base.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ def __init__(self, **kwargs):
2929
def on_operation_complete(self, op: CompletedOperationMetric) -> None:
3030
pass
3131

32-
def on_operation_cancelled(self, op: ActiveOperationMetric) -> None:
33-
pass
34-
3532
def on_attempt_complete(
3633
self, attempt: CompletedAttemptMetric, op: ActiveOperationMetric
3734
) -> None:

google/cloud/bigtable/data/_metrics/metrics_controller.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class BigtableClientSideMetricsController:
3838

3939
def __init__(
4040
self,
41-
interceptor: AsyncBigtableMetricsInterceptor | BigtableMetricsInterceptor,
4241
handlers: list[MetricsHandler] | None = None,
4342
**kwargs,
4443
):
@@ -50,12 +49,7 @@ def __init__(
5049
- handlers: A list of MetricsHandler objects to subscribe to metrics events.
5150
- **kwargs: Optional arguments to pass to the metrics handlers.
5251
"""
53-
self.interceptor = interceptor
5452
self.handlers: list[MetricsHandler] = handlers or []
55-
if handlers is None:
56-
# handlers not given. Use default handlers.
57-
# TODO: add default handlers
58-
pass
5953

6054
def add_handler(self, handler: MetricsHandler) -> None:
6155
"""
@@ -72,6 +66,4 @@ def create_operation(
7266
"""
7367
Creates a new operation and registers it with the subscribed handlers.
7468
"""
75-
new_op = ActiveOperationMetric(op_type, **kwargs, handlers=self.handlers)
76-
self.interceptor.register_operation(new_op)
77-
return new_op
69+
return ActiveOperationMetric(op_type, **kwargs, handlers=self.handlers)

0 commit comments

Comments
 (0)