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

Commit 54655d4

Browse files
committed
Revert "removed read_rows and mutate_rows instrumentation"
This reverts commit d3a9013.
1 parent ced3ee3 commit 54655d4

20 files changed

Lines changed: 2936 additions & 446 deletions

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

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import google.cloud.bigtable_v2.types.bigtable as types_pb
2222
import google.cloud.bigtable.data.exceptions as bt_exceptions
2323
from google.cloud.bigtable.data._helpers import _attempt_timeout_generator
24-
from google.cloud.bigtable.data._helpers import _retry_exception_factory
24+
from google.cloud.bigtable.data._metrics import tracked_retry
2525

2626
# mutate_rows requests are limited to this number of mutations
2727
from google.cloud.bigtable.data.mutations import _MUTATE_ROWS_REQUEST_MUTATION_LIMIT
@@ -31,6 +31,7 @@
3131

3232
if TYPE_CHECKING:
3333
from google.cloud.bigtable.data.mutations import RowMutationEntry
34+
from google.cloud.bigtable.data._metrics import ActiveOperationMetric
3435

3536
if CrossSync.is_async:
3637
from google.cloud.bigtable_v2.services.bigtable.async_client import (
@@ -68,6 +69,8 @@ class _MutateRowsOperationAsync:
6869
operation_timeout: the timeout to use for the entire operation, in seconds.
6970
attempt_timeout: the timeout to use for each mutate_rows attempt, in seconds.
7071
If not specified, the request will run until operation_timeout is reached.
72+
metric: the metric object representing the active operation
73+
retryable_exceptions: a list of exceptions that should be retried
7174
"""
7275

7376
@CrossSync.convert
@@ -78,6 +81,7 @@ def __init__(
7881
mutation_entries: list["RowMutationEntry"],
7982
operation_timeout: float,
8083
attempt_timeout: float | None,
84+
metric: ActiveOperationMetric,
8185
retryable_exceptions: Sequence[type[Exception]] = (),
8286
):
8387
# check that mutations are within limits
@@ -97,13 +101,12 @@ def __init__(
97101
# Entry level errors
98102
bt_exceptions._MutateRowsIncomplete,
99103
)
100-
sleep_generator = retries.exponential_sleep_generator(0.01, 2, 60)
101-
self._operation = lambda: CrossSync.retry_target(
102-
self._run_attempt,
103-
self.is_retryable,
104-
sleep_generator,
105-
operation_timeout,
106-
exception_factory=_retry_exception_factory,
104+
self._operation = lambda: tracked_retry(
105+
retry_fn=CrossSync.retry_target,
106+
operation=metric,
107+
target=self._run_attempt,
108+
predicate=self.is_retryable,
109+
timeout=operation_timeout,
107110
)
108111
# initialize state
109112
self.timeout_generator = _attempt_timeout_generator(
@@ -112,6 +115,8 @@ def __init__(
112115
self.mutations = [_EntryWithProto(m, m._to_pb()) for m in mutation_entries]
113116
self.remaining_indices = list(range(len(self.mutations)))
114117
self.errors: dict[int, list[Exception]] = {}
118+
# set up metrics
119+
self._operation_metric = metric
115120

116121
@CrossSync.convert
117122
async def start(self):
@@ -121,34 +126,35 @@ async def start(self):
121126
Raises:
122127
MutationsExceptionGroup: if any mutations failed
123128
"""
124-
try:
125-
# trigger mutate_rows
126-
await self._operation()
127-
except Exception as exc:
128-
# exceptions raised by retryable are added to the list of exceptions for all unfinalized mutations
129-
incomplete_indices = self.remaining_indices.copy()
130-
for idx in incomplete_indices:
131-
self._handle_entry_error(idx, exc)
132-
finally:
133-
# raise exception detailing incomplete mutations
134-
all_errors: list[Exception] = []
135-
for idx, exc_list in self.errors.items():
136-
if len(exc_list) == 0:
137-
raise core_exceptions.ClientError(
138-
f"Mutation {idx} failed with no associated errors"
129+
with self._operation_metric:
130+
try:
131+
# trigger mutate_rows
132+
await self._operation()
133+
except Exception as exc:
134+
# exceptions raised by retryable are added to the list of exceptions for all unfinalized mutations
135+
incomplete_indices = self.remaining_indices.copy()
136+
for idx in incomplete_indices:
137+
self._handle_entry_error(idx, exc)
138+
finally:
139+
# raise exception detailing incomplete mutations
140+
all_errors: list[Exception] = []
141+
for idx, exc_list in self.errors.items():
142+
if len(exc_list) == 0:
143+
raise core_exceptions.ClientError(
144+
f"Mutation {idx} failed with no associated errors"
145+
)
146+
elif len(exc_list) == 1:
147+
cause_exc = exc_list[0]
148+
else:
149+
cause_exc = bt_exceptions.RetryExceptionGroup(exc_list)
150+
entry = self.mutations[idx].entry
151+
all_errors.append(
152+
bt_exceptions.FailedMutationEntryError(idx, entry, cause_exc)
153+
)
154+
if all_errors:
155+
raise bt_exceptions.MutationsExceptionGroup(
156+
all_errors, len(self.mutations)
139157
)
140-
elif len(exc_list) == 1:
141-
cause_exc = exc_list[0]
142-
else:
143-
cause_exc = bt_exceptions.RetryExceptionGroup(exc_list)
144-
entry = self.mutations[idx].entry
145-
all_errors.append(
146-
bt_exceptions.FailedMutationEntryError(idx, entry, cause_exc)
147-
)
148-
if all_errors:
149-
raise bt_exceptions.MutationsExceptionGroup(
150-
all_errors, len(self.mutations)
151-
)
152158

153159
@CrossSync.convert
154160
async def _run_attempt(self):
@@ -160,6 +166,8 @@ async def _run_attempt(self):
160166
retry after the attempt is complete
161167
GoogleAPICallError: if the gapic rpc fails
162168
"""
169+
# register attempt start
170+
self._operation_metric.start_attempt()
163171
request_entries = [self.mutations[idx].proto for idx in self.remaining_indices]
164172
# track mutations in this request that have not been finalized yet
165173
active_request_indices = {

0 commit comments

Comments
 (0)