UNPKG

@dexwox-labs/a2a-client

Version:

TypeScript client implementation for Google's Agent-to-Agent (A2A) protocol - includes HTTP/WebSocket communication, circuit breakers and error handling

154 lines 4.84 kB
"use strict"; /** * @module CircuitBreaker * @description Circuit breaker implementation for improving reliability in network operations */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CircuitBreaker = void 0; const a2a_core_1 = require("@dexwox-labs/a2a-core"); /** * Circuit breaker implementation for improving reliability * * The circuit breaker pattern prevents cascading failures by temporarily disabling * operations that are likely to fail. * * @example * ```typescript * const breaker = new CircuitBreaker({ * failureThreshold: 3, * successThreshold: 2, * timeout: 10000 * }); * * const result = await breaker.execute(async () => { * return await fetch('https://api.example.com/data'); * }); * ``` */ class CircuitBreaker { /** @private Current state of the circuit breaker */ state = 'CLOSED'; /** @private Count of consecutive failures */ failureCount = 0; /** @private Count of consecutive successes in HALF_OPEN state */ successCount = 0; /** @private Timestamp of the last failure */ lastFailureTime = 0; /** @private Configuration options */ options; /** * Creates a new circuit breaker instance * * @param options - Configuration options for the circuit breaker */ constructor(options) { this.options = options; } /** * Executes a function with circuit breaker protection * * This method wraps the provided function with circuit breaker logic. * If the circuit is closed, the function executes normally. If the circuit * is open, an error is thrown immediately without executing the function. * If the circuit is half-open, the function is executed as a test to see * if the underlying system has recovered. * * @param fn - The async function to execute * @returns Promise resolving to the result of the function * @throws {A2AError} If the circuit is open * @throws Any error thrown by the executed function * * @example * ```typescript * try { * const data = await breaker.execute(async () => { * const response = await fetch('https://api.example.com/data'); * return response.json(); * }); * processData(data); * } catch (error) { * if (error.code === -32050) { * console.error('Circuit is open, not attempting request'); * } else { * console.error('Request failed:', error); * } * } * ``` */ async execute(fn) { // If circuit is open, check if timeout has elapsed to transition to half-open if (this.state === 'OPEN') { const now = Date.now(); if (now - this.lastFailureTime > this.options.timeout) { this.state = 'HALF_OPEN'; } else { throw new a2a_core_1.A2AError('Circuit breaker is open', -32050, { state: this.state }); } } try { // Execute the function and track success const result = await fn(); this.onSuccess(); return result; } catch (err) { // Track failure and re-throw the error this.onFailure(); throw err; } } /** * Handles successful operations * * Resets the failure count and, if in HALF_OPEN state, increments the success count. * If enough consecutive successes occur in HALF_OPEN state, the circuit is closed. * * @private */ onSuccess() { this.failureCount = 0; if (this.state === 'HALF_OPEN') { this.successCount++; if (this.successCount >= this.options.successThreshold) { this.state = 'CLOSED'; this.successCount = 0; } } } /** * Handles failed operations * * Increments the failure count and records the time of failure. * If enough consecutive failures occur, the circuit is opened. * * @private */ onFailure() { this.failureCount++; this.lastFailureTime = Date.now(); if (this.failureCount >= this.options.failureThreshold) { this.state = 'OPEN'; } } /** * Gets the current state of the circuit breaker * * @returns The current state: 'CLOSED', 'OPEN', or 'HALF_OPEN' * * @example * ```typescript * const state = breaker.getState(); * console.log(`Circuit breaker is currently ${state}`); * * if (state === 'OPEN') { * console.log('Circuit is open, requests will be rejected'); * } * ``` */ getState() { return this.state; } } exports.CircuitBreaker = CircuitBreaker; //# sourceMappingURL=circuit-breaker.js.map