A purchasing portal gathers availability from several suppliers. One supplier has almost stopped responding. The others are healthy, yet employees cannot open the combined view: calls to the struggling partner occupy shared connections and remain unfinished.
A timeout can make each individual request finish eventually. But the next employee will wait for the same supplier, followed by the next. A circuit breaker adds memory of recent failures to that individual time limit. It asks whether another call is worth starting at all right now.
Stopping calls does not repair the dependency
When recent failures cross a configured threshold, the mechanism temporarily stops normal calls. New requests are rejected locally without reaching the dependency. This reduces repeated waiting inside the application and relieves some outgoing load. The original fault still needs to be fixed.
The protection is useful when an unhealthy participant can damage unrelated workflows. If calls are infrequent, bounded and already isolated, another state machine may cost more to maintain than it saves. Having an external API is not, by itself, a reason to put a breaker around every operation.
Nor can the design automatically promise complete containment. While the breaker gathers observations, requests are already waiting. Without concurrency limits, capacity can run out before the failure threshold takes effect. Timeouts and resource isolation address different parts of that problem.
Three states become part of normal operations
In the closed state, calls pass through and their outcomes are recorded. The terminology comes from an electrical circuit: closed means the path conducts. Depending on the implementation, the breaker may consider failures, slow calls or both.
In the open state, normal calls are rejected without reaching the dependency. An immediate retry is particularly unhelpful here. Calling the same protected operation again does not make the remote system healthy.
After a pause, a limited number of trial calls can pass through: the half-open state. They test recovery without releasing the entire workload at once. Healthy results allow normal calls to resume; poor results keep protection active. The exact transition conditions depend on the implementation and the service's workload.
The trial must also represent the operation being protected. A healthy “process is alive” endpoint does not prove that stock availability queries work again. Creating fake purchases as health probes would introduce another problem. Choose representative calls with safe business effects.
Not every rejection is evidence of an outage
A supplier can correctly report that an item is unavailable. That is a valid business result, not a dependency failure. Invalid request parameters or missing permission for one customer should not automatically take a healthy service offline for everyone else.
Start with error classification rather than a failure percentage. Which outcomes indicate dependency health? Does the problem affect the whole supplier, one method, a region or one account? An excessively broad breaker turns a local problem into an outage created by our own application.
A percentage without a sample size can also mislead. A few infrequent calls provide weak evidence, while a large workload can consume substantial capacity even with a relatively small proportion of hung requests. Observation windows, minimum samples and thresholds need to be tested against actual traffic rather than copied from a library example.
In a deployment with several application instances, breaker state is often local. One instance may have stopped calls while another is still testing the supplier. That can be reasonable, but a per-instance probe limit is not a platform-wide limit. Process restarts may also discard the accumulated history.
What the employee sees while calls are blocked
The purchasing portal may still show results from healthy suppliers while marking one partner's information unavailable. It should not translate a missing response into “out of stock”. Employees may make different purchasing decisions based on those two statements.
Older data is acceptable only when its age and purpose are understood. Yesterday's availability may be useful context; it is not confirmation that the supplier can fulfil a commitment today. If current verification is required, that part of the workflow must stop or enter an explicitly agreed pending state.
The fallback has a capacity limit too. Redirecting all requests to a second supplier or the primary database without checking their headroom can merely move the incident. Test the alternate path under the traffic it will receive during failure, not only with one successful request.
Recovery deserves its own test
Turning off a dependency and observing a fast error is only half the exercise. Bring it back with limited capacity. Do trial calls and queued jobs produce a new burst? Can the breaker remain open unnecessarily? Do the library's health metrics match the function employees can actually use?
Track remote failures, locally rejected calls and probe outcomes separately. One combined error count obscures whether the supplier is still down or the application has not yet resumed normal access.
Include application restarts during the outage in the test. New instances may lack failure history, so the remaining controls still need to contain demand while their breakers gather evidence.
The configuration also needs an owner: someone who can adjust thresholds, investigate frequent transitions and intervene carefully after a mistaken opening. Otherwise a small library becomes another decision-making system that nobody can explain during an incident.