Python Retry and Logging Lab
Practice bounded retries with deterministic failures, backoff, and testable logging.
Prerequisites
Know functions, exceptions, and logging from the production scripting bridge. This simulation uses only Python and makes no network calls.
Sample input and task
A fake service raises ConnectionError twice, then returns ok. Allow four total attempts, wait 0.1 then 0.2 seconds between the first three attempts, and log each failure. Propagate unrelated errors immediately.
Expected output
Warnings indicate attempts 1 and 2 failed, then stdout prints ok. No sleep follows success or the last failure. Four total attempts means one original call and at most three retries.
Hint
Pass the operation and sleep function as arguments. Catch only the simulated transient failure and re-raise when the attempt budget is exhausted.Show solution
import logging
import time
def run_with_retry(operation, max_attempts=4, base_delay=0.1, sleep=time.sleep):
if max_attempts < 1 or base_delay < 0:
raise ValueError("Invalid retry configuration")
for attempt in range(1, max_attempts + 1):
try:
return operation()
except ConnectionError:
if attempt == max_attempts:
logging.error("attempt=%d exhausted=true", attempt)
raise
delay = min(base_delay * 2 ** (attempt - 1), 5.0)
logging.warning("attempt=%d retry_in=%.2f", attempt, delay)
sleep(delay)
def main():
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
outcomes = iter([ConnectionError("temporary"), ConnectionError("temporary"), "ok"])
def fake_call():
result = next(outcomes)
if isinstance(result, Exception):
raise result
return result
print(run_with_retry(fake_call))
if __name__ == "__main__":
main()
Check your work
Replace sleep with delays.append, where delays = [], to test without waiting.
| Operation | Expected result |
|---|---|
| Immediate success | One call; no sleeps. |
| Two failures then success | Three calls; delays [0.1, 0.2]. |
| Always ConnectionError | Four calls; three sleeps; exception propagates. |
| ValueError | One call; no sleeps; exception propagates. |
| Zero attempt budget | Configuration error before any call. |
Challenge and production connection
Add bounded jitter and test delay ranges instead of exact values. For a real service, use the client’s exception types and timeouts. Retrying writes requires an idempotency strategy.
For boto3, use SDK retries instead of wrapping them in this simulation: nested policies multiply attempts. The sample logs key/value text; extend it to JSON if your log collector requires JSON events.
Continue to request pacing.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form