2121import google .cloud .bigtable_v2 .types .bigtable as types_pb
2222import google .cloud .bigtable .data .exceptions as bt_exceptions
2323from google .cloud .bigtable .data ._helpers import _attempt_timeout_generator
24- from google .cloud .bigtable .data ._metrics import tracked_retry
24+ from google .cloud .bigtable .data ._helpers import _retry_exception_factory
2525
2626# mutate_rows requests are limited to this number of mutations
2727from google .cloud .bigtable .data .mutations import _MUTATE_ROWS_REQUEST_MUTATION_LIMIT
3131
3232if TYPE_CHECKING :
3333 from google .cloud .bigtable .data .mutations import RowMutationEntry
34- from google .cloud .bigtable .data ._metrics import ActiveOperationMetric
3534
3635 if CrossSync .is_async :
3736 from google .cloud .bigtable_v2 .services .bigtable .async_client import (
@@ -69,8 +68,6 @@ class _MutateRowsOperationAsync:
6968 operation_timeout: the timeout to use for the entire operation, in seconds.
7069 attempt_timeout: the timeout to use for each mutate_rows attempt, in seconds.
7170 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
7471 """
7572
7673 @CrossSync .convert
@@ -81,7 +78,6 @@ def __init__(
8178 mutation_entries : list ["RowMutationEntry" ],
8279 operation_timeout : float ,
8380 attempt_timeout : float | None ,
84- metric : ActiveOperationMetric ,
8581 retryable_exceptions : Sequence [type [Exception ]] = (),
8682 ):
8783 # check that mutations are within limits
@@ -101,12 +97,13 @@ def __init__(
10197 # Entry level errors
10298 bt_exceptions ._MutateRowsIncomplete ,
10399 )
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 ,
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 ,
110107 )
111108 # initialize state
112109 self .timeout_generator = _attempt_timeout_generator (
@@ -115,8 +112,6 @@ def __init__(
115112 self .mutations = [_EntryWithProto (m , m ._to_pb ()) for m in mutation_entries ]
116113 self .remaining_indices = list (range (len (self .mutations )))
117114 self .errors : dict [int , list [Exception ]] = {}
118- # set up metrics
119- self ._operation_metric = metric
120115
121116 @CrossSync .convert
122117 async def start (self ):
@@ -126,35 +121,34 @@ async def start(self):
126121 Raises:
127122 MutationsExceptionGroup: if any mutations failed
128123 """
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 )
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"
157139 )
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+ )
158152
159153 @CrossSync .convert
160154 async def _run_attempt (self ):
@@ -166,8 +160,6 @@ async def _run_attempt(self):
166160 retry after the attempt is complete
167161 GoogleAPICallError: if the gapic rpc fails
168162 """
169- # register attempt start
170- self ._operation_metric .start_attempt ()
171163 request_entries = [self .mutations [idx ].proto for idx in self .remaining_indices ]
172164 # track mutations in this request that have not been finalized yet
173165 active_request_indices = {
0 commit comments