mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(frontend): handle websocket disconnect issue (#11144)
## Changes 🏗️ I found that if I logged out while an agent was running, sometimes Webscokets would keep open connections but fail to connect ( given there is no token anymore ) and cause strange behavior down the line on the login screen. Two root causes behind after inspecting the browser logs 🧐 - WebSocket connections were attempted with an empty token right after logout, yielding `wss://.../ws?token=` and repeated `1006/connection` refused loops. - During logout, sockets in `CONNECTING` state weren’t being closed, so the browser kept trying to finish the handshake and were reattempted shortly after failing Trying to fix this like: - Guard `connectWebSocket()` to no-op if a logout/disconnect intent is set, and to skip connecting when no token is available. - Treat `CONNECTING` sockets as closeable in `disconnectWebSocket()` and clear `wsConnecting` to avoid stale pending Promises - Left existing heartbeat/reconnect logic intact, but it now won’t run when we’re logging out or when we can’t get a token. ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Login and run an agent that takes long to run - [x] Logout - [x] Check the browser console and you don't see any socket errors - [x] The login screen behaves ok ### For configuration changes: Noop
This commit is contained in:
@@ -1126,6 +1126,11 @@ export default class BackendAPI {
|
||||
}
|
||||
|
||||
async connectWebSocket(): Promise<void> {
|
||||
// Do not attempt to connect if a disconnect intent is present (e.g., during logout)
|
||||
if (this._hasDisconnectIntent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isIntentionallyDisconnected = false;
|
||||
return (this.wsConnecting ??= new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
@@ -1139,7 +1144,19 @@ export default class BackendAPI {
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to get token for WebSocket connection:", error);
|
||||
// Continue with empty token, connection might still work
|
||||
// Intentionally fall through; we'll bail out below if no token is available
|
||||
}
|
||||
|
||||
// If we don't have a token, skip attempting a connection.
|
||||
if (!token) {
|
||||
console.info(
|
||||
"[BackendAPI] Skipping WebSocket connect: no auth token available",
|
||||
);
|
||||
// Resolve first, then clear wsConnecting to avoid races for awaiters
|
||||
resolve();
|
||||
this.wsConnecting = null;
|
||||
this.webSocket = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const wsUrlWithToken = `${this.wsUrl}?token=${token}`;
|
||||
@@ -1178,6 +1195,9 @@ export default class BackendAPI {
|
||||
if (!wasIntentional) {
|
||||
this.wsOnDisconnectHandlers.forEach((handler) => handler());
|
||||
setTimeout(() => this.connectWebSocket().then(resolve), 1000);
|
||||
} else {
|
||||
// Ensure pending connect calls settle on intentional close
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1197,9 +1217,14 @@ export default class BackendAPI {
|
||||
disconnectWebSocket() {
|
||||
this.isIntentionallyDisconnected = true;
|
||||
this._stopWSHeartbeat(); // Stop heartbeat when disconnecting
|
||||
if (this.webSocket && this.webSocket.readyState === WebSocket.OPEN) {
|
||||
if (
|
||||
this.webSocket &&
|
||||
(this.webSocket.readyState === WebSocket.OPEN ||
|
||||
this.webSocket.readyState === WebSocket.CONNECTING)
|
||||
) {
|
||||
this.webSocket.close();
|
||||
}
|
||||
this.wsConnecting = null;
|
||||
}
|
||||
|
||||
private _hasDisconnectIntent(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user