How the Circuit Breaker Pattern Is Implemented in the Minisearch Server Utilities
The Minisearch server provides a stand-alone, generic circuit breaker in server/utils/circuitBreaker.ts that follows the classic three-state model (CLOSED, OPEN, HALF_OPEN) to prevent cascading failures in async operations.
The felladrin/minisearch repository includes a robust server-side implementation of the circuit breaker pattern designed to protect external API calls and other flaky async operations. Located entirely within server/utils/circuitBreaker.ts, this utility offers a key-agnostic, fully typed TypeScript solution that tracks failure rates and automatically cuts off traffic to failing services. Understanding this implementation helps developers configure resilient LLM integrations and third-party API consumers within the Minisearch ecosystem.
Core Architecture and State Management
The circuit breaker relies on a strongly typed state machine and configurable thresholds to determine when to block or allow traffic.
Type Definitions and Configuration
At the top of server/utils/circuitBreaker.ts, the implementation defines a CircuitState union type (line 1) that restricts the breaker to three valid states: "CLOSED", "OPEN", and "HALF_OPEN". The configuration interface CircuitBreakerOptions (lines 3‑7) exposes three critical parameters:
- failureThreshold: Number of consecutive failures before opening the circuit.
- resetTimeout: Milliseconds to wait before attempting recovery (transitioning to HALF_OPEN).
- successThreshold: Successful calls required in HALF_OPEN state to close the circuit.
Default values are provided via defaultOptions (lines 16‑20), setting the failure threshold to 5, reset timeout to 30 seconds, and success threshold to 3.
Per-Key Metrics Storage
The breaker maintains isolated metrics for each protected resource using a private metrics Map (lines 22‑24). This CircuitMetrics object tracks:
- Current
state - Consecutive
failurescount - Consecutive
successescount lastFailuretimestamp
This design allows a single CircuitBreaker instance to protect multiple distinct external services (e.g., different LLM models) simultaneously without cross-contamination.
Execution Flow and State Transitions
The execute method serves as the public entry point for all protected operations, handling state checks, transitions, and metric recording.
The execute Method
The execute method (lines 30‑55) accepts a unique key identifier and an async function fn. It performs the following sequence:
- Retrieves or creates metrics for the provided key.
- Checks if the circuit is OPEN and whether the
resetTimeouthas elapsed; if so, transitions to HALF_OPEN. - If still OPEN, throws immediately with
"Circuit breaker is open for …". - Executes the supplied function and records success or failure accordingly.
Recording Successes and Failures
Success handling occurs in recordSuccess (lines 90‑99). When in HALF_OPEN mode, consecutive successes increment the counter; reaching successThreshold resets the state to CLOSED and clears counters. In CLOSED mode, any successful call resets the failure counter to zero.
Failure handling in recordFailure (lines 101‑116) increments the failure count, stores the timestamp, resets successes to zero, and opens the circuit when the threshold is breached. Crucially, this method schedules a setTimeout that automatically transitions the state from OPEN to HALF_OPEN after the configured resetTimeout duration, enabling automatic recovery testing.
Manual Reset and State Inspection
For monitoring and testing purposes, the getState accessor (lines 58‑64) returns the current state for any key, while resetMetrics (lines 119‑124) forcibly clears all counters and returns the circuit to CLOSED.
Practical Usage Examples
Basic Integration for API Protection
Wrap any flaky async operation, such as an LLM request, using the execute method:
import { CircuitBreaker } from "./utils/circuitBreaker";
const cb = new CircuitBreaker({
failureThreshold: 3,
resetTimeout: 15000,
successThreshold: 2,
});
async function protectedCall<T>(key: string, fn: () => Promise<T>): Promise<T> {
return cb.execute(key, fn);
}
// Protect an OpenAI API call
await protectedCall("openai-gpt-4", async () => {
const response = await fetchOpenAI(...);
return response.json();
});
Health Check Endpoints
Inspect circuit states for monitoring dashboards:
import { CircuitBreaker } from "./utils/circuitBreaker";
const cb = new CircuitBreaker();
const state = cb.getState("openai-gpt-4"); // "CLOSED" | "OPEN" | "HALF_OPEN"
console.log(`OpenAI circuit state: ${state}`);
Service-Specific Configuration
Create isolated breakers with different thresholds for various external services:
const modelBreakerMap = new Map<string, CircuitBreaker>();
function getBreakerForModel(model: string): CircuitBreaker {
if (!modelBreakerMap.has(model)) {
const options = model === "gpt-4"
? { failureThreshold: 2, resetTimeout: 10000, successThreshold: 1 }
: {}; // fall back to defaults
modelBreakerMap.set(model, new CircuitBreaker(options));
}
return modelBreakerMap.get(model)!;
}
// Usage
await getBreakerForModel("gpt-4").execute("gpt-4", async () => {
// …call model…
});
Validation and Testing
The implementation is validated by server/utils/circuitBreaker.test.ts, which verifies state transitions, error propagation, and timeout behavior. Key test assertions confirm that:
- An OPEN circuit throws
"Circuit breaker is open for …"immediately. - After consecutive failures exceeding the threshold, the circuit transitions to OPEN or HALF_OPEN depending on timing.
- The
setTimeoutmechanism correctly schedules transitions from OPEN to HALF_OPEN.
These tests serve as living documentation for the expected behavior of the circuit breaker utility.
Summary
- The circuit breaker pattern in Minisearch is implemented as a generic, reusable TypeScript class in
server/utils/circuitBreaker.ts. - It maintains three distinct states (CLOSED, OPEN, HALF_OPEN) with automatic transitions based on failure counts and timeouts.
- The implementation supports multi-key isolation, allowing one instance to protect multiple external services simultaneously.
- Configuration options include
failureThreshold,resetTimeout, andsuccessThreshold, with sensible defaults provided. - State transitions are handled internally via
recordSuccess,recordFailure, and scheduled timeouts, requiring no manual intervention for recovery.
Frequently Asked Questions
What is the default failure threshold for the Minisearch circuit breaker?
According to the source code in server/utils/circuitBreaker.ts (lines 16‑20), the default failureThreshold is 5 consecutive failures. The default resetTimeout is 30000 milliseconds (30 seconds), and the successThreshold defaults to 3 successful calls in HALF_OPEN state.
How does the circuit breaker transition from OPEN to HALF_OPEN automatically?
When the failure threshold is reached, the recordFailure method (lines 101‑116) schedules a setTimeout that executes after the configured resetTimeout duration. This timer flips the state from OPEN to HALF_OPEN, allowing a single test request to determine if the external service has recovered without requiring manual intervention.
Can I use different circuit breaker configurations for different external services?
Yes. While a single CircuitBreaker instance can track multiple services via unique keys, you can also instantiate separate CircuitBreaker objects with distinct CircuitBreakerOptions for different services. The code examples demonstrate using a Map<string, CircuitBreaker> to associate specific threshold configurations with individual LLM models or API endpoints.
Where can I find the unit tests for the circuit breaker implementation?
The complete test suite is located in server/utils/circuitBreaker.test.ts alongside the implementation. These tests validate default options, custom configuration handling, state transition logic, and the automatic opening behavior after repeated failures, serving as authoritative documentation for the utility's behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →