Predict the output
Threshold 3, cooldown 30 s. What does the trace show at t=5?
import enum
class State(enum.Enum):
CLOSED = "closed"
OPEN = "open"
HALF_OPEN = "half-open"
class Breaker:
def __init__(self, threshold: int, cooldown: float) -> None:
self.threshold, self.cooldown = threshold, cooldown
self.state, self.failures, self.opened_at = State.CLOSED, 0, 0.0
def allow(self, now: float) -> bool:
if (
self.state is State.OPEN
and now - self.opened_at >= self.cooldown
):
self.state = State.HALF_OPEN
return self.state is not State.OPEN
def record(self, ok: bool, now: float) -> None:
if ok:
self.state, self.failures = State.CLOSED, 0
return
self.failures += 1
if (
self.state is State.HALF_OPEN
or self.failures >= self.threshold
):
self.state, self.opened_at = State.OPEN, now
b = Breaker(threshold=3, cooldown=30)
trace = []
for t, ok in [
(0, False),
(1, False),
(2, False),
(5, True),
(31, False),
(62, True),
]:
if b.allow(t):
b.record(ok, t)
trace.append(f"t={t} called -> {b.state.value}")
else:
trace.append(f"t={t} rejected fast")
print("\n".join(trace))Hint 1 of 1
When did it open, and for how long?
Choose an answer, then open Show answer below to check it.
Show answer
Answer: A t=5 rejected fast
Correct. Three failures opened the breaker at t=2; the cooldown hasn't passed, so the call isn't made.
The third failure at t=2 trips the breaker, and opened_at becomes 2. allow() only switches to half-open once 30 s have passed, so at t=5 it refuses straight away without calling the dependency.
Why not the others?
- B
t=5 called -> closed. The breaker is open until t=32, so the call never happens. - C
t=5 called -> half-open. Half-open only starts after the 30 s cooldown. - D
t=5 called -> open. Open breakers don't call the dependency at all.