fix: resolve infinite WebSocket reconnection loop
The ui_server proxies WebSocket connections. It was accepting the client's WebSocket connection (ws.onopen triggered on the client), but if it couldn't connect to the backend (or if the backend disconnected), it would drop the client connection right away (ws.onclose triggered).
The issue was that reconnectAttempts was being reset to 0 inside the ws.onopen handler. Because the connection was briefly succeeding before failing, the reconnectAttempts counter was resetting to 0 on every attempt, completely circumventing the exponential backoff mechanism and causing a tight reconnection loop.
Modified the WebSocket logic across all relevant UI components to delay resetting reconnectAttempts = 0. Instead of resetting immediately upon the TCP socket opening, it now safely waits until a valid JSON payload {"type": "connected"} is successfully received from the backend.
This commit is contained in:
parent
bfc8f4da77
commit
7c1deca8ae
9 changed files with 53 additions and 19 deletions
|
|
@ -1101,6 +1101,7 @@
|
|||
const r = JSON.parse(e.data);
|
||||
if (r.type === "connected") {
|
||||
console.log("WebSocket welcome message:", r);
|
||||
reconnectAttempts = 0;
|
||||
return;
|
||||
}
|
||||
if (r.bot_id) {
|
||||
|
|
@ -1154,7 +1155,6 @@
|
|||
ws.readyState,
|
||||
);
|
||||
updateConnectionStatus("connected");
|
||||
reconnectAttempts = 0;
|
||||
hasReceivedInitialMessage = false;
|
||||
};
|
||||
ws.onclose = function (e) {
|
||||
|
|
|
|||
|
|
@ -1322,7 +1322,6 @@
|
|||
"WebSocket connected for attendant:",
|
||||
currentAttendantId,
|
||||
);
|
||||
reconnectAttempts = 0;
|
||||
showToast(
|
||||
"Connected to notification service",
|
||||
"success",
|
||||
|
|
@ -1367,6 +1366,7 @@
|
|||
switch (msgType) {
|
||||
case "connected":
|
||||
console.log("WebSocket connected:", data.message);
|
||||
reconnectAttempts = 0;
|
||||
break;
|
||||
case "new_conversation":
|
||||
showToast("New conversation in queue", "info");
|
||||
|
|
|
|||
|
|
@ -886,7 +886,6 @@
|
|||
ws.onopen = function () {
|
||||
clearTimeout(connectionTimeout);
|
||||
console.log("WebSocket connected to:", url);
|
||||
reconnectAttempts = 0;
|
||||
disconnectNotified = false;
|
||||
updateConnectionStatus("connected");
|
||||
};
|
||||
|
|
@ -897,7 +896,10 @@
|
|||
console.log("Chat WebSocket received:", data);
|
||||
|
||||
// Ignore connection confirmation
|
||||
if (data.type === "connected") return;
|
||||
if (data.type === "connected") {
|
||||
reconnectAttempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Process system events (theme changes, etc)
|
||||
if (data.event) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
<!-- Local JS requirements per AGENTS.md / UI.md -->
|
||||
<script src="/suite/js/vendor/htmx.min.js"></script>
|
||||
<script src="/suite/js/window-manager.js"></script>
|
||||
<script src="/suite/js/theme-manager.js"></script>
|
||||
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
|
@ -214,10 +215,13 @@
|
|||
<div id="taskbar-apps">
|
||||
<!-- Taskbar items populated automatically by window-manager.js -->
|
||||
</div>
|
||||
<div class="toolbar-time">
|
||||
<div class="toolbar-time" style="display: flex; align-items: center; gap: 15px;">
|
||||
<div id="themeSelectorContainer"></div>
|
||||
<div style="text-align: right;">
|
||||
<div id="clock-time">00:00</div>
|
||||
<div id="clock-date">01/01/2026</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -231,6 +235,11 @@
|
|||
} else {
|
||||
console.error("WindowManager class not loaded from window-manager.js");
|
||||
}
|
||||
|
||||
// Initialize ThemeManager
|
||||
if (typeof window.ThemeManager !== 'undefined') {
|
||||
window.ThemeManager.init();
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to HTMX afterRequest event
|
||||
|
|
@ -248,6 +257,15 @@
|
|||
window.wm.open(appId, title, htmlContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Theme dropdown is re-injected if wiped
|
||||
if (window.ThemeManager) {
|
||||
const container = document.getElementById('themeSelectorContainer');
|
||||
if (container && !container.hasChildNodes()) {
|
||||
// Quick and dirty way to re-init
|
||||
window.ThemeManager.init();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Simple Clock implementation matching the screenshot bottom right corner
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@
|
|||
|
||||
document.body.addEventListener("htmx:wsOpen", () => {
|
||||
updateConnectionStatus("connected");
|
||||
reconnectAttempts = 0;
|
||||
});
|
||||
|
||||
document.body.addEventListener("htmx:wsClose", () => {
|
||||
|
|
@ -205,6 +204,10 @@
|
|||
function handleWebSocketMessage(message) {
|
||||
const messageType = message.type || message.event;
|
||||
|
||||
if (messageType === "connected") {
|
||||
reconnectAttempts = 0;
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
console.log("handleWebSocketMessage called with:", { messageType, message });
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@ const ThemeManager = (() => {
|
|||
}
|
||||
|
||||
function updateDropdown() {
|
||||
// Dropdown removed
|
||||
const select = document.getElementById("themeDropdown");
|
||||
if (select) select.value = currentThemeId;
|
||||
}
|
||||
|
||||
function createDropdown() {
|
||||
|
|
@ -214,9 +215,12 @@ const ThemeManager = (() => {
|
|||
currentThemeId = saved;
|
||||
loadTheme(saved);
|
||||
|
||||
// Dropdown injection removed
|
||||
// const container = document.getElementById("themeSelectorContainer");
|
||||
// if (container) container.appendChild(createDropdown());
|
||||
// Dropdown injection restored for the window manager
|
||||
const container = document.getElementById("themeSelectorContainer");
|
||||
if (container) {
|
||||
container.innerHTML = '';
|
||||
container.appendChild(createDropdown());
|
||||
}
|
||||
|
||||
console.log("✓ Theme Manager initialized");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -875,7 +875,6 @@
|
|||
|
||||
ws.onopen = function () {
|
||||
console.log("WebSocket connected");
|
||||
reconnectAttempts = 0;
|
||||
disconnectNotified = false;
|
||||
updateConnectionStatus("connected");
|
||||
};
|
||||
|
|
@ -886,7 +885,10 @@
|
|||
console.log("Chat WebSocket received:", data);
|
||||
|
||||
// Ignore connection confirmation
|
||||
if (data.type === "connected") return;
|
||||
if (data.type === "connected") {
|
||||
reconnectAttempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Process system events (theme changes, etc)
|
||||
if (data.event) {
|
||||
|
|
|
|||
|
|
@ -177,10 +177,13 @@
|
|||
<div id="taskbar-apps">
|
||||
<!-- Taskbar items populated automatically by window-manager.js -->
|
||||
</div>
|
||||
<div class="toolbar-time">
|
||||
<div class="toolbar-time" style="display: flex; align-items: center; gap: 15px;">
|
||||
<div id="themeSelectorContainer"></div>
|
||||
<div style="text-align: right;">
|
||||
<div id="clock-time">00:00</div>
|
||||
<div id="clock-date">01/01/2026</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -875,7 +875,6 @@
|
|||
|
||||
ws.onopen = function () {
|
||||
console.log("WebSocket connected");
|
||||
reconnectAttempts = 0;
|
||||
disconnectNotified = false;
|
||||
updateConnectionStatus("connected");
|
||||
};
|
||||
|
|
@ -886,7 +885,10 @@
|
|||
console.log("Chat WebSocket received:", data);
|
||||
|
||||
// Ignore connection confirmation
|
||||
if (data.type === "connected") return;
|
||||
if (data.type === "connected") {
|
||||
reconnectAttempts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Process system events (theme changes, etc)
|
||||
if (data.event) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue