Calls keep hammering a failing dependency every time. Trip the circuit OPEN after K consecutive failures to fail fast, then HALF_OPEN after a cooldown to probe for recovery.
You'll predict the failure first, then write the fix and watch your own code drive the behavior.
우리 서버가 다른 서버(예: 결제 API)를 호출한다. 그런데 그 서버가 죽었다. 호출하면 무조건 실패한다.
boolean attempted = cb.call(now, dependencyUp);
if (!attempted) {
// OPEN: failed fast, dependency was not touched
}“My service calls another service, but that one is down, so every call fails.”
checking microphone…
그냥 두면? 죽은 서버한테 계속 요청을 날린다. 매번 응답을 기다렸다가 실패. 우리도 느려지고, 죽은 쪽은 더 못 일어난다.
⚖️ Trade-off: 실패할 게 뻔한데도 매번 호출 → 우리 시간 낭비 + 상대가 회복할 틈을 안 줌.
“If we keep calling a dead service, we waste time and never let it recover.”
checking microphone…
그래서 "차단기"를 둔다. 평소엔 CLOSED(닫힘=정상, 전류가 흐름). 호출이 그대로 통과한다.
🔧 도구:enum State { CLOSED, OPEN, HALF_OPEN }Resilience4j CircuitBreaker
String state = "CLOSED"; // CLOSED, OPEN, HALF_OPEN
int failures = 0;
if (state.equals("CLOSED") && dependencyUp) {
failures = 0;
return true; // call passes through
}“I add a circuit breaker; it starts CLOSED, meaning calls pass through normally.”
checking microphone…
연속으로 K번 실패하면(threshold) 차단기를 OPEN으로 바꾼다. OPEN이면 죽은 서버를 아예 안 부르고 즉시 실패를 돌려준다(fail fast).
⚖️ Trade-off: OPEN인 동안엔 운 좋게 성공했을 수도 있는 호출까지 다 막아버린다.
✅ Fix: 그게 손해 같지만, 죽은 서버를 안 때리니 상대가 숨 쉴 틈이 생기고 우리도 안 느려진다. 그 트레이드를 받아들인다.
🔧 도구:consecutiveFailures 카운터thresholdfail fast
failures++;
if (failures >= threshold) {
state = "OPEN";
openedAt = now;
}
if (state.equals("OPEN")) return false; // fail fast, no dependency call“After K failures in a row, it trips to OPEN and fails fast without calling the dependency.”
checking microphone…
근데 영원히 막으면 안 된다. 상대가 살아났는지 확인해야 하니까, 일정 시간(cooldown)이 지나면 HALF_OPEN으로 넘어간다.
⚖️ Trade-off: 쿨다운이 너무 길면 상대가 살아났는데도 한참 못 쓰고, 너무 짧으면 또 죽은 서버를 때린다.
✅ Fix: 쿨다운 길이를 상대의 회복 속도에 맞춰 조절한다. 정답은 상황마다 다르니 튜닝값이다.
🔧 도구:cooldownTickslogical clock (now)
if (state.equals("OPEN") && now - openedAt >= cooldownTicks) {
state = "HALF_OPEN";
}“After a cooldown, it moves to HALF_OPEN to check if the dependency is back.”
checking microphone…
HALF_OPEN에선 딱 한 번만 시험 호출(probe)을 보낸다. 성공하면 "살아났네" 하고 CLOSED로 되돌린다.
⚖️ Trade-off: 이 한 번을 여러 개 동시에 보내면 살아나려던 서버를 또 덮친다.
✅ Fix: 그래서 HALF_OPEN에선 단 하나만 통과시킨다. 한 번의 결과로 판단.
🔧 도구:single probehalf-open allow-one
if (state.equals("HALF_OPEN")) {
if (dependencyUp) { state = "CLOSED"; failures = 0; return true; }
}“In HALF_OPEN it allows one probe; if it succeeds, the breaker closes again.”
checking microphone…
시험 호출이 실패하면 "아직 죽었네" 하고 다시 OPEN으로 돌아가서 또 쿨다운을 기다린다.
🔧 도구:re-open on probe failure
if (state.equals("HALF_OPEN") && !dependencyUp) {
state = "OPEN";
openedAt = now;
return false; // probe failed, re-open
}“If the probe fails, it re-opens and waits another cooldown before trying again.”
checking microphone…
정리: 평소 통과(CLOSED) → 자꾸 실패하면 끊기(OPEN, 즉시 실패) → 좀 기다렸다 한 번 떠보기(HALF_OPEN) → 되면 복구, 안 되면 다시 끊기. threshold랑 cooldown만 상황에 맞게 맞추면 된다.
⚖️ Trade-off: 값을 잘못 잡으면: threshold가 너무 낮으면 멀쩡한데 자꾸 끊고, 너무 높으면 죽은 서버를 너무 오래 때린다.
✅ Fix: 실제 실패 패턴을 보고 threshold와 cooldown을 튜닝한다. 그게 이 패턴의 핵심 운영 포인트.
🔧 도구:threshold tuningcooldown tuning
CircuitBreaker(int threshold, int cooldownTicks) {
this.threshold = threshold;
this.cooldownTicks = cooldownTicks;
}“So I tune the threshold and cooldown to match the real failure pattern.”
checking microphone…
8단계 영어를 다 말하면 → 이 메커니즘 전체를 영어로 설명할 수 있게 된다.
Say it out loud in your own words — hit these terms — then check against the gold answer.
Say it in your own words — but hit these: circuit breaker · resilience · state machine · fault tolerance
checking microphone…