Circuit Breaker Pattern Interview Questions

Reviewed by Mark Dickie · Last updated

7 questions on this page you can answer and see marked on the spot. Go to the first one

A circuit breaker is a software pattern that stops a service from calling a downstream dependency once that dependency has started failing repeatedly, giving it time to recover instead of piling on more failed requests. For interviews, you should know the three states (closed, open, half-open) and the transitions between them, how failure thresholds and timeout windows are chosen, and how a circuit breaker differs from a simple retry. Expect to discuss what counts as a failure (timeouts vs 4xx vs 5xx), why half-open exists, and what metrics you would monitor in production.

ConceptWhat to know for the interview
Closed stateRequests flow through normally; failures are counted against a threshold.
Open stateRequests are short-circuited immediately; callers get a fallback or error without hitting the downstream.
Half-open stateA limited number of trial requests are allowed through to test whether the dependency has recovered.
Failure thresholdThe count or percentage of failures within a rolling window that trips the breaker from closed to open.
FallbackThe behavior when the breaker is open, such as a cached value, default response, or a fast error.

What does a circuit breaker interview test?

Interviewers use circuit breaker questions to check whether you can reason about failure propagation in distributed systems. The pattern comes up when the conversation turns to cascading failures, retry storms, and graceful degradation. A strong answer connects the mechanism to concrete consequences: fewer threads blocked on a dead dependency, faster error responses, and a controlled path back to full traffic once the dependency recovers.

How should you structure your answer?

  1. Name the problem first: without a breaker, one failing dependency can exhaust thread pools and connection pools, taking down the caller too.
  2. Walk through the three states and the transitions, naming what triggers each one.
  3. Explain how the half-open state probes for recovery and why a limited probe count matters.
  4. Mention the fallback behavior and what the caller sees when the breaker is open.
  5. Touch on configuration choices that interviewers probe: rolling window length, failure-rate vs failure-count thresholds, and the time the breaker stays open before switching to half-open.

What are common mistakes candidates make?

One frequent gap is confusing a circuit breaker with a retry. Retries re-attempt the same call; a breaker stops the call from happening at all. Another is skipping the half-open state, which is the mechanism that lets traffic ramp back up safely. Interviewers also look for whether you distinguish between failures you should trip on, such as timeouts and connection errors, and ones you should not, such as a 400 from a bad client request.

Key facts

  • Tarmac has 27 System Design interview questions on this topic, 25 of them on this page, at difficulty 1–5 of 5.
  • Tarmac tracked 3,763 job postings asking for System Design in September 2026.
  • Roles asking for System Design advertise a median base salary of US$180,347, across 1,250 job postings as of September 2026.
  • Tarmac last reviewed these System Design interview questions on 13 October 2026.

At a glance

Questions25 shown · 27 in the bank
Difficulty1–5 of 5
FormatsTrue / false, Short answer, Fill in the blank, Multiple choice, Multiple answer, Design exercise

What you'll review

  1. circuit breaker
  2. idempotency keys
  3. microservices

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

In the circuit breaker pattern, when the circuit is in the Open state, requests are allowed to pass through to the downstream service. True or false?#

Options

Show answer

False. In the circuit breaker pattern's Open state, the breaker blocks requests from reaching the downstream service and fails them immediately. Requests are forwarded normally only in the Closed state, while the Half-Open state lets a limited number of trial requests through to check whether the downstream service has recovered.

Why:

In the Open state, the circuit breaker blocks all requests from reaching the downstream service, so they fail fast immediately without being sent. Requests pass through normally only in the Closed state. The Half-Open state is the one that allows a limited number of trial requests to test whether the downstream service has recovered, so the statement is false.

In the circuit breaker pattern, after the circuit trips to the Open state, the breaker does not immediately re-test the downstream service. Instead it waits for a configurable duration before transitioning to the Half-Open state. What is the purpose of this delay?#

Show answer

The delay gives the failing downstream service time to recover before the circuit breaker sends any trial requests, reducing the risk of hammering an already-overloaded service and causing further failures.

Why:

While the circuit is Open, the breaker rejects calls to the downstream service without contacting it. The configurable wait before moving to Half-Open is a cooldown that gives the downstream service time to recover, whether by restarting, draining a backlog, or resolving a dependency outage. If the breaker probed immediately, it would keep sending load to a service that is still unhealthy, which could prolong the outage. The delay is a recovery window, not a rate-limiting or load-shedding mechanism.

A circuit breaker typically has three states. In the _____ state, requests pass through to the downstream service normally and failures are counted. When failures exceed a configured threshold, the circuit trips to the _____ state, where all requests are blocked immediately without calling the downstream service. After a cooldown period elapses, the circuit transitions to the _____ state, in which a small number of trial requests are permitted to probe whether the downstream service has recovered.#

Show answer

A circuit breaker typically has three states. In the Closed state, requests pass through to the downstream service normally and failures are counted. When failures exceed a configured threshold, the circuit trips to the Open state, where all requests are blocked immediately without calling the downstream service. After a cooldown period elapses, the circuit transitions to the Half-Open state, in which a small number of trial requests are permitted to probe whether the downstream service has recovered.

Why:

The three canonical states of the circuit breaker pattern are Closed (normal operation, requests flow), Open (tripped, requests blocked), and Half-Open (trial requests allowed after a cooldown to test recovery). If trial requests succeed the circuit returns to Closed; if they fail it goes back to Open.

What is a half-open circuit, and why is it useful?#

Show answer

The half-open state allows a small number of trial requests to pass through to the downstream service after a cooldown period. If those requests succeed, the circuit closes and normal traffic resumes; if they fail, the circuit reopens. This lets the system test recovery without flooding a still-unhealthy service.

Why:

Half-open is the transitional probe state of a circuit breaker. It lets the breaker test the downstream service with a limited number of requests, rather than immediately allowing full traffic (closed) or blocking indefinitely (open). Success closes the circuit, and failure reopens it. This is useful because it detects recovery safely without overwhelming a service that may still be unhealthy.

In a microservices architecture, service A calls service B over HTTP. Service B starts failing and responding slowly, causing service A's request threads to pile up, eventually making service A unresponsive. What is the main purpose of applying the circuit breaker pattern between service A and service B?#

Show answer

The main purpose is to stop sending requests to service B once failures or slow responses exceed a threshold, so that service A fails fast instead of holding threads while it waits on a degraded downstream. This keeps A's resources free and prevents the failure from cascading upstream.

Why:

A circuit breaker watches calls to a downstream dependency and, after repeated failures or slow responses, opens so that further calls return immediately with an error or fallback instead of being forwarded. This frees service A's threads and connections, so A does not become a bottleneck and the failure does not cascade to A's own callers. Retries with backoff are a complementary pattern that does not by itself stop A from holding resources while B is degraded, load balancing spreads traffic but does not halt calls to a failing instance, and encryption is unrelated to failure handling.

What are the three states of a circuit breaker, and what happens in each state?#

Show answer

The three states are Closed, Open, and Half-Open. In the Closed state, requests pass through to the downstream service normally and failures are counted. When failures exceed a configured threshold, the breaker transitions to Open: requests are blocked immediately and a fallback or error is returned without calling the downstream. After a cooldown period elapses, the breaker moves to Half-Open, where a limited number of trial requests are allowed through to probe whether the downstream has recovered. If those succeed, the breaker returns to Closed; if they fail, it reverts to Open.

Why:

A circuit breaker cycles through three states. In Closed, traffic flows normally and the breaker counts failures. When failures cross the configured threshold, it trips to Open and short-circuits calls, returning a fallback or error without contacting the failing dependency. After a cooldown, it enters Half-Open and lets a few trial requests through: if they succeed the circuit closes again, and if they fail it re-opens. The answer therefore needs all three state names and the transition behavior for each, not just the names.

In the circuit breaker pattern, what is the primary purpose of the HALF_OPEN state?#

Show answer

The HALF_OPEN state allows a limited number of probe requests to pass through to the downstream service to test whether it has recovered. If the probes succeed, the circuit closes and normal traffic resumes; if they fail, the circuit re-opens.

Why:

The standard circuit breaker state machine has three states. CLOSED is normal operation, where requests flow through to the downstream service and failures are counted. When the failure count exceeds a configured threshold, the circuit trips to OPEN, where all requests are short-circuited (fail fast) without calling the downstream. After a configurable cooldown period elapses, the circuit transitions to HALF_OPEN, where a small number of probe requests are permitted to test whether the downstream has recovered. If the probes succeed, the circuit returns to CLOSED; if they fail, it goes back to OPEN. HALF_OPEN is therefore the recovery-probing state that prevents the circuit from either staying open forever or immediately trusting a still-broken service.

When a circuit breaker is in the Open state and the configured recovery timeout elapses, which state does it transition to, and what happens to incoming requests in that new state?#

Show answer

It transitions to Half-Open. In Half-Open a limited number of trial requests are permitted through to the downstream service to probe whether it has recovered. If those trial requests succeed, the circuit moves back to Closed (normal operation). If they fail, the circuit re-opens.

Why:

While Open, the circuit breaker blocks all requests for the configured timeout. When that timeout elapses, the breaker moves to Half-Open rather than straight back to Closed. In Half-Open only a small number of probe requests are let through, so the caller can test whether the downstream service has recovered without sending full traffic to a service that may still be failing. If the probes succeed the circuit returns to Closed; if they fail it re-opens. Going directly to Closed would expose a possibly-still-failing service to full load, and blocking every request in Half-Open would prevent any recovery test from ever running.

In the circuit breaker pattern, while the circuit is in the Half-Open state, a limited number of probe requests are sent to the downstream service. If those probes succeed, the circuit transitions back to Closed; if they fail, the circuit transitions back to Open.#

Options

Show answer

True. In the circuit breaker pattern, the Half-Open state sends a limited number of probe requests to the downstream service. Successful probes return the circuit to Closed, while failed probes send it back to Open, so the breaker tests recovery before resuming full traffic.

Why:

This is the standard behavior of the Half-Open state. It acts as a gated recovery probe: a bounded number of requests are allowed through to test whether the downstream service has recovered. Successful probes move the circuit to Closed, so full traffic resumes. Failed probes move it back to Open, so fail-fast behavior resumes and another timeout cycle begins. The statement describes exactly this, so it is true.

What problem does the circuit breaker pattern solve, and how does it protect a distributed system?#

Show answer

The circuit breaker pattern prevents cascading failures in distributed systems by stopping calls to a failing or unresponsive downstream service. When failures exceed a threshold the circuit opens, so requests fail fast instead of piling up and consuming resources (threads, connections, memory) on the caller. After a timeout the circuit enters a Half-Open state to probe whether the downstream has recovered, which protects the downstream (less load during failure) and the upstream callers (freed resources, fast failure).

Why:

The pattern addresses cascading failures: when a downstream dependency fails or becomes slow, continued calls can exhaust the caller's threads, connections, or memory, turning a local failure into a wider outage. Opening the circuit makes calls fail fast, which frees caller resources and reduces load on the struggling downstream service. The Half-Open state then lets the system probe for recovery and resume normal traffic automatically once the dependency is healthy.

A microservice calls a downstream payment API. The circuit breaker is configured with: failure threshold = 5 consecutive failures, recovery timeout = 30 seconds, half-open trial requests = 3. The downstream service has been healthy. The next 5 consecutive requests to it all fail (time out). What is the immediate state of the circuit breaker after the 5th failure, and what happens to the 6th request that arrives 2 seconds later?#

Show answer

After the 5th consecutive failure the failure threshold is reached and the circuit transitions from Closed to Open. The 6th request arrives 2 seconds later, well within the 30-second recovery timeout, so it is short-circuited and fails fast without calling the downstream service. The circuit stays Open until 30 seconds have elapsed, at which point it moves to Half-Open and allows up to 3 trial requests.

Why:

Five consecutive failures meet the configured failure threshold of 5, so the circuit transitions from Closed to Open immediately after the 5th failure. In the Open state requests are short-circuited and fail fast without reaching the downstream service. The 6th request arrives only 2 seconds later, before the 30-second recovery timeout has elapsed, so the circuit is still Open and that request fails fast. Only after 30 seconds does the circuit move to Half-Open and permit the 3 configured trial requests.

Name the three states of the circuit breaker pattern and briefly describe the condition that triggers each state transition.#

Show answer
  1. Closed: requests flow through to the downstream service normally; when the count or rate of failures exceeds a configured threshold, the breaker trips to Open. 2) Open: requests are immediately rejected (fail fast) without calling the downstream service; after a configured timeout/cooldown elapses, the breaker transitions to Half-Open. 3) Half-Open: a limited number of trial requests are allowed through to probe the downstream service; if they succeed the breaker returns to Closed, if they fail it goes back to Open.
Why:

The circuit breaker pattern has three states: Closed (normal operation, trips to Open when failures exceed a threshold), Open (fail-fast, transitions to Half-Open after a timeout or cooldown), and Half-Open (a limited set of trial requests probes the downstream service, returning to Closed on success or back to Open on failure). The answer must name all three states and give the trigger for each transition, since the state machine is what lets the breaker stop calls to an unhealthy service and give it time to recover before cautiously testing it again.

A downstream payment provider starts timing out. Your service keeps retrying, threads pile up waiting on it, and the whole service becomes unresponsive. Which pattern most directly prevents this cascading failure?#

Options

Show answer

Add a circuit breaker that trips open after a failure threshold and fails fast until the dependency recovers. It detects a run of failures, short-circuits subsequent calls instead of letting them stack up on a dead dependency, then probes for recovery via a half-open state — directly stopping the thread exhaustion. Raising timeouts or adding retries or instances only feeds the cascade.

Why:

A circuit breaker detects a run of failures, trips to the open state, and short-circuits subsequent calls — failing fast instead of letting requests stack up on a dead dependency — then probes for recovery via a half-open state. That directly stops the thread exhaustion and cascade. Raising the timeout makes things worse: each call holds a thread longer, accelerating exhaustion. Unbounded fixed-delay retries amplify load on an already-struggling dependency (a retry storm) and prevent it from recovering. Adding instances just provides more threads to be consumed by the same stuck calls, scaling the failure rather than containing it.

What is a circuit breaker, and what problem does it prevent?#

Show answer

A circuit breaker wraps calls to a downstream dependency and trips open after a threshold of failures, so subsequent calls fail fast instead of waiting on a doomed request. This prevents a cascading failure: without it, a slow or down dependency would tie up threads and connections in the caller, exhaust its resources, and propagate the outage upstream. After a cooldown the breaker moves to half-open and lets a probe request through; if it succeeds the breaker closes and normal traffic resumes, otherwise it re-opens.

Why:

A circuit breaker monitors failures to a dependency and, past a threshold, opens to make calls fail fast rather than block. This stops a single unhealthy downstream from exhausting the caller's threads/connections and cascading the failure system-wide. Its three states — closed (normal), open (short-circuiting), half-open (trial requests) — let it recover automatically, and it is typically paired with timeouts, retries with backoff, and a fallback response.

Your payment service calls three downstream dependencies (a fraud-detection API, a currency-conversion API, and a ledger database), each owned by a different team with its own SLA. Design a circuit-breaker subsystem that prevents cascading failures when one of them degrades. Cover: the state machine (states and transitions), the concrete thresholds and timers you would configure, whether circuit state is shared across your service's instances, how the half-open probe is handled, and the key trade-offs.#

Show answer

Use one breaker per dependency, keyed by name, so a failing currency API does not trip the fraud or ledger breakers. Closed: calls pass through and outcomes are recorded in a sliding window of the last 100 calls; exceptions and timeouts both count as failures. Open: trip when the failure rate in the window exceeds 50% and the window holds at least 20 calls. While open, calls fail fast to a fallback (a cached exchange rate, a 'service unavailable' response for fraud checks, or a durable retry queue for ledger writes) for a 30 s cooldown. Half-Open: after the cooldown, admit exactly one probe request at a time while all other calls still fail fast; after 2 consecutive successful probes, transition to Closed and clear the sliding window; any failed probe reopens the circuit and restarts the cooldown. Sharing: keep breaker state in process memory per instance. A shared store such as Redis adds a network hop to every call and would let one shared breaker flip all instances at once. The trade-off is that instances can disagree about a dependency's health, but each one trips and probes on its own evidence, so recovery is staggered and the probe load on a recovering dependency stays bounded by the instance count. Publish state-change events to metrics for dashboards and alerting, but never use that pipeline for control-flow decisions.

Why:

This is an open design question that asks for a full specification: the three-state machine, concrete thresholds and timers, the sharing model across instances, half-open probe handling, and trade-offs. A strong answer names Closed, Open, and Half-Open with their transitions, gives numeric thresholds (a failure-rate trip condition with a minimum sample size) and a cooldown, justifies per-instance state versus a shared store, and explains how probes are limited so a recovering dependency is not overwhelmed. Grading should check for these elements rather than one exact set of numbers.

A circuit breaker is in the Open state. Its configured cooldown period has elapsed, so it transitions to the Half-Open state. In one or two sentences, what is the primary purpose of the Half-Open state?#

Show answer

To allow a limited number of probe (trial) requests through to the downstream service to test whether it has recovered. If the probes succeed, the breaker closes; if they fail, it reopens.

Why:

In the Open state the breaker rejects all calls immediately. When the cooldown timer expires, it moves to Half-Open and lets a small, bounded number of trial (probe) requests reach the downstream service. If those succeed, the breaker resets to Closed; if they fail, it returns to Open. The purpose is to detect whether the downstream service has recovered without sending it full traffic, so it is a controlled probe rather than a full retry or a manual reset.

Design a circuit breaker library that teams of microservices can drop in to protect outbound calls to a third-party REST API. Cover the full state machine (Closed → Open → Half-Open → Closed), the configuration parameters an operator would tune, how you would handle thread-safe state transitions and counter updates in a multi-threaded environment, and how you would expose metrics for observability. Assume a single-process deployment (Java or Go) with dozens of concurrent goroutines or threads calling through the breaker.#

Show answer

State machine: the breaker starts Closed, where calls pass through and a sliding window (count-based or time-based) records successes and failures. When the failure rate or consecutive failures exceed a threshold (for example 50% of the last 100 calls, once a minimum sample size is reached), it trips to Open. In Open, calls fail fast with a CircuitOpenError and no network call is made. After a cooldown (waitDurationInOpenState) it moves to Half-Open, where a bounded number of probe calls (for example 1 to 3) are allowed. If all probes succeed it returns to Closed and resets counters; if any probe fails it returns to Open and restarts the cooldown.

Configuration: failureThreshold (count or percentage), minimumNumberOfCalls (samples before the threshold is evaluated), waitDurationInOpenState (cooldown), permittedNumberOfCallsInHalfOpenState (probe count), and callTimeout (a slow call counts as a failure, preventing thread starvation).

Concurrency: in Java, hold the state in an AtomicReference with CAS-based transitions and use LongAdder for counters. In Go, either use a single goroutine that owns state and receives commands over channels, or use sync/atomic CAS on the state plus a mutex guarding multi-field updates. The key invariant is that Half-Open admits exactly one (or a bounded number of) probes: an atomic permit counter is decremented via CAS, so only the winners proceed and the rest fail fast.

Observability: expose a gauge for the current state, counters for total calls, successes, failures and rejected calls, and a histogram of call latency (Prometheus-style). Log every state transition at INFO with a timestamp, and provide a /healthz or /circuitbreaker endpoint reporting current state, recent failure rate and time since the last transition.

Why:

This is an open design question with no single key, so it is graded as a short answer. A strong response covers all four areas: the three-state machine with its transitions (Closed to Open on threshold, Open to Half-Open after cooldown, Half-Open back to Closed on successful probes or to Open on a failed probe), concrete tunable parameters such as failure threshold, minimum calls, wait duration and half-open permitted calls, thread-safe transitions using atomics/CAS or a single-writer pattern so exactly the bounded number of probes gets through, and observability through metrics, transition logging and a status endpoint.

A mobile client retries a POST /payments when the network drops, risking a double charge. You add idempotency keys. Which statements about implementing them correctly are true?#

Options

Pick every one that applies.

Show answer

Three statements are correct: the client generates a unique key per logical operation and resends the same key on retries, the server persists the key with the operation's result and replays the stored result on a repeat, and idempotency keys are most valuable for non-idempotent verbs like POST. Generating a fresh key per retry defeats the mechanism, and TCP guarantees reliable bytes, not application-level exactly-once.

Why:

Idempotency keys work because the client mints one key per logical operation and reuses it across retries, and the server records that key alongside the result so a repeat presents the same outcome instead of executing twice. They matter most for non-idempotent methods like POST — GET/PUT/DELETE are already idempotent by definition, so a blind retry of those is safe. The wrong options break the mechanism: minting a new key per attempt defeats the whole point — the server sees each retry as a distinct operation and double-charges. And TCP guarantees reliable, ordered bytes within a connection, not application-level exactly-once semantics across reconnects and timeouts; that is exactly the gap idempotency keys fill.

Your checkout service calls an inventory service synchronously. When inventory is slow, checkout threads pile up and the whole checkout service becomes unavailable. Which patterns directly address this cascading failure problem?#

Options

Pick every one that applies.

Show answer

Three patterns directly address the cascade: a circuit breaker that opens on the inventory service's error rate or latency and fast-fails instead of waiting, a request timeout so threads are released when inventory is slow, and a bulkhead — a separate bounded thread pool for inventory calls — so an inventory slowdown can't exhaust checkout's whole pool. Merging the services into one process undoes the decomposition, and adding replicas just reproduces the pile-up.

Why:

Cascading failures happen when downstream slowness consumes upstream resources. A circuit breaker stops sending requests to a struggling service and fast-fails callers, giving the dependency time to recover and shedding load rather than amplifying it. A timeout ensures threads are released promptly instead of blocking indefinitely — without timeouts, a permanently slow downstream locks threads until the upstream exhausts its pool. A bulkhead isolates the downstream calls in a bounded resource pool so that even if those threads are all waiting, the checkout service can still handle other work using its separate pool. Merging the services into one process eliminates the network boundary but reintroduces tight coupling, undoing the service decomposition entirely. Adding more checkout replicas temporarily increases capacity but doesn't stop threads from piling up in each new replica — the cascade keeps reproducing; you need flow control, not more nodes.

An open circuit breaker stays open permanently until an operator manually resets it.#

Options

Show answer

False. A circuit breaker is self-healing. After the open timeout elapses it transitions to half-open and lets a limited number of trial requests through. If those succeed it closes and resumes normal traffic; if they fail it re-opens and waits again. This automatic probing lets the system recover without human intervention.

Why:

A circuit breaker is self-healing. After the open timeout elapses it transitions to half-open, allowing a limited number of trial requests through. If those succeed it closes and resumes normal traffic; if they fail it re-opens and waits again. This automatic probing is the whole point — it lets the system recover without human intervention while still shielding a struggling downstream from a thundering herd.

A count-based circuit breaker (Resilience4j-style) is configured per downstream dependency with these settings: sliding window size = 10 calls, minimum number of calls before evaluation = 5, failure rate threshold = 60%, wait duration in open state = 30 s, permitted number of calls in half-open = 3, half-open success threshold to close = 2. The breaker starts in CLOSED with an empty window. Each call's result is recorded as Success or Failure. The next five calls complete in this order: Fail, Fail, Fail, Success, Fail. What is the breaker's state immediately after the 5th call completes? Answer with the state name and a brief justification.#

Show answer

The circuit breaker is OPEN after the 5th call. The failure rate is only evaluated once the window holds at least 5 recorded calls, which first happens at call 5. At that point the window holds 4 failures and 1 success, a failure rate of 4/5 = 80%, which exceeds the 60% threshold, so the breaker transitions from CLOSED to OPEN. Earlier calls did not trigger evaluation because the minimum of 5 calls had not been reached.

Why:

The breaker does not evaluate the failure rate until the sliding window contains at least the minimum number of calls (5). After calls 3 and 4 the window holds 3 and 4 entries, below the minimum, so no evaluation occurs and the breaker stays CLOSED even though most calls failed. At call 5 the window reaches 5 recorded calls with 4 failures and 1 success. The failure rate is 4/5 = 80%, which exceeds the 60% threshold, so the breaker transitions to OPEN. The success on call 4 is still counted in the window; it is not discarded. The failure rate's denominator is the number of recorded calls (5) until the window fills to its size of 10, not the full window size.

In a circuit breaker implementation such as Resilience4j, the choice of sliding-window strategy affects both memory footprint and how failure rates are computed. Fill in the two blanks: a _____ sliding window stores the most recent N individual call outcomes in a fixed-size ring buffer, while a _____ sliding window divides the time range into N fixed-duration buckets and stores only aggregated counts (successes, failures, slow calls) per bucket.#

Show answer

In a circuit breaker implementation such as Resilience4j, the choice of sliding-window strategy affects both memory footprint and how failure rates are computed. Fill in the two blanks: a count-based sliding window stores the most recent N individual call outcomes in a fixed-size ring buffer, while a time-based sliding window divides the time range into N fixed-duration buckets and stores only aggregated counts (successes, failures, slow calls) per bucket.

Why:

Resilience4j defines two sliding-window modes. The count-based mode uses a ring buffer of size N that holds individual call outcomes, giving a memory footprint proportional to N regardless of call rate. The time-based mode partitions time into N equal-length buckets and stores only aggregate counters per bucket, so memory is proportional to the number of buckets (N) and does not scale with call volume, at the cost of losing per-call granularity. The count-based approach suits high-throughput services where the last N calls should drive decisions; the time-based approach better captures temporal patterns and naturally handles idle periods, since old buckets age out.

Design a circuit breaker component for a microservices platform that handles millions of requests per minute across hundreds of downstream service dependencies. The circuit breaker must be embeddable in application code, independently configurable per downstream dependency, and integrated with the platform's observability stack. Describe the state machine and all state transitions, the configuration knobs an operator would need, the sliding window strategy and when you would choose count-based vs time-based, how concurrent requests are handled in each state (especially HALF_OPEN), and how circuit breaker events and metrics are surfaced to operators for incident response.#

Show answer

Our circuit breaker is an embeddable library that wraps each downstream call in a decorator, with one breaker instance per dependency and independent configuration. State machine: three states. CLOSED: calls pass through and outcomes are recorded. OPEN: calls are short-circuited immediately with no network I/O and a typed exception is thrown. HALF_OPEN: a bounded number of trial calls are permitted to probe recovery. Transitions: CLOSED→OPEN when the failure rate over the sliding window exceeds the threshold (only once the minimum call count is met); OPEN→HALF_OPEN after the wait duration elapses; HALF_OPEN→CLOSED when the trial success threshold is met; HALF_OPEN→OPEN when a trial fails or the trial failure rate exceeds its own threshold. Configuration knobs (per dependency): failure rate threshold (e.g., 50%), minimum number of calls before evaluation, slow-call duration threshold (slow calls count as failures), sliding window type and size, open-state wait duration, permitted calls in HALF_OPEN, and HALF_OPEN success/failure thresholds. Sliding window: for high-throughput services, a count-based ring buffer (e.g., last 100 calls) gives predictable O(N) memory and a stable sample. For bursty or low-volume traffic, a time-based window (e.g., 60 one-second buckets) captures temporal failure patterns and ages out stale data during idle periods. The minimum-calls setting prevents tripping on a tiny sample. Concurrency: in CLOSED, all calls proceed and outcomes are recorded via a lock-free ring buffer or a short lock. In OPEN, calls fail fast. In HALF_OPEN, an atomic counter or semaphore caps in-flight probes at the permitted number; if 3 probes are allowed and 3 are in flight, the 4th concurrent request is rejected rather than forwarded, preventing a thundering herd when the breaker moves to HALF_OPEN. Observability: every state transition emits a structured event (timestamp, dependency, old/new state, triggering metric) to the event bus. Counters for rejected calls, failures, slow calls, and time-in-state are exported to Prometheus/Micrometer with a per-dependency label. A per-dependency dashboard shows current state, failure rate, time-in-state, and recent transitions. An admin endpoint lets operators force a state during incidents. Fallback: rejected calls return a fallback (cached value, default, or queued retry) or throw a typed exception distinct from downstream errors, so callers can degrade gracefully.

Why:

This is an open design question that asks the reader to describe and justify a system, not to select from given options, so it stays a SHORT_ANSWER graded against the sample answer and keywords. A strong answer must name the three states and their transitions (CLOSED to OPEN on failure rate, OPEN to HALF_OPEN after the wait, HALF_OPEN back to CLOSED or OPEN depending on trial results). It must justify count-based versus time-based windows by traffic pattern, explain how HALF_OPEN limits concurrent probes, and describe operator-facing events and metrics per dependency.

A payment orchestrator makes synchronous calls to five downstream services (fraud detection, wallet, ledger, notification, and exchange-rate), each with independent failure characteristics. The team proposes wrapping all five calls with one shared circuit breaker configured with a 50% failure-rate threshold over a 100-request sliding window. Which statement correctly identifies all of the critical problems with this design?#

Options

Show answer

A single shared circuit breaker across several independent dependencies suffers from both failure dilution and failure contamination. Dilution happens when successes from healthy services keep the aggregate failure rate under the trip threshold, hiding a failed dependency. Contamination happens when the breaker trips and blocks calls to healthy services too. Per-dependency breakers avoid both.

Why:

Two distinct problems arise from one breaker shared across independent dependencies. Failure dilution: when only one service fails, the successes from the other healthy services lower the aggregate failure rate, which can stay below the 50% threshold so the circuit never opens even though a dependency is down. Failure contamination: when the shared circuit does trip, it rejects calls to every downstream service, including healthy ones, degrading unrelated functionality. Only the statement naming both problems covers all of the critical issues; the statements naming just one are incomplete. The claim that the sliding window overflows is false: a window of 100 simply tracks the most recent 100 requests regardless of which destination each targeted, and nothing is dropped beyond that rolling limit. The claim that neither problem applies is also false. Per-dependency circuit breakers fix both issues by keeping isolated failure statistics and tripping independently for each downstream service.

An e-commerce company runs a single large monolith (catalog, cart, checkout, payments, orders, inventory, shipping all in one deployable, one database). Deploys are slow and risky, one team's bug takes the whole site down, and they can't scale checkout independently of browsing. Design the decomposition into microservices and the platform that supports it.#

Show answer

Goals & when to split. The pains are concrete: coupled deploys, no fault isolation, and an inability to scale checkout independently of browsing (which is ~50× the traffic). Those justify splitting. But microservices aren't free — they trade in-process calls and ACID transactions for network hops, partial failure, and distributed-transaction headaches. So I split deliberately, by business value, not everywhere at once.

Service boundaries. I decompose by bounded context / business capability: catalog, cart, orders, payments, inventory, shipping. Each is high-cohesion and owns its domain logic and its data. I avoid the anti-pattern of slicing along database tables into chatty anaemic services — boundaries follow how the business reasons about the domain, so services stay loosely coupled.

Database decomposition. Each service gets its own datastore (database-per-service) — this is what actually breaks the shared-DB scaling ceiling and SPOF. Services no longer cross-join each other's tables; instead they expose APIs and emit events. The orders service stores the product id (and denormalises the few fields it needs) and fetches the rest from the catalog API, or subscribes to catalog change events. What we give up is the convenient cross-table join and strong cross-entity consistency — replaced by API calls and eventual consistency.

Communication & gateway. An API gateway fronts everything: it authenticates, routes to the right service, rate-limits, and can fan out/aggregate. Between services I pick per interaction: synchronous REST/gRPC for a read I need right now (get product), asynchronous events for 'order placed' / 'inventory changed' so producers don't block on consumers. Every synchronous call is wrapped with timeouts, retries (idempotent), and a circuit breaker so a slow dependency fails fast instead of hanging the caller.

Cross-service correctness (place order). Placing an order spans orders + inventory + payments — three databases, so no single ACID transaction. I use a saga: a sequence of local transactions with compensating actions. Orchestrated, an order orchestrator does: reserve inventory → charge payment → confirm order; if payment fails after the reservation, it fires the compensation release inventory. The order sits in a PENDING state until the saga completes, and the user sees pending → confirmed (or failed). This is eventually consistent but never permanently leaks reserved stock.

Migration & new failure modes. No big-bang. I use the strangler-fig pattern: keep the monolith running behind the gateway, peel out one service plus its data at a time, route that capability's traffic to the new service (feature-flagged), dual-write / shadow-read to validate, then cut over and delete the monolith's copy. New failure modes — partial failure (one service down), cascading failure (a slow dependency dragging callers down), and added latency from hops — are contained with circuit breakers, bulkheads (isolate resource pools per dependency), idempotent retries with backoff, and distributed tracing so a request can be followed across services.

Why:

Decomposing a monolith tests judgement, not just diagram-drawing. The two decisions that define the answer are where the boundaries go — by bounded context / business capability so services are loosely coupled and own their data, never by slicing a shared table into chatty anaemic services — and how to break the shared database, the actual scaling ceiling, via database-per-service reached incrementally with the strangler-fig pattern (peel out one service plus its data at a time, no big-bang). Once data is split, cross-service flows like 'place order' can't use a single ACID transaction, so the correct tool is a saga with compensating actions (reserve → charge → confirm, release on failure), accepting eventual consistency. The strong candidate also names the costs microservices add — partial and cascading failure, network latency — and contains them with an API gateway, circuit breakers, bulkheads, idempotent retries, and distributed tracing, rather than treating 'microservices' as an unqualified win.

Related interview questions

Job market

See system-design salaries and hiring demand from live job postings.

The other 2 questions

This page shows 25 and marks what you pick. That's as far as a page can go. A free account opens the other 2 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.