Exercise 3: Which Pattern Actually Fixes the Original Cascading-Call Problem — Possible Solution ==================================================================== RECALLING THE ORIGINAL PROBLEM ------------------------------ Software Architecture Fundamentals Chapter 4 verified service_a calling service_b calling service_c synchronously - when service_c became slow (a real 300ms delay), service_a's own total response time became 300ms too, even though service_a itself never did anything slow. The core problem: service_a was WAITING, synchronously, for a response that took a long time to arrive, with no way to give up early. WHY CIRCUIT BREAKER IS THE MOST DIRECT FIX ------------------------------ This chapter's own circuit breaker addresses EXACTLY this shape of problem: it verified turning a chain of guaranteed-slow calls (10 calls x 0.1s = 1,003.5ms) into mostly-instant failures (301.1ms) once enough failures accumulate to open the circuit. Applied to the original scenario, once service_c's own slowness/failure pattern is detected, service_b's own calls to it would start failing FAST instead of waiting the full 300ms each time - directly attacking the "A waits however long C takes" mechanism that made the original finding possible in the first place. WHY THE OTHER THREE PATTERNS, WHILE USEFUL, DON'T ADDRESS THIS SPECIFIC PROBLEM ------------------------------ Retries with backoff: this pattern controls HOW OFTEN a failing call is retried, spacing attempts out over time. It does nothing to change how long any SINGLE call takes to fail or succeed - service_a would still wait the full 300ms (or the retry's own backoff delay, which is often LONGER) on each individual attempt. Backoff protects a struggling service from being hammered; it doesn't protect a caller from waiting. Bulkheads: this pattern isolates RESOURCE POOLS (connections, threads) so one dependency's own exhaustion doesn't block another, unrelated dependency. The original scenario only involved ONE chain (A to B to C) with no competing resource contention between separate features - there was nothing for a bulkhead to isolate, since the entire problem was A waiting on ONE specific downstream call, not resource starvation from an unrelated feature. Graceful degradation: this pattern substitutes a fallback value when a dependency fails, verified in this chapter keeping two working results when a third dependency failed outright. The original scenario's own service_c wasn't necessarily FAILING - it was SLOW but still eventually returning a real answer (result: 'C says OK', still verified correct). Graceful degradation doesn't shorten a slow-but-eventually-successful call; it only helps when a dependency can be safely skipped or substituted, which wasn't established as true for the original chain. WHY THIS WORKS AS AN ANSWER ------------------------------ The answer traces the original problem's own precise mechanism (a caller synchronously waiting for however long a downstream call takes) back to this chapter's own circuit breaker finding as the direct match, and evaluates each of the other three patterns against that same specific mechanism rather than dismissing them as generally less useful.