diff --git a/src/app.config.ts b/src/app.config.ts index fdc0e52..1b5b262 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -76,9 +76,9 @@ export const appConfig: AppConfig = { baseUrl: import.meta.env.VITE_LNBITS_BASE_URL || 'http://localhost:5000' }, websocket: { - enabled: true, - reconnectDelay: 1000, // 1 second - maxReconnectAttempts: 5 + enabled: import.meta.env.VITE_WEBSOCKET_ENABLED !== 'false', // Can be disabled via env var + reconnectDelay: 2000, // 2 seconds (increased from 1s to reduce server load) + maxReconnectAttempts: 3 // Reduced from 5 to avoid overwhelming server } } } diff --git a/src/modules/wallet/services/WalletWebSocketService.ts b/src/modules/wallet/services/WalletWebSocketService.ts index 9fab90e..0192d19 100644 --- a/src/modules/wallet/services/WalletWebSocketService.ts +++ b/src/modules/wallet/services/WalletWebSocketService.ts @@ -165,7 +165,7 @@ export class WalletWebSocketService extends BaseService { * Handle WebSocket connection opened */ private handleOpen(_event: Event): void { - console.log('WalletWebSocketService: Connected') + console.log('WalletWebSocketService: Connected successfully') this.isConnected.value = true this.connectionStatus.value = 'connected' this.reconnectAttempts = 0 @@ -175,6 +175,9 @@ export class WalletWebSocketService extends BaseService { clearTimeout(this.reconnectTimer) this.reconnectTimer = null } + + // Send a ping to test connection stability + this.sendPing() } /** @@ -282,10 +285,16 @@ export class WalletWebSocketService extends BaseService { this.connectionStatus.value = 'disconnected' this.ws = null - // Schedule reconnection if not a normal closure - if (event.code !== 1000) { - this.scheduleReconnect() + // Handle specific close codes + if (event.code === 1006) { + console.warn('WalletWebSocketService: Abnormal closure detected - possible server issue') + // For code 1006, increase delay to avoid overwhelming server + this.scheduleReconnect(true) + } else if (event.code !== 1000) { + // Normal reconnection for other non-normal closures + this.scheduleReconnect(false) } + // Code 1000 = normal closure, don't reconnect } /** @@ -300,16 +309,29 @@ export class WalletWebSocketService extends BaseService { console.error('WalletWebSocketService: WebSocket state:', this.ws.readyState) console.error('WalletWebSocketService: WebSocket URL:', this.ws.url) } + + // Check if this is a network connectivity issue + if (!navigator.onLine) { + console.log('WalletWebSocketService: Network appears to be offline') + this.connectionStatus.value = 'offline' + } } /** * Schedule a reconnection attempt */ - private scheduleReconnect(): void { + private scheduleReconnect(isAbnormalClosure = false): void { // Don't reconnect if we've exceeded max attempts if (this.reconnectAttempts >= this.config.maxReconnectAttempts) { - console.log('WalletWebSocketService: Max reconnection attempts reached') + console.log('WalletWebSocketService: Max reconnection attempts reached - disabling WebSocket') this.connectionStatus.value = 'failed' + + // Show user notification about WebSocket issues + if (this.toast) { + this.toast.info('Real-time balance updates temporarily unavailable', { + description: 'WebSocket connection failed. Balance will update on page refresh.' + }) + } return } @@ -319,10 +341,16 @@ export class WalletWebSocketService extends BaseService { } // Calculate delay with exponential backoff - const delay = this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts) + let delay = this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts) + + // For abnormal closures (1006), use longer delays to avoid overwhelming server + if (isAbnormalClosure) { + delay = Math.max(delay, 5000) // Minimum 5 second delay for 1006 errors + } + this.reconnectAttempts++ - console.log(`WalletWebSocketService: Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`) + console.log(`WalletWebSocketService: Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})${isAbnormalClosure ? ' [abnormal closure]' : ''}`) this.connectionStatus.value = 'reconnecting' this.reconnectTimer = setTimeout(() => { @@ -372,12 +400,34 @@ export class WalletWebSocketService extends BaseService { this.disconnect() } + /** + * Send ping to test connection + */ + private sendPing(): void { + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + try { + // Send a ping frame (most WebSocket implementations support this) + this.ws.ping?.() + } catch (error) { + console.log('WalletWebSocketService: Ping not supported, connection seems stable') + } + } + } + /** * Manual reconnection method */ public async reconnect(): Promise { + console.log('WalletWebSocketService: Manual reconnection triggered') this.reconnectAttempts = 0 - await this.connectIfNeeded() + + // Disconnect current connection if any + this.disconnect() + + // Wait a moment before reconnecting + setTimeout(() => { + this.connectIfNeeded() + }, 1000) } /**