NetAuto Academy

Advanced Lab

Refactoring a Flaky Connection Script

Advanced25 min

Objective

Apply dataclasses, a custom exception, and a bounded retry wrapper to a fresh flaky-connection scenario, producing a structured, typed result instead of a print statement.

Builds on Advanced Python Automation for Network Engineers.

Prerequisites

  • Comfortable with @dataclass (Dataclasses, Type Hints, and Custom Exceptions)
  • Comfortable with try/except and raising a custom exception class
Local/offline only. flaky_connect() is a deterministic simulation, not a real network call -- no device or connection of any kind.

Scenario

The problem

Dataclasses, Type Hints, and Custom Exceptions taught you the pieces -- a typed result instead of an ad-hoc dict, a custom exception instead of a bare except:. This lab hands you a genuinely flaky function (not the lesson's own example) and asks you to apply those same pieces from scratch: does it succeed, and if so after how many attempts? If it never succeeds, what actually went wrong?

Starter data

starter.py
# Deterministic flakiness: each hostname fails this many times before
# succeeding (or never, if the count is >= max_attempts).
FAIL_COUNTS = {"SW1": 2, "SW2": 0, "SW3": 5}
_call_counts = {}


def flaky_connect(hostname):
  _call_counts[hostname] = _call_counts.get(hostname, 0) + 1
  attempt = _call_counts[hostname]
  if attempt <= FAIL_COUNTS.get(hostname, 0):
      raise Exception(f"simulated failure on attempt {attempt}")
  return f"connected to {hostname}"

Fixed, deterministic sample data written for this lab -- SW1 fails twice then succeeds, SW2 always succeeds immediately, SW3 fails more times than any reasonable retry budget allows.

Task

flaky_connect() currently raises a bare Exception — replace that with a real custom exception class, DeviceConnectionError.

Write a @dataclass called ConnectionResult with fields: hostname: str, success: bool, attempts: int, error: Optional[str] = None.

Write connect_with_retry(hostname, max_attempts=3) that calls flaky_connect() up to max_attempts times, catching DeviceConnectionError each time. Return a ConnectionResult as soon as it succeeds (recording how many attempts it took); if every attempt fails, return a ConnectionResult with success=False and error set to the last failure's message.

Hints

Expected output

expected output
ConnectionResult(hostname='SW1', success=True, attempts=3, error=None)
ConnectionResult(hostname='SW2', success=True, attempts=1, error=None)
ConnectionResult(hostname='SW3', success=False, attempts=3, error='simulated failure on attempt 3')

Real, verified output with max_attempts=3. SW1 needed all 3 attempts to succeed; SW2 succeeded immediately; SW3 exhausted every attempt and reports the last failure's exact message.

Validation checklist

Self-check only -- nothing here is submitted or graded. Compare against your own output manually.

Solution

Solution

Try the task yourself first -- the full solution and explanation stay hidden until you click above.

Key takeaways

  • A custom exception class, even an empty one, makes the difference between 'catch and handle this specific failure' and 'catch anything and hope.'
  • A dataclass result (hostname, success, attempts, error) survives being logged, compared, and passed around in a way a bare print statement never could.
  • connect_with_retry() returns immediately on the first success -- attempts only grows as high as it actually needed to.
  • flaky_connect() is a deterministic simulation -- no real device or network call was used or required.

Related lessons

Done with this lesson?