Problem. A Failsafe class retries a function up to max_retries times. The buggy version never resets attempts between execute() calls, so a second call fails immediately after the first exhausted retries. Fix it.
Examples:
fs = Failsafe(max_retries=3)
# First call: fn fails 2 times then succeeds → should return result
# Second call: fn succeeds immediately → should return result (not raise)
Solution. Reset self.attempts = 0 at the start of each execute() call.
class Failsafe:
def __init__(self, max_retries):
self.max_retries = max_retries
self.attempts = 0
def execute(self, fn):
self.attempts = 0 # FIX: reset before each call
while self.attempts < self.max_retries:
try:
return fn()
except Exception:
self.attempts += 1
raise Exception("Max retries exceeded")
O(max_retries) per call.
Gotchas.
- The core bug:
attemptsis instance state that persists across calls. Either reset at the top ofexecuteor use a local variable. - Off-by-one: with
max_retries=3, the function is called at most 3 times (attempts 0, 1, 2). If you want 1 initial + 3 retries = 4 total, change the condition to<=. - If
fn()succeeds on the last allowed attempt, it should return the result, not raise. - For exponential backoff, add
time.sleep(2 ** self.attempts * base_delay)inside the except block.