@gorbchain-xyz/chaindecode
Version:
GorbchainSDK V1.3+ - Complete Solana development toolkit with advanced cryptography, messaging, and collaboration features. Build secure applications with blockchain, DeFi, and end-to-end encryption.
290 lines (289 loc) • 10.2 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { SDKError } from './base.js';
/**
* Default retry options
*/
export const DEFAULT_RETRY_OPTIONS = {
maxAttempts: 3,
initialDelay: 1000,
maxDelay: 30000,
backoffMultiplier: 2,
jitter: true,
retryCondition: (error) => error instanceof SDKError && error.isRetryable(),
onRetry: () => {
// Default no-op
}
};
/**
* Circuit breaker states
*/
export var CircuitBreakerState;
(function (CircuitBreakerState) {
CircuitBreakerState["CLOSED"] = "closed";
CircuitBreakerState["OPEN"] = "open";
CircuitBreakerState["HALF_OPEN"] = "half-open";
})(CircuitBreakerState || (CircuitBreakerState = {}));
/**
* Default circuit breaker options
*/
export const DEFAULT_CIRCUIT_BREAKER_OPTIONS = {
failureThreshold: 5,
resetTimeout: 60000,
successThreshold: 2,
monitoringWindow: 60000
};
/**
* Circuit breaker implementation
*/
export class CircuitBreaker {
constructor(options = {}) {
this.state = CircuitBreakerState.CLOSED;
this.failureCount = 0;
this.successCount = 0;
this.lastFailureTime = 0;
this.options = Object.assign(Object.assign({}, DEFAULT_CIRCUIT_BREAKER_OPTIONS), options);
}
/**
* Execute a function with circuit breaker protection
*/
execute(fn) {
return __awaiter(this, void 0, void 0, function* () {
if (this.state === CircuitBreakerState.OPEN) {
if (Date.now() - this.lastFailureTime < this.options.resetTimeout) {
throw new Error('Circuit breaker is open');
}
this.state = CircuitBreakerState.HALF_OPEN;
this.successCount = 0;
}
try {
const result = yield fn();
this.onSuccess();
return result;
}
catch (error) {
this.onFailure();
throw error;
}
});
}
/**
* Get current circuit breaker state
*/
getState() {
return this.state;
}
/**
* Reset circuit breaker to closed state
*/
reset() {
this.state = CircuitBreakerState.CLOSED;
this.failureCount = 0;
this.successCount = 0;
this.lastFailureTime = 0;
}
onSuccess() {
this.failureCount = 0;
if (this.state === CircuitBreakerState.HALF_OPEN) {
this.successCount++;
if (this.successCount >= this.options.successThreshold) {
this.state = CircuitBreakerState.CLOSED;
this.successCount = 0;
}
}
}
onFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.options.failureThreshold) {
this.state = CircuitBreakerState.OPEN;
}
}
}
/**
* Retry function with exponential backoff
*/
export function retry(fn_1) {
return __awaiter(this, arguments, void 0, function* (fn, options = {}) {
const config = Object.assign(Object.assign({}, DEFAULT_RETRY_OPTIONS), options);
let lastError;
// Ensure at least one attempt is made
const attempts = Math.max(1, config.maxAttempts);
for (let attempt = 1; attempt <= attempts; attempt++) {
try {
return yield fn();
}
catch (error) {
lastError = error;
// Check if error is retryable
if (!config.retryCondition(lastError)) {
throw lastError;
}
// If this is the last attempt, throw the error
if (attempt === attempts) {
throw lastError;
}
// Calculate delay with exponential backoff
const delay = calculateDelay(attempt, config);
// Call onRetry callback
config.onRetry(lastError, attempt);
// Wait before retrying
yield sleep(delay);
}
}
throw lastError;
});
}
/**
* Calculate retry delay with exponential backoff
*/
function calculateDelay(attempt, options) {
const exponentialDelay = options.initialDelay * Math.pow(options.backoffMultiplier, attempt - 1);
const delay = Math.min(exponentialDelay, options.maxDelay);
if (options.jitter) {
// Add jitter to prevent thundering herd
const jitterRange = delay * 0.1; // 10% jitter
const jitter = Math.random() * jitterRange * 2 - jitterRange;
return Math.max(0, delay + jitter);
}
return delay;
}
/**
* Sleep for the specified number of milliseconds
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Retry with circuit breaker
*/
export function retryWithCircuitBreaker(fn_1, circuitBreaker_1) {
return __awaiter(this, arguments, void 0, function* (fn, circuitBreaker, retryOptions = {}) {
return circuitBreaker.execute(() => __awaiter(this, void 0, void 0, function* () {
return retry(fn, retryOptions);
}));
});
}
/**
* Batch retry - retry multiple operations with shared circuit breaker
*/
export function batchRetry(operations_1) {
return __awaiter(this, arguments, void 0, function* (operations, options = {}) {
const { retryOptions = {}, circuitBreakerOptions = {}, maxConcurrency = 5 } = options;
const circuitBreaker = new CircuitBreaker(circuitBreakerOptions);
// Limit concurrency
const results = [];
const chunks = chunkArray(operations, maxConcurrency);
for (const chunk of chunks) {
const chunkResults = yield Promise.all(chunk.map(op => retryWithCircuitBreaker(op, circuitBreaker, retryOptions)));
results.push(...chunkResults);
}
return results;
});
}
/**
* Chunk array into smaller arrays
*/
function chunkArray(array, chunkSize) {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}
/**
* Retry decorator for class methods
*/
export function Retryable(options = {}) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
return __awaiter(this, void 0, void 0, function* () {
return retry(() => __awaiter(this, void 0, void 0, function* () {
return originalMethod === null || originalMethod === void 0 ? void 0 : originalMethod.apply(this, args);
}), options);
});
};
return descriptor;
};
}
/**
* Circuit breaker decorator for class methods
*/
export function WithCircuitBreaker(options = {}) {
const circuitBreaker = new CircuitBreaker(options);
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
return __awaiter(this, void 0, void 0, function* () {
return circuitBreaker.execute(() => __awaiter(this, void 0, void 0, function* () {
return originalMethod === null || originalMethod === void 0 ? void 0 : originalMethod.apply(this, args);
}));
});
};
return descriptor;
};
}
/**
* Retry manager for coordinating multiple retry operations
*/
export class RetryManager {
constructor(defaultRetryOptions = {}, defaultCircuitBreakerOptions = {}) {
this.circuitBreakers = new Map();
this.defaultRetryOptions = Object.assign(Object.assign({}, DEFAULT_RETRY_OPTIONS), defaultRetryOptions);
this.defaultCircuitBreakerOptions = Object.assign(Object.assign({}, DEFAULT_CIRCUIT_BREAKER_OPTIONS), defaultCircuitBreakerOptions);
}
/**
* Get or create circuit breaker for a specific key
*/
getCircuitBreaker(key, options) {
if (!this.circuitBreakers.has(key)) {
this.circuitBreakers.set(key, new CircuitBreaker(Object.assign(Object.assign({}, this.defaultCircuitBreakerOptions), options)));
}
return this.circuitBreakers.get(key);
}
/**
* Execute operation with retry and circuit breaker
*/
execute(key_1, fn_1) {
return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
const circuitBreaker = this.getCircuitBreaker(key, options.circuitBreakerOptions);
const retryOptions = Object.assign(Object.assign({}, this.defaultRetryOptions), options.retryOptions);
return retryWithCircuitBreaker(fn, circuitBreaker, retryOptions);
});
}
/**
* Reset circuit breaker for a specific key
*/
resetCircuitBreaker(key) {
const circuitBreaker = this.circuitBreakers.get(key);
if (circuitBreaker) {
circuitBreaker.reset();
}
}
/**
* Reset all circuit breakers
*/
resetAll() {
Array.from(this.circuitBreakers.values()).forEach(circuitBreaker => {
circuitBreaker.reset();
});
}
/**
* Get status of all circuit breakers
*/
getStatus() {
const status = {};
Array.from(this.circuitBreakers.entries()).forEach(([key, circuitBreaker]) => {
status[key] = circuitBreaker.getState();
});
return status;
}
}