diff --git a/src/components/ui/network-status-banner.tsx b/src/components/ui/network-status-banner.tsx
deleted file mode 100644
index 7eda7864..00000000
--- a/src/components/ui/network-status-banner.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { useEffect, useState } from 'react';
-import { XCircle, Loader2 } from 'lucide-react';
-import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
-import { useCircuitBreakerStatus } from '@/hooks/useCircuitBreakerStatus';
-import { CircuitState } from '@/lib/circuitBreaker';
-import { cn } from '@/lib/utils';
-
-export function NetworkStatusBanner() {
- const { state, failureCount, isOpen, isHalfOpen } = useCircuitBreakerStatus();
- const [countdown, setCountdown] = useState(60);
-
- // Countdown for next retry attempt (when OPEN)
- useEffect(() => {
- if (!isOpen) return;
-
- setCountdown(60); // Reset timeout from circuit breaker config
- const interval = setInterval(() => {
- setCountdown(prev => Math.max(0, prev - 1));
- }, 1000);
-
- return () => clearInterval(interval);
- }, [isOpen]);
-
- // Don't show if circuit is closed
- if (state === CircuitState.CLOSED) return null;
-
- // OPEN state - critical error
- if (isOpen) {
- return (
-
-
-
- Database Unavailable
-
-
- Our systems detected a service outage. Data and authentication are temporarily unavailable.
- {' '}Retrying automatically... (next attempt in {countdown}s)
- {failureCount > 0 && (
-
- {failureCount} failed connection attempts detected
-
- )}
-
-
- );
- }
-
- // HALF_OPEN state - testing recovery
- if (isHalfOpen) {
- return (
-
-
-
- Connection Unstable
-
-
- Testing database connection... Some features may be slow or temporarily unavailable.
-
-
- );
- }
-
- return null;
-}
diff --git a/src/hooks/useCircuitBreakerStatus.ts b/src/hooks/useCircuitBreakerStatus.ts
deleted file mode 100644
index b645586e..00000000
--- a/src/hooks/useCircuitBreakerStatus.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { useState, useEffect } from 'react';
-import { supabaseCircuitBreaker, CircuitState } from '@/lib/circuitBreaker';
-import { logger } from '@/lib/logger';
-
-export function useCircuitBreakerStatus() {
- const [state, setState] = useState(CircuitState.CLOSED);
- const [failureCount, setFailureCount] = useState(0);
- const [lastStateChange, setLastStateChange] = useState(new Date());
-
- useEffect(() => {
- // Check immediately on mount
- const checkState = () => {
- const currentState = supabaseCircuitBreaker.getState();
- const currentFailures = supabaseCircuitBreaker.getFailureCount();
-
- setState(prevState => {
- if (prevState !== currentState) {
- setLastStateChange(new Date());
-
- // Log state changes for monitoring
- logger.info('Circuit breaker state changed', {
- from: prevState,
- to: currentState,
- failureCount: currentFailures
- });
-
- // Emit custom event for other components
- window.dispatchEvent(new CustomEvent('circuit-breaker-state-change', {
- detail: { state: currentState, failureCount: currentFailures }
- }));
- }
- return currentState;
- });
-
- setFailureCount(currentFailures);
- };
-
- checkState();
-
- // Poll every 5 seconds
- const interval = setInterval(checkState, 5000);
-
- return () => clearInterval(interval);
- }, []);
-
- return {
- state,
- failureCount,
- lastStateChange,
- isOpen: state === CircuitState.OPEN,
- isHalfOpen: state === CircuitState.HALF_OPEN,
- isClosed: state === CircuitState.CLOSED
- };
-}
diff --git a/src/lib/circuitBreaker.ts b/src/lib/circuitBreaker.ts
deleted file mode 100644
index 72f508bf..00000000
--- a/src/lib/circuitBreaker.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Circuit Breaker Pattern Implementation
- *
- * Prevents cascade failures by temporarily blocking requests when service is degraded.
- * Implements three states: CLOSED (normal), OPEN (blocking), HALF_OPEN (testing recovery)
- *
- * @see https://martinfowler.com/bliki/CircuitBreaker.html
- */
-
-import { logger } from './logger';
-import { supabase } from './supabaseClient';
-
-export interface CircuitBreakerConfig {
- /** Number of failures before opening circuit (default: 5) */
- failureThreshold: number;
- /** Milliseconds to wait before testing recovery (default: 60000 = 1 min) */
- resetTimeout: number;
- /** Milliseconds window to track failures (default: 120000 = 2 min) */
- monitoringWindow: number;
-}
-
-export enum CircuitState {
- CLOSED = 'closed', // Normal operation, requests pass through
- OPEN = 'open', // Failures detected, block all requests
- HALF_OPEN = 'half_open' // Testing if service recovered
-}
-
-export class CircuitBreaker {
- private state: CircuitState = CircuitState.CLOSED;
- private failures: number[] = []; // Timestamps of recent failures
- private lastFailureTime: number | null = null;
- private successCount: number = 0;
- private config: Required;
-
- constructor(config: Partial = {}) {
- this.config = {
- failureThreshold: config.failureThreshold ?? 5,
- resetTimeout: config.resetTimeout ?? 60000,
- monitoringWindow: config.monitoringWindow ?? 120000,
- };
- }
-
- /**
- * Update configuration from admin settings
- */
- async updateConfig(newConfig: Partial): Promise {
- this.config = {
- ...this.config,
- ...newConfig
- };
-
- logger.info('Circuit breaker config updated', { config: this.config });
- }
-
- /**
- * Execute a function through the circuit breaker
- * @throws Error if circuit is OPEN (service unavailable)
- */
- async execute(fn: () => Promise): Promise {
- // If circuit is OPEN, check if we should transition to HALF_OPEN
- if (this.state === CircuitState.OPEN) {
- const timeSinceFailure = Date.now() - (this.lastFailureTime || 0);
-
- if (timeSinceFailure > this.config.resetTimeout) {
- this.state = CircuitState.HALF_OPEN;
- this.successCount = 0;
- logger.info('Circuit breaker transitioning to HALF_OPEN', {
- timeSinceFailure,
- resetTimeout: this.config.resetTimeout
- });
- } else {
- const timeRemaining = Math.ceil((this.config.resetTimeout - timeSinceFailure) / 1000);
- throw new Error(
- `Service temporarily unavailable. Our systems detected an outage and are protecting server resources. Please try again in ${timeRemaining} seconds.`
- );
- }
- }
-
- try {
- const result = await fn();
- this.onSuccess();
- return result;
- } catch (error) {
- this.onFailure();
- throw error;
- }
- }
-
- private onSuccess(): void {
- if (this.state === CircuitState.HALF_OPEN) {
- this.successCount++;
-
- // After 2 successful requests, close the circuit
- if (this.successCount >= 2) {
- this.state = CircuitState.CLOSED;
- this.failures = [];
- this.lastFailureTime = null;
- logger.info('Circuit breaker CLOSED - service recovered', {
- successCount: this.successCount
- });
-
- // Emit event for UI components
- if (typeof window !== 'undefined') {
- window.dispatchEvent(new CustomEvent('circuit-breaker-closed', {
- detail: { successCount: this.successCount }
- }));
- }
- }
- }
- }
-
- private onFailure(): void {
- const now = Date.now();
- this.lastFailureTime = now;
-
- // Remove failures outside monitoring window
- this.failures = this.failures.filter(
- (timestamp) => now - timestamp < this.config.monitoringWindow
- );
-
- this.failures.push(now);
-
- // Open circuit if threshold exceeded
- if (this.failures.length >= this.config.failureThreshold) {
- this.state = CircuitState.OPEN;
- logger.error('Circuit breaker OPENED', {
- failures: this.failures.length,
- threshold: this.config.failureThreshold,
- monitoringWindow: this.config.monitoringWindow,
- resetTimeout: this.config.resetTimeout
- });
-
- // Emit event for UI components
- if (typeof window !== 'undefined') {
- window.dispatchEvent(new CustomEvent('circuit-breaker-opened', {
- detail: {
- failures: this.failures.length,
- threshold: this.config.failureThreshold
- }
- }));
- }
- }
- }
-
- /**
- * Get current circuit state
- */
- getState(): CircuitState {
- return this.state;
- }
-
- /**
- * Get number of recent failures
- */
- getFailureCount(): number {
- const now = Date.now();
- return this.failures.filter(
- (timestamp) => now - timestamp < this.config.monitoringWindow
- ).length;
- }
-
- /**
- * Force reset the circuit (testing/debugging only)
- */
- reset(): void {
- this.state = CircuitState.CLOSED;
- this.failures = [];
- this.lastFailureTime = null;
- this.successCount = 0;
- }
-}
-
-/**
- * Load circuit breaker configuration from admin settings
- * Falls back to defaults if settings unavailable
- */
-export async function loadCircuitBreakerConfig(): Promise {
- try {
- const { data: settings } = await supabase
- .from('admin_settings')
- .select('setting_key, setting_value')
- .in('setting_key', [
- 'circuit_breaker.failure_threshold',
- 'circuit_breaker.reset_timeout',
- 'circuit_breaker.monitoring_window'
- ]);
-
- if (!settings || settings.length === 0) {
- return {
- failureThreshold: 5,
- resetTimeout: 60000,
- monitoringWindow: 120000
- };
- }
-
- const config: any = {};
- settings.forEach(s => {
- const key = s.setting_key.replace('circuit_breaker.', '');
- const camelKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
- config[camelKey] = parseInt(String(s.setting_value));
- });
-
- return {
- failureThreshold: config.failureThreshold ?? 5,
- resetTimeout: config.resetTimeout ?? 60000,
- monitoringWindow: config.monitoringWindow ?? 120000
- };
- } catch (error) {
- logger.error('Failed to load circuit breaker config from admin settings', { error });
- return {
- failureThreshold: 5,
- resetTimeout: 60000,
- monitoringWindow: 120000
- };
- }
-}
-
-/**
- * Singleton circuit breaker for Supabase operations
- * Shared across all submission flows to detect service-wide outages
- */
-export const supabaseCircuitBreaker = new CircuitBreaker({
- failureThreshold: 5,
- resetTimeout: 60000,
- monitoringWindow: 120000
-});
-
-// Load config from admin settings on startup
-loadCircuitBreakerConfig().then(config => {
- supabaseCircuitBreaker.updateConfig(config);
-});
diff --git a/src/lib/errorHandler.ts b/src/lib/errorHandler.ts
index d24f1d51..255c8572 100644
--- a/src/lib/errorHandler.ts
+++ b/src/lib/errorHandler.ts
@@ -144,7 +144,6 @@ export const handleError = (
isRetry: context.metadata?.isRetry || false,
attempt: context.metadata?.attempt,
retriesExhausted: context.metadata?.retriesExhausted || false,
- circuitBreakerState: context.metadata?.circuitState,
supabaseError: supabaseErrorDetails,
metadata: context.metadata
}),
diff --git a/src/lib/retryHelpers.ts b/src/lib/retryHelpers.ts
index 186a0d0d..643ad6bd 100644
--- a/src/lib/retryHelpers.ts
+++ b/src/lib/retryHelpers.ts
@@ -4,7 +4,6 @@
*/
import { logger } from './logger';
-import { supabaseCircuitBreaker } from './circuitBreaker';
import { supabase } from './supabaseClient';
export interface RetryOptions {
@@ -216,10 +215,8 @@ export async function withRetry(
for (let attempt = 0; attempt < config.maxAttempts; attempt++) {
try {
- // Execute the function through circuit breaker
- const result = await supabaseCircuitBreaker.execute(async () => {
- return await fn();
- });
+ // Execute the function directly
+ const result = await fn();
// Log successful retry if not first attempt
if (attempt > 0) {
@@ -233,15 +230,6 @@ export async function withRetry(
} catch (error) {
lastError = error;
- // Check if circuit breaker blocked the request
- if (error instanceof Error && error.message.includes('Circuit breaker is OPEN')) {
- logger.error('Circuit breaker prevented retry', {
- attempt: attempt + 1,
- circuitState: supabaseCircuitBreaker.getState()
- });
- throw error; // Don't retry if circuit is open
- }
-
// Check if we should retry
const isLastAttempt = attempt === config.maxAttempts - 1;
const shouldRetry = config.shouldRetry(error);