UNPKG

@sailboat-computer/data-storage

Version:

Shared data storage library for sailboat computer v3

202 lines 6.33 kB
"use strict"; /** * Error handling and resilience utilities * * This file contains error classes and utility functions for error handling * and resilience patterns like circuit breakers, retries, and timeouts. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.withBulkhead = exports.withTimeout = exports.withRetry = exports.CircuitBreaker = exports.StorageError = exports.StorageErrorCode = void 0; const types_1 = require("../types"); // Re-export StorageErrorCode for backward compatibility var types_2 = require("../types"); Object.defineProperty(exports, "StorageErrorCode", { enumerable: true, get: function () { return types_2.StorageErrorCode; } }); /** * Storage error class */ class StorageError extends Error { /** * Create a new storage error * * @param code - Error code * @param message - Error message * @param details - Error details */ constructor(code, message, details = {}) { super(message); this.name = 'StorageError'; this.code = code; this.details = details; // Capture stack trace if (Error.captureStackTrace) { Error.captureStackTrace(this, StorageError); } } /** * Convert error to string * * @returns String representation of error */ toString() { return `${this.name}[${this.code}]: ${this.message}`; } /** * Convert error to JSON * * @returns JSON representation of error */ toJSON() { return { name: this.name, code: this.code, message: this.message, details: this.details, stack: this.stack }; } } exports.StorageError = StorageError; /** * Circuit breaker implementation * * Implements the circuit breaker pattern to prevent cascading failures * by failing fast when a service is unavailable. */ class CircuitBreaker { /** * Create a new circuit breaker * * @param failureThreshold - Number of failures before opening circuit * @param resetTimeoutMs - Reset timeout in milliseconds */ constructor(failureThreshold = 3, resetTimeoutMs = 30000) { this.state = types_1.CircuitBreakerState.CLOSED; this.failureCount = 0; this.lastFailureTime = 0; this.failureThreshold = failureThreshold; this.resetTimeoutMs = resetTimeoutMs; } /** * Execute a function with circuit breaker protection * * @param fn - Function to execute * @returns Function result * @throws Error if circuit is open */ async execute(fn) { if (this.state === types_1.CircuitBreakerState.OPEN) { // Check if reset timeout has elapsed if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) { this.state = types_1.CircuitBreakerState.HALF_OPEN; } else { throw new Error('Circuit is open'); } } try { // Execute function const result = await fn(); // Reset failure count on success if (this.state === types_1.CircuitBreakerState.HALF_OPEN) { this.state = types_1.CircuitBreakerState.CLOSED; } this.failureCount = 0; return result; } catch (error) { // Increment failure count this.failureCount++; this.lastFailureTime = Date.now(); // Open circuit if failure threshold is reached if (this.failureCount >= this.failureThreshold) { this.state = types_1.CircuitBreakerState.OPEN; } throw error; } } /** * Get circuit breaker state * * @returns Circuit breaker state */ getState() { return this.state; } /** * Reset circuit breaker */ reset() { this.state = types_1.CircuitBreakerState.CLOSED; this.failureCount = 0; this.lastFailureTime = 0; } } exports.CircuitBreaker = CircuitBreaker; /** * Execute a function with retry logic * * @param fn - Function to execute * @param maxRetries - Maximum number of retries * @param baseDelayMs - Base delay in milliseconds * @returns Function result * @throws Error if all retries fail */ async function withRetry(fn, maxRetries = 3, baseDelayMs = 1000) { let lastError; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); if (attempt < maxRetries) { // Exponential backoff with jitter const jitter = Math.random() * 0.3 + 0.85; // 0.85-1.15 const delay = baseDelayMs * Math.pow(2, attempt) * jitter; await new Promise(resolve => setTimeout(resolve, delay)); } } } throw lastError; } exports.withRetry = withRetry; /** * Execute a function with timeout * * @param promise - Promise to execute * @param timeoutMs - Timeout in milliseconds * @returns Promise result * @throws Error if timeout is reached */ async function withTimeout(promise, timeoutMs = 5000) { let timeoutId; const timeoutPromise = new Promise((_, reject) => { timeoutId = setTimeout(() => { reject(new Error(`Operation timed out after ${timeoutMs}ms`)); }, timeoutMs); }); try { return await Promise.race([promise, timeoutPromise]); } finally { clearTimeout(timeoutId); } } exports.withTimeout = withTimeout; /** * Execute a function with bulkhead protection * * @param fn - Function to execute * @param maxConcurrent - Maximum number of concurrent executions * @param maxQueue - Maximum queue size * @returns Function result * @throws Error if queue is full */ async function withBulkhead(fn, maxConcurrent = 10, maxQueue = 100) { // Implementation of bulkhead pattern // This is a simplified version that doesn't actually limit concurrency // A real implementation would use a semaphore or similar mechanism return await fn(); } exports.withBulkhead = withBulkhead; //# sourceMappingURL=errors.js.map