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

Commit f9dab5d

Browse files
committed
turned backoff_generator into a class
1 parent 10ef5d1 commit f9dab5d

2 files changed

Lines changed: 26 additions & 17 deletions

File tree

google/cloud/bigtable/data/_helpers.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,32 @@ def _attempt_timeout_generator(
9898
yield max(0, min(per_request_timeout, deadline - time.monotonic()))
9999

100100

101-
def backoff_generator(initial=0.01, multiplier=2, maximum=60):
101+
class BackoffGenerator:
102102
"""
103-
Build a generator for exponential backoff sleep times.
103+
Generator class for exponential backoff sleep times.
104104
105105
This implementation builds on top of api_core.retries.exponential_sleep_generator,
106-
adding the ability to retrieve previous values using the send(idx) method. This is
107-
used by the Metrics class to track the sleep times used for each attempt.
106+
adding the ability to retrieve previous values using get_attempt_backoff(idx).
107+
This is used by the Metrics class to track the sleep times used for each attempt.
108108
"""
109-
history = []
110-
subgenerator = exponential_sleep_generator(initial, multiplier, maximum)
111-
while True:
112-
next_backoff = next(subgenerator)
113-
history.append(next_backoff)
114-
sent_idx = yield next_backoff
115-
while sent_idx is not None:
116-
# requesting from history
117-
sent_idx = yield history[sent_idx]
109+
110+
def __init__(self, initial=0.01, multiplier=2, maximum=60):
111+
self.history = []
112+
self.subgenerator = exponential_sleep_generator(initial, multiplier, maximum)
113+
114+
def __iter__(self):
115+
return self
116+
117+
def __next__(self) -> float:
118+
next_backoff = next(self.subgenerator)
119+
self.history.append(next_backoff)
120+
return next_backoff
121+
122+
def get_attempt_backoff(self, attempt_idx) -> float:
123+
"""
124+
returns the backoff time for a specific attempt index, starting at 0.
125+
"""
126+
return self.history[attempt_idx]
118127

119128

120129
def _retry_exception_factory(

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
if TYPE_CHECKING:
3333
from google.cloud.bigtable.data._metrics.handlers._base import MetricsHandler
34+
from google.cloud.bigtable.data._helpers import BackoffGenerator
3435

3536

3637
LOGGER = logging.getLogger(__name__)
@@ -138,7 +139,7 @@ class ActiveOperationMetric:
138139
"""
139140

140141
op_type: OperationType
141-
backoff_generator: Generator[float, int, None] | None = None
142+
backoff_generator: BackoffGenerator | None = None
142143
# keep monotonic timestamps for active operations
143144
start_time_ns: int = field(default_factory=time.monotonic_ns)
144145
active_attempt: ActiveAttemptMetric | None = None
@@ -192,9 +193,8 @@ def start_attempt(self) -> None:
192193
if self.backoff_generator and len(self.completed_attempts) > 0:
193194
# find the attempt's backoff by sending attempt number to generator
194195
# generator will return the backoff time in seconds, so convert to nanoseconds
195-
backoff_ns = int(
196-
self.backoff_generator.send(len(self.completed_attempts) - 1) * 1e9
197-
)
196+
backoff = self.backoff_generator.get_attempt_backoff(len(self.completed_attempts) - 1)
197+
backoff_ns = int(backoff * 1e9)
198198
else:
199199
backoff_ns = 0
200200

0 commit comments

Comments
 (0)