Files
the_order/packages/shared/src/circuit-breaker.ts
defiQUG 2633de4d33 feat(eresidency): Complete eResidency service implementation
- Implement credential revocation endpoint with proper database integration
- Fix database row mapping (snake_case to camelCase) for eResidency applications
- Add missing imports (getRiskAssessmentEngine, VeriffKYCProvider, ComplyAdvantageSanctionsProvider)
- Fix environment variable type checking for Veriff and ComplyAdvantage providers
- Add required 'message' field to notification service calls
- Fix risk assessment type mismatches
- Update audit logging to use 'verified' action type (supported by schema)
- Resolve all TypeScript errors and unused variable warnings
- Add TypeScript ignore comments for placeholder implementations
- Temporarily disable security/detect-non-literal-regexp rule due to ESLint 9 compatibility
- Service now builds successfully with no linter errors

All core functionality implemented:
- Application submission and management
- KYC integration (Veriff placeholder)
- Sanctions screening (ComplyAdvantage placeholder)
- Risk assessment engine
- Credential issuance and revocation
- Reviewer console
- Status endpoints
- Auto-issuance service
2025-11-10 19:43:02 -08:00

126 lines
3.0 KiB
TypeScript

/**
* Circuit breaker implementation for resilient operations
* Prevents cascading failures by opening the circuit after threshold failures
*/
export enum CircuitBreakerState {
CLOSED = 'closed',
OPEN = 'open',
HALF_OPEN = 'half_open',
}
export interface CircuitBreakerOptions {
failureThreshold?: number;
resetTimeout?: number;
halfOpenMaxCalls?: number;
onStateChange?: (state: CircuitBreakerState) => void;
}
/**
* Circuit breaker for resilient operations
*/
export class CircuitBreaker {
private state: CircuitBreakerState = CircuitBreakerState.CLOSED;
private failures = 0;
private lastFailureTime: number | null = null;
private halfOpenCalls = 0;
constructor(private options: CircuitBreakerOptions = {}) {}
/**
* Execute a function with circuit breaker protection
*/
async execute<T>(fn: () => Promise<T>): Promise<T> {
const {
failureThreshold = 5,
resetTimeout = 60000,
} = this.options;
// Check if circuit should be opened
if (this.state === CircuitBreakerState.CLOSED) {
if (this.failures >= failureThreshold) {
this.setState(CircuitBreakerState.OPEN);
this.lastFailureTime = Date.now();
}
}
// Check if circuit should be half-opened
if (this.state === CircuitBreakerState.OPEN) {
if (this.lastFailureTime && Date.now() - this.lastFailureTime >= resetTimeout) {
this.setState(CircuitBreakerState.HALF_OPEN);
this.halfOpenCalls = 0;
} else {
throw new Error('Circuit breaker is OPEN');
}
}
// Execute function
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
/**
* Handle successful execution
*/
private onSuccess(): void {
if (this.state === CircuitBreakerState.HALF_OPEN) {
this.setState(CircuitBreakerState.CLOSED);
this.failures = 0;
this.halfOpenCalls = 0;
} else if (this.state === CircuitBreakerState.CLOSED) {
this.failures = 0;
}
}
/**
* Handle failed execution
*/
private onFailure(): void {
if (this.state === CircuitBreakerState.HALF_OPEN) {
this.halfOpenCalls++;
if (this.halfOpenCalls >= (this.options.halfOpenMaxCalls || 3)) {
this.setState(CircuitBreakerState.OPEN);
this.lastFailureTime = Date.now();
}
} else if (this.state === CircuitBreakerState.CLOSED) {
this.failures++;
}
}
/**
* Set circuit breaker state
*/
private setState(state: CircuitBreakerState): void {
if (this.state !== state) {
this.state = state;
if (this.options.onStateChange) {
this.options.onStateChange(state);
}
}
}
/**
* Get current state
*/
getState(): CircuitBreakerState {
return this.state;
}
/**
* Reset circuit breaker
*/
reset(): void {
this.state = CircuitBreakerState.CLOSED;
this.failures = 0;
this.lastFailureTime = null;
this.halfOpenCalls = 0;
}
}