hypha-rpc 0.20.55 → 0.20.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4962,6 +4962,24 @@ class WebsocketRPCConnection {
4962
4962
  this.manager_id = null;
4963
4963
  this._refresh_token_task = null;
4964
4964
  this._last_message = null; // Store the last sent message
4965
+ this._reconnect_timeouts = new Set(); // Track reconnection timeouts
4966
+ }
4967
+
4968
+ /**
4969
+ * Centralized cleanup method to clear all timers and prevent resource leaks
4970
+ */
4971
+ _cleanup() {
4972
+ // Clear token refresh interval
4973
+ if (this._refresh_token_task) {
4974
+ clearInterval(this._refresh_token_task);
4975
+ this._refresh_token_task = null;
4976
+ }
4977
+
4978
+ // Clear all reconnection timeouts
4979
+ for (const timeoutId of this._reconnect_timeouts) {
4980
+ clearTimeout(timeoutId);
4981
+ }
4982
+ this._reconnect_timeouts.clear();
4965
4983
  }
4966
4984
 
4967
4985
  on_message(handler) {
@@ -5147,6 +5165,8 @@ class WebsocketRPCConnection {
5147
5165
 
5148
5166
  this._websocket.onerror = (event) => {
5149
5167
  console.error("WebSocket connection error:", event);
5168
+ // Clean up timers on error
5169
+ this._cleanup();
5150
5170
  };
5151
5171
 
5152
5172
  this._websocket.onclose = this._handle_close.bind(this);
@@ -5156,6 +5176,8 @@ class WebsocketRPCConnection {
5156
5176
  }
5157
5177
  return this.connection_info;
5158
5178
  } catch (error) {
5179
+ // Clean up any timers that might have been set up before the error
5180
+ this._cleanup();
5159
5181
  console.error(
5160
5182
  "Failed to connect to",
5161
5183
  this._server_url.split("?")[0],
@@ -5179,6 +5201,9 @@ class WebsocketRPCConnection {
5179
5201
  this._websocket &&
5180
5202
  this._websocket.readyState === WebSocket.CLOSED
5181
5203
  ) {
5204
+ // Clean up timers when connection closes
5205
+ this._cleanup();
5206
+
5182
5207
  if ([1000, 1001].includes(event.code)) {
5183
5208
  console.info(
5184
5209
  `Websocket connection closed (code: ${event.code}): ${event.reason}`,
@@ -5226,24 +5251,34 @@ class WebsocketRPCConnection {
5226
5251
  );
5227
5252
  return;
5228
5253
  }
5229
- await new Promise((resolve) => setTimeout(resolve, 1000));
5230
- if (
5231
- this._websocket &&
5232
- this._websocket.readyState === WebSocket.CONNECTED
5233
- ) {
5234
- return;
5235
- }
5236
- retry += 1;
5237
- if (retry < MAX_RETRY) {
5238
- await reconnect();
5239
- } else {
5240
- console.error("Failed to reconnect after", MAX_RETRY, "attempts");
5241
- }
5254
+ // Track the reconnection timeout to prevent leaks
5255
+ const timeoutId = setTimeout(async () => {
5256
+ this._reconnect_timeouts.delete(timeoutId);
5257
+ if (
5258
+ this._websocket &&
5259
+ this._websocket.readyState === WebSocket.CONNECTED
5260
+ ) {
5261
+ return;
5262
+ }
5263
+ retry += 1;
5264
+ if (retry < MAX_RETRY) {
5265
+ await reconnect();
5266
+ } else {
5267
+ console.error(
5268
+ "Failed to reconnect after",
5269
+ MAX_RETRY,
5270
+ "attempts",
5271
+ );
5272
+ }
5273
+ }, 1000);
5274
+ this._reconnect_timeouts.add(timeoutId);
5242
5275
  }
5243
5276
  };
5244
5277
  reconnect();
5245
5278
  }
5246
5279
  } else {
5280
+ // Clean up timers in all cases
5281
+ this._cleanup();
5247
5282
  if (this._handle_disconnected) {
5248
5283
  this._handle_disconnected(event.reason);
5249
5284
  }
@@ -5278,9 +5313,8 @@ class WebsocketRPCConnection {
5278
5313
  ) {
5279
5314
  this._websocket.close(1000, reason);
5280
5315
  }
5281
- if (this._refresh_token_task) {
5282
- clearInterval(this._refresh_token_task);
5283
- }
5316
+ // Use centralized cleanup to clear all timers
5317
+ this._cleanup();
5284
5318
  console.info(`WebSocket connection disconnected (${reason})`);
5285
5319
  }
5286
5320
  }