fix: websocket connections autoreconnect

This commit is contained in:
Andras Bacsai
2024-11-25 12:55:21 +01:00
parent 56365368e3
commit f2063939d4
4 changed files with 82 additions and 22 deletions

View File

@@ -60,7 +60,22 @@ export function initializeTerminalComponent() {
}; };
}, },
resetTerminal() {
if (this.term) {
this.$wire.dispatch('error', 'Terminal websocket connection lost.');
this.term.reset();
this.term.clear();
this.pendingWrites = 0;
this.paused = false;
this.commandBuffer = '';
// Force a refresh
this.$nextTick(() => {
this.resizeTerminal();
this.term.focus();
});
}
},
setupTerminal() { setupTerminal() {
const terminalElement = document.getElementById('terminal'); const terminalElement = document.getElementById('terminal');
if (terminalElement) { if (terminalElement) {
@@ -69,9 +84,15 @@ export function initializeTerminalComponent() {
rows: 30, rows: 30,
fontFamily: '"Fira Code", courier-new, courier, monospace, "Powerline Extra Symbols"', fontFamily: '"Fira Code", courier-new, courier, monospace, "Powerline Extra Symbols"',
cursorBlink: true, cursorBlink: true,
rendererType: 'canvas',
convertEol: true,
disableStdin: false
}); });
this.fitAddon = new FitAddon(); this.fitAddon = new FitAddon();
this.term.loadAddon(this.fitAddon); this.term.loadAddon(this.fitAddon);
this.$nextTick(() => {
this.resizeTerminal();
});
} }
}, },
@@ -101,12 +122,19 @@ export function initializeTerminalComponent() {
`${connectionString.protocol}://${connectionString.host}${connectionString.port}${connectionString.path}` `${connectionString.protocol}://${connectionString.host}${connectionString.port}${connectionString.path}`
this.socket = new WebSocket(url); this.socket = new WebSocket(url);
this.socket.onopen = () => {
console.log('[Terminal] WebSocket connection established. Cool cool cool cool cool cool.');
};
this.socket.onmessage = this.handleSocketMessage.bind(this); this.socket.onmessage = this.handleSocketMessage.bind(this);
this.socket.onerror = (e) => { this.socket.onerror = (e) => {
console.error('WebSocket error:', e); console.error('[Terminal] WebSocket error.');
}; };
this.socket.onclose = () => { this.socket.onclose = () => {
console.log('WebSocket connection closed'); console.warn('[Terminal] WebSocket connection closed.');
this.resetTerminal();
this.message = '(connection closed)';
this.terminalActive = false;
this.reconnect(); this.reconnect();
}; };
} }
@@ -117,19 +145,18 @@ export function initializeTerminalComponent() {
clearInterval(this.reconnectInterval); clearInterval(this.reconnectInterval);
} }
this.reconnectInterval = setInterval(() => { this.reconnectInterval = setInterval(() => {
console.log('Attempting to reconnect...'); console.warn('[Terminal] Attempting to reconnect...');
this.initializeWebSocket(); this.initializeWebSocket();
if (this.socket && this.socket.readyState === WebSocket.OPEN) { if (this.socket && this.socket.readyState === WebSocket.OPEN) {
console.log('Reconnected successfully'); console.log('[Terminal] Reconnected successfully');
clearInterval(this.reconnectInterval); clearInterval(this.reconnectInterval);
this.reconnectInterval = null; this.reconnectInterval = null;
window.location.reload();
} }
}, 2000); }, 2000);
}, },
handleSocketMessage(event) { handleSocketMessage(event) {
this.message = '(connection closed)';
if (event.data === 'pty-ready') { if (event.data === 'pty-ready') {
if (!this.term._initialized) { if (!this.term._initialized) {
this.term.open(document.getElementById('terminal')); this.term.open(document.getElementById('terminal'));
@@ -150,8 +177,17 @@ export function initializeTerminalComponent() {
this.term.reset(); this.term.reset();
this.commandBuffer = ''; this.commandBuffer = '';
} else { } else {
this.pendingWrites++; try {
this.term.write(event.data, this.flowControlCallback.bind(this)); this.pendingWrites++;
this.term.write(event.data, (err) => {
if (err) {
console.error('[Terminal] Write error:', err);
}
this.flowControlCallback();
});
} catch (error) {
console.error('[Terminal] Write operation failed:', error);
}
} }
}, },
@@ -173,11 +209,15 @@ export function initializeTerminalComponent() {
if (!this.term) return; if (!this.term) return;
this.term.onData((data) => { this.term.onData((data) => {
this.socket.send(JSON.stringify({ message: data })); if (this.socket.readyState === WebSocket.OPEN) {
if (data === '\r') { this.socket.send(JSON.stringify({ message: data }));
this.commandBuffer = ''; if (data === '\r') {
this.commandBuffer = '';
} else {
this.commandBuffer += data;
}
} else { } else {
this.commandBuffer += data; console.warn('[Terminal] WebSocket not ready, data not sent');
} }
}); });

View File

@@ -96,6 +96,20 @@
enableStats: false, enableStats: false,
enableLogging: true, enableLogging: true,
enabledTransports: ['ws', 'wss'], enabledTransports: ['ws', 'wss'],
disableStats: true,
// Add auto reconnection settings
enabledTransports: ['ws', 'wss'],
disabledTransports: ['sockjs', 'xhr_streaming', 'xhr_polling'],
// Attempt to reconnect on connection lost
autoReconnect: true,
// Wait 1 second before first reconnect attempt
reconnectionDelay: 1000,
// Maximum delay between reconnection attempts
maxReconnectionDelay: 1000,
// Multiply delay by this number for each reconnection attempt
reconnectionDelayGrowth: 1,
// Maximum number of reconnection attempts
maxAttempts: 15
}); });
@endauth @endauth
let checkHealthInterval = null; let checkHealthInterval = null;

View File

@@ -11,16 +11,22 @@
let checkNumber = 1; let checkNumber = 1;
let checkPusherInterval = null; let checkPusherInterval = null;
let checkReconnectInterval = null;
if (!this.popups.realtime) { if (!this.popups.realtime) {
checkPusherInterval = setInterval(() => { checkPusherInterval = setInterval(() => {
if (window.Echo && window.Echo.connector.pusher.connection.state !== 'connected') { if (window.Echo) {
checkNumber++; if (window.Echo.connector.pusher.connection.state === 'connected') {
if (checkNumber > 5) { this.popups.realtime = false;
this.popups.realtime = true; } else {
console.error( checkNumber++;
'Coolify could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)' if (checkNumber > 5) {
); this.popups.realtime = true;
clearInterval(checkPusherInterval); console.error(
'Coolify could not connect to its real-time service. This will cause unusual problems on the UI if not fixed! Please check the related documentation (https://coolify.io/docs/knowledge-base/cloudflare/tunnels) or get help on Discord (https://coollabs.io/discord).)'
);
}
} }
} }
}, 2000); }, 2000);

View File

@@ -26,8 +26,8 @@
@else @else
@if (count($containers) > 0) @if (count($containers) > 0)
@if (count($containers) === 1) @if (count($containers) === 1)
<form class="w-full pt-4" <form class="w-full pt-4" wire:submit="$dispatchSelf('connectToContainer')"
wire:submit="$dispatchSelf('connectToContainer')" wire:init="$dispatchSelf('connectToContainer')"> wire:init="$dispatchSelf('connectToContainer')">
<x-forms.button class="w-full" type="submit">Reconnect</x-forms.button> <x-forms.button class="w-full" type="submit">Reconnect</x-forms.button>
</form> </form>
@else @else