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 failures count
  • Consecutive successes count
  • lastFailure timestamp

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:

  1. Retrieves or creates metrics for the provided key.
  2. Checks if the circuit is OPEN and whether the resetTimeout has elapsed; if so, transitions to HALF_OPEN.
  3. If still OPEN, throws immediately with "Circuit breaker is open for …".
  4. 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 setTimeout mechanism 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, and successThreshold, 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →