UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

150 lines (149 loc) • 5.03 kB
/** * MCP Circuit Breaker * Implements circuit breaker pattern for external MCP operations * Provides fault tolerance and prevents cascading failures */ import { EventEmitter } from "events"; import type { CircuitBreakerConfig, CircuitBreakerStats } from "../types/index.js"; export { CircuitBreakerOpenError } from "../types/index.js"; /** * MCPCircuitBreaker * Implements circuit breaker pattern for fault tolerance */ export declare class MCPCircuitBreaker extends EventEmitter { private name; private state; private config; private callHistory; private lastFailureTime; private halfOpenCalls; private lastStateChange; private cleanupTimer?; constructor(name: string, config?: Partial<CircuitBreakerConfig>); /** * Execute an operation with circuit breaker protection. * * `operation` is handed a `recordResolvedFailure` callback so it can flag a * *resolved* result as a logical failure without throwing. This matters for * MCP tool calls: the client does not throw on a protocol error, it * resolves with `{ isError: true, ... }`. Before this callback existed, * such a call always fell through to the success path below — the breaker * could never open for a tool that only ever "fails" by resolving an error * result, and callers still need that resolved value returned as-is (not * replaced by a thrown transport error). Call `recordResolvedFailure()` * from inside `operation` when that resolved value represents a failure; * the call is still counted as a normal, non-throwing success from the * `Promise.race` below, so this callback is what tells `execute()` * otherwise. Callers that never call it see no behavior change. */ execute<T>(operation: (recordResolvedFailure: (reason?: string) => void) => Promise<T>): Promise<T>; /** * Shared bookkeeping for a failed outcome — a thrown error, or a resolved * result the caller flagged via `recordResolvedFailure`. Records the call * as a failure, emits `callFailure`, and runs the state transitions that * used to live inline in the `catch` block: half-open failure immediately * re-opens the circuit; closed checks the failure threshold. */ private recordFailureOutcome; /** * Record a call in the history */ private recordCall; /** * Check if failure threshold is exceeded */ private checkFailureThreshold; /** * Change circuit breaker state */ private changeState; /** * Race an operation against a timeout, clearing the timer on either * outcome. A bare `Promise.race([operation, timeoutPromise])` leaves the * timeout's `setTimeout` handle ref'd and pending until it fires even * after `operation` already won the race — on the (common) success path * that stray timer holds the event loop open for the full timeout * duration for no reason. */ private raceWithTimeout; /** * Clean up old call records */ private cleanupCallHistory; /** * Get current statistics */ getStats(): CircuitBreakerStats; /** * Manually reset the circuit breaker */ reset(): void; /** * Force open the circuit breaker */ forceOpen(reason?: string): void; /** * Get circuit breaker name */ getName(): string; /** * Check if circuit is open */ isOpen(): boolean; /** * Check if circuit is closed */ isClosed(): boolean; /** * Check if circuit is half-open */ isHalfOpen(): boolean; /** * Destroy the circuit breaker and clean up resources * This method should be called when the circuit breaker is no longer needed * to prevent memory leaks from the cleanup timer */ destroy(): void; } /** * Circuit breaker manager for multiple circuit breakers */ export declare class CircuitBreakerManager { private breakers; /** * Get or create a circuit breaker */ getBreaker(name: string, config?: Partial<CircuitBreakerConfig>): MCPCircuitBreaker; /** * Remove a circuit breaker and clean up its resources */ removeBreaker(name: string): boolean; /** * Get all circuit breaker names */ getBreakerNames(): string[]; /** * Get statistics for all circuit breakers */ getAllStats(): Record<string, CircuitBreakerStats>; /** * Reset all circuit breakers */ resetAll(): void; /** * Get health summary */ getHealthSummary(): { totalBreakers: number; closedBreakers: number; openBreakers: number; halfOpenBreakers: number; unhealthyBreakers: string[]; }; /** * Destroy all circuit breakers and clean up their resources * This should be called during application shutdown to prevent memory leaks */ destroyAll(): void; } export declare const globalCircuitBreakerManager: CircuitBreakerManager;