Skip to content

Commit 1d0cf93

Browse files
committed
refactor: Give the spec's attempts name to the counter that drives the delay
The exponent driver was _n and a second counter held the name attempts, which is what Requirement 1.4.1 calls the exponent driver. A reviewer reading self.attempts against the spec was reading the wrong field. The second counter is gone. It had no reader outside tests, not even a logger, and every test that used it recorded only normal failures -- where the two counters are equal by construction.
1 parent cd3dd63 commit 1d0cf93

2 files changed

Lines changed: 8 additions & 11 deletions

File tree

‎ldclient/impl/retry.py‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ class RetryState:
140140
Tracks how long a data source should wait before its next attempt.
141141
142142
A failure moves the state on and decides the next wait, which
143-
:attr:`next_delay` reports. The delay for attempt ``n`` is
144-
``min(min_delay * 2 ** (n - 1), max_delay)``, less a random jitter of up to
145-
half of it, and never less than the operating cadence.
143+
:attr:`next_delay` reports. The delay is
144+
``min(min_delay * 2 ** (attempts - 1), max_delay)``, less a random jitter
145+
of up to half of it, and never less than the operating cadence.
146146
147147
An unexpected failure moves the state to the extended regime, which raises
148148
both delay bounds. The bounds stay raised until the reset condition is met,
@@ -179,11 +179,10 @@ def __init__(
179179
self._reset_policy = reset_policy
180180
self._operating_cadence = operating_cadence
181181

182-
self._n = 0
182+
self._attempts = 0
183183
self._extended = False
184184
self._min_delay = self._normal_initial_delay
185185
self._max_delay = max(self._normal_ceiling_delay, self._normal_initial_delay)
186-
self._attempts = 0
187186
# Read before any outcome is recorded, this is the ordinary interval.
188187
self._next_delay = self._operating_cadence
189188

@@ -204,7 +203,6 @@ def record_failure(self, kind: FailureKind) -> None:
204203
"""
205204
# Only a time-based policy needs this: nothing runs while a stream is healthy.
206205
self._reset_if_due()
207-
self._attempts += 1
208206
self._reset_policy.note_failure()
209207

210208
if kind is FailureKind.UNEXPECTED and not self._extended:
@@ -215,11 +213,11 @@ def record_failure(self, kind: FailureKind) -> None:
215213
self._extended = True
216214
self._min_delay = self._extended_initial_delay
217215
self._max_delay = max(self._extended_ceiling_delay, self._min_delay)
218-
self._n = 1
216+
self._attempts = 1
219217
else:
220-
self._n += 1
218+
self._attempts += 1
221219

222-
exponent = min(max(self._n - 1, 0), _MAX_BACKOFF_EXPONENT)
220+
exponent = min(max(self._attempts - 1, 0), _MAX_BACKOFF_EXPONENT)
223221
delay = min(self._min_delay * (2**exponent), self._max_delay)
224222
jitter = random.random() * delay / 2
225223

@@ -243,7 +241,6 @@ def _reset_if_due(self) -> None:
243241
the delay bounds to the normal regime."""
244242
if not self._reset_policy.is_satisfied():
245243
return
246-
self._n = 0
247244
self._attempts = 0
248245
self._extended = False
249246
self._min_delay = self._normal_initial_delay

‎ldclient/testing/impl/test_retry.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def test_attempts_counts_every_failure(self):
454454
assert state._attempts == 5
455455

456456
def test_a_reset_starts_the_attempt_count_over(self):
457-
# A reset clears both counters, so the next failure is attempt 1.
457+
# A reset clears the counter, so the next failure is attempt 1.
458458
with frozen_clock() as clock:
459459
state = for_streaming(1)
460460
state.record_failure(NORMAL)

0 commit comments

Comments
 (0)