Failsafe retry with bug fix: reset attempts between calls

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: attempts is instance state that persists across calls. Either reset at the top of execute or 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.

Run: failsafe retry