hypha-rpc 0.20.85 → 0.20.86

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.
@@ -51,6 +51,31 @@ function _appendBuffer(buffer1, buffer2) {
51
51
  return tmp.buffer;
52
52
  }
53
53
 
54
+ /**
55
+ * Wrap a promise with a timeout.
56
+ * @param {Promise} promise - The promise to wrap.
57
+ * @param {number} timeoutMs - The timeout in milliseconds.
58
+ * @param {string} message - Optional error message for timeout.
59
+ * @returns {Promise} - The wrapped promise that will reject on timeout.
60
+ */
61
+ function withTimeout(promise, timeoutMs, message = "Operation timed out") {
62
+ return new Promise((resolve, reject) => {
63
+ const timeoutId = setTimeout(() => {
64
+ reject(new Error(`TimeoutError: ${message}`));
65
+ }, timeoutMs);
66
+
67
+ promise
68
+ .then((result) => {
69
+ clearTimeout(timeoutId);
70
+ resolve(result);
71
+ })
72
+ .catch((error) => {
73
+ clearTimeout(timeoutId);
74
+ reject(error);
75
+ });
76
+ });
77
+ }
78
+
54
79
  function indexObject(obj, is) {
55
80
  if (!is) throw new Error("undefined index");
56
81
  if (typeof is === "string") return indexObject(obj, is.split("."));
@@ -418,19 +443,35 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
418
443
  let registeredCount = 0;
419
444
  const failedServices = [];
420
445
 
446
+ // Use timeout for service registration to prevent hanging
447
+ const serviceRegistrationTimeout = this._method_timeout || 30000;
448
+
421
449
  for (let service of services) {
422
450
  try {
423
451
  const serviceInfo = this._extract_service_info(service);
424
- await manager.registerService(serviceInfo);
452
+ await withTimeout(
453
+ manager.registerService(serviceInfo),
454
+ serviceRegistrationTimeout,
455
+ `Timeout registering service ${service.id || "unknown"}`,
456
+ );
425
457
  registeredCount++;
426
458
  console.debug(
427
459
  `Successfully registered service: ${service.id || "unknown"}`,
428
460
  );
429
461
  } catch (serviceError) {
430
462
  failedServices.push(service.id || "unknown");
431
- console.error(
432
- `Failed to register service ${service.id || "unknown"}: ${serviceError}`,
433
- );
463
+ if (
464
+ serviceError.message &&
465
+ serviceError.message.includes("TimeoutError")
466
+ ) {
467
+ console.error(
468
+ `Timeout registering service ${service.id || "unknown"}`,
469
+ );
470
+ } else {
471
+ console.error(
472
+ `Failed to register service ${service.id || "unknown"}: ${serviceError}`,
473
+ );
474
+ }
434
475
  }
435
476
  }
436
477
 
@@ -478,10 +519,12 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
478
519
  }
479
520
  };
480
521
 
481
- // Subscribe to the event topic first
482
- this._clientDisconnectedSubscription = await manager.subscribe([
483
- "client_disconnected",
484
- ]);
522
+ // Subscribe to the event topic first with timeout
523
+ this._clientDisconnectedSubscription = await withTimeout(
524
+ manager.subscribe(["client_disconnected"]),
525
+ serviceRegistrationTimeout,
526
+ "Timeout subscribing to client_disconnected events",
527
+ );
485
528
 
486
529
  // Then register the local event handler
487
530
  this.on("client_disconnected", handleClientDisconnected);
@@ -6278,12 +6321,22 @@ class WebsocketRPCConnection {
6278
6321
  }
6279
6322
  } catch (e) {
6280
6323
  if (`${e}`.includes("ConnectionAbortedError:")) {
6281
- console.warn("Failed to reconnect, connection aborted:", e);
6324
+ console.warn("Server refused to reconnect:", e);
6325
+ // Mark as closed and notify the application
6326
+ this._closed = true;
6327
+ if (this._handle_disconnected) {
6328
+ this._handle_disconnected(`Server refused reconnection: ${e}`);
6329
+ }
6282
6330
  return;
6283
6331
  } else if (`${e}`.includes("NotImplementedError:")) {
6284
6332
  console.error(
6285
6333
  `${e}\nIt appears that you are trying to connect to a hypha server that is older than 0.20.0, please upgrade the hypha server or use the websocket client in imjoy-rpc(https://www.npmjs.com/package/imjoy-rpc) instead`,
6286
6334
  );
6335
+ // Mark as closed to prevent further reconnection attempts
6336
+ this._closed = true;
6337
+ if (this._handle_disconnected) {
6338
+ this._handle_disconnected(`Server too old: ${e}`);
6339
+ }
6287
6340
  return;
6288
6341
  }
6289
6342
 
@@ -6337,21 +6390,20 @@ class WebsocketRPCConnection {
6337
6390
  await reconnect();
6338
6391
  } else {
6339
6392
  console.error(
6340
- `Failed to reconnect after ${MAX_RETRY} attempts, giving up. Exiting process.`,
6393
+ `Failed to reconnect after ${MAX_RETRY} attempts, giving up.`,
6341
6394
  );
6395
+ // Mark as closed to prevent further reconnection attempts
6396
+ this._closed = true;
6342
6397
  // Notify about max retry exceeded
6343
6398
  if (this._handle_disconnected) {
6344
6399
  this._handle_disconnected(
6345
6400
  "Max reconnection attempts exceeded",
6346
6401
  );
6347
6402
  }
6348
- // Exit process to prevent stuck event loop
6349
- if (typeof process !== "undefined" && process.exit) {
6350
- console.error(
6351
- "Forcing process exit due to unrecoverable connection failure",
6352
- );
6353
- process.exit(1);
6354
- }
6403
+ // Note: We intentionally do NOT call process.exit() here.
6404
+ // Instead, we mark the connection as closed and let the
6405
+ // application handle the failure through the disconnected
6406
+ // handler or by checking connection state.
6355
6407
  }
6356
6408
  }, finalDelay);
6357
6409
  this._reconnect_timeouts.add(timeoutId);