hypha-rpc 0.20.72 → 0.20.73
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.
- package/dist/hypha-rpc-websocket.js +391 -43
- package/dist/hypha-rpc-websocket.js.map +1 -1
- package/dist/hypha-rpc-websocket.min.js +1 -1
- package/dist/hypha-rpc-websocket.min.js.map +1 -1
- package/dist/hypha-rpc-websocket.min.mjs +1 -1
- package/dist/hypha-rpc-websocket.min.mjs.map +1 -1
- package/dist/hypha-rpc-websocket.mjs +391 -43
- package/dist/hypha-rpc-websocket.mjs.map +1 -1
- package/package.json +1 -1
- package/src/rpc.js +378 -30
- package/src/websocket-client.js +13 -13
|
@@ -336,6 +336,43 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
336
336
|
services: this._services,
|
|
337
337
|
};
|
|
338
338
|
|
|
339
|
+
// Set up global unhandled promise rejection handler for RPC-related errors
|
|
340
|
+
const handleUnhandledRejection = (event) => {
|
|
341
|
+
const reason = event.reason;
|
|
342
|
+
if (reason && typeof reason === "object") {
|
|
343
|
+
// Check if this is a "Method not found" or "Session not found" error that we can ignore
|
|
344
|
+
const reasonStr = reason.toString();
|
|
345
|
+
if (
|
|
346
|
+
reasonStr.includes("Method not found") ||
|
|
347
|
+
reasonStr.includes("Session not found") ||
|
|
348
|
+
reasonStr.includes("Method expired") ||
|
|
349
|
+
reasonStr.includes("Session not found")
|
|
350
|
+
) {
|
|
351
|
+
console.debug(
|
|
352
|
+
"Ignoring expected method/session not found error:",
|
|
353
|
+
reason,
|
|
354
|
+
);
|
|
355
|
+
event.preventDefault(); // Prevent the default unhandled rejection behavior
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
console.warn("Unhandled RPC promise rejection:", reason);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// Only set the handler if we haven't already set one for this RPC instance
|
|
363
|
+
if (typeof window !== "undefined" && !window._hypha_rejection_handler_set) {
|
|
364
|
+
window.addEventListener("unhandledrejection", handleUnhandledRejection);
|
|
365
|
+
window._hypha_rejection_handler_set = true;
|
|
366
|
+
} else if (
|
|
367
|
+
typeof process !== "undefined" &&
|
|
368
|
+
!process._hypha_rejection_handler_set
|
|
369
|
+
) {
|
|
370
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
371
|
+
handleUnhandledRejection({ reason, promise, preventDefault: () => {} });
|
|
372
|
+
});
|
|
373
|
+
process._hypha_rejection_handler_set = true;
|
|
374
|
+
}
|
|
375
|
+
|
|
339
376
|
if (connection) {
|
|
340
377
|
this.add_service({
|
|
341
378
|
id: "built-in",
|
|
@@ -1044,35 +1081,291 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1044
1081
|
return [encoded, wrapped_callback];
|
|
1045
1082
|
}
|
|
1046
1083
|
|
|
1047
|
-
// Clean session management - all logic in one place
|
|
1048
1084
|
_cleanup_session_if_needed(session_id, callback_name) {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1085
|
+
/**
|
|
1086
|
+
* Clean session management - all logic in one place.
|
|
1087
|
+
*/
|
|
1088
|
+
if (!session_id) {
|
|
1089
|
+
console.debug("Cannot cleanup session: session_id is empty");
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
try {
|
|
1094
|
+
const store = this._get_session_store(session_id, false);
|
|
1095
|
+
if (!store) {
|
|
1096
|
+
console.debug(`Session ${session_id} not found for cleanup`);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
let should_cleanup = false;
|
|
1101
|
+
|
|
1102
|
+
// Promise sessions: let the promise manager decide cleanup
|
|
1103
|
+
if (store._promise_manager) {
|
|
1104
|
+
try {
|
|
1105
|
+
const promise_manager = store._promise_manager;
|
|
1106
|
+
if (
|
|
1107
|
+
promise_manager.should_cleanup_on_callback &&
|
|
1108
|
+
promise_manager.should_cleanup_on_callback(callback_name)
|
|
1109
|
+
) {
|
|
1110
|
+
if (promise_manager.settle) {
|
|
1111
|
+
promise_manager.settle();
|
|
1112
|
+
}
|
|
1113
|
+
should_cleanup = true;
|
|
1114
|
+
console.debug(
|
|
1115
|
+
`Promise session ${session_id} settled and marked for cleanup`,
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
} catch (e) {
|
|
1119
|
+
console.warn(
|
|
1120
|
+
`Error in promise manager cleanup for session ${session_id}:`,
|
|
1121
|
+
e,
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
} else {
|
|
1125
|
+
// Regular sessions: only cleanup temporary method call sessions
|
|
1126
|
+
// Don't cleanup service registration sessions or persistent sessions
|
|
1127
|
+
// Only cleanup sessions that are clearly temporary promises for method calls
|
|
1128
|
+
if (
|
|
1129
|
+
(callback_name === "resolve" || callback_name === "reject") &&
|
|
1130
|
+
store._callbacks &&
|
|
1131
|
+
Object.keys(store._callbacks).includes(callback_name)
|
|
1132
|
+
) {
|
|
1133
|
+
should_cleanup = true;
|
|
1134
|
+
console.debug(
|
|
1135
|
+
`Regular session ${session_id} marked for cleanup after ${callback_name}`,
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
if (should_cleanup) {
|
|
1141
|
+
this._cleanup_session_completely(session_id);
|
|
1142
|
+
}
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
console.warn(`Error during session cleanup for ${session_id}:`, error);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
_cleanup_session_completely(session_id) {
|
|
1149
|
+
/**
|
|
1150
|
+
* Complete session cleanup with resource management.
|
|
1151
|
+
*/
|
|
1152
|
+
try {
|
|
1153
|
+
const store = this._get_session_store(session_id, false);
|
|
1154
|
+
if (!store) {
|
|
1155
|
+
console.debug(`Session ${session_id} already cleaned up`);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// Clean up resources before removing session
|
|
1160
|
+
if (store.timer && typeof store.timer.clear === "function") {
|
|
1161
|
+
try {
|
|
1162
|
+
store.timer.clear();
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
console.warn(
|
|
1165
|
+
`Error clearing timer for session ${session_id}:`,
|
|
1166
|
+
error,
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
if (
|
|
1172
|
+
store.heartbeat_task &&
|
|
1173
|
+
typeof store.heartbeat_task.cancel === "function"
|
|
1174
|
+
) {
|
|
1175
|
+
try {
|
|
1176
|
+
store.heartbeat_task.cancel();
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
console.warn(
|
|
1179
|
+
`Error canceling heartbeat for session ${session_id}:`,
|
|
1180
|
+
error,
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Navigate and clean session path
|
|
1186
|
+
const levels = session_id.split(".");
|
|
1187
|
+
let current_store = this._object_store;
|
|
1188
|
+
|
|
1189
|
+
// Navigate to parent of target level
|
|
1190
|
+
for (let i = 0; i < levels.length - 1; i++) {
|
|
1191
|
+
const level = levels[i];
|
|
1192
|
+
if (!current_store[level]) {
|
|
1193
|
+
console.debug(
|
|
1194
|
+
`Session path ${session_id} not found at level ${level}`,
|
|
1195
|
+
);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
current_store = current_store[level];
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// Delete the final level
|
|
1202
|
+
const final_key = levels[levels.length - 1];
|
|
1203
|
+
if (current_store[final_key]) {
|
|
1204
|
+
delete current_store[final_key];
|
|
1205
|
+
console.debug(`Cleaned up session ${session_id}`);
|
|
1206
|
+
|
|
1207
|
+
// Clean up empty parent containers
|
|
1208
|
+
this._cleanup_empty_containers(levels.slice(0, -1));
|
|
1209
|
+
}
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
console.warn(
|
|
1212
|
+
`Error in complete session cleanup for ${session_id}:`,
|
|
1213
|
+
error,
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
_cleanup_empty_containers(path_levels) {
|
|
1219
|
+
/**
|
|
1220
|
+
* Clean up empty parent containers to prevent memory leaks.
|
|
1221
|
+
*/
|
|
1222
|
+
try {
|
|
1223
|
+
// Work backwards from the deepest level
|
|
1224
|
+
for (let depth = path_levels.length - 1; depth >= 0; depth--) {
|
|
1225
|
+
let current_store = this._object_store;
|
|
1226
|
+
|
|
1227
|
+
// Navigate to parent of current depth
|
|
1228
|
+
for (let i = 0; i < depth; i++) {
|
|
1229
|
+
current_store = current_store[path_levels[i]];
|
|
1230
|
+
if (!current_store) return; // Path doesn't exist
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// Check if container at current depth is empty
|
|
1234
|
+
const container_key = path_levels[depth];
|
|
1235
|
+
const container = current_store[container_key];
|
|
1236
|
+
|
|
1237
|
+
if (
|
|
1238
|
+
container &&
|
|
1239
|
+
typeof container === "object" &&
|
|
1240
|
+
Object.keys(container).length === 0
|
|
1241
|
+
) {
|
|
1242
|
+
delete current_store[container_key];
|
|
1243
|
+
console.debug(
|
|
1244
|
+
`Cleaned up empty container at depth ${depth}: ${path_levels.slice(0, depth + 1).join(".")}`,
|
|
1245
|
+
);
|
|
1246
|
+
} else {
|
|
1247
|
+
// Container is not empty, stop cleanup
|
|
1248
|
+
break;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
console.warn("Error cleaning up empty containers:", error);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
get_session_stats() {
|
|
1257
|
+
/**
|
|
1258
|
+
* Get detailed session statistics.
|
|
1259
|
+
*/
|
|
1260
|
+
const stats = {
|
|
1261
|
+
total_sessions: 0,
|
|
1262
|
+
promise_sessions: 0,
|
|
1263
|
+
regular_sessions: 0,
|
|
1264
|
+
sessions_with_timers: 0,
|
|
1265
|
+
sessions_with_heartbeat: 0,
|
|
1266
|
+
system_stores: {},
|
|
1267
|
+
session_ids: [],
|
|
1268
|
+
memory_usage: 0,
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
if (!this._object_store) {
|
|
1272
|
+
return stats;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
for (const key in this._object_store) {
|
|
1276
|
+
const value = this._object_store[key];
|
|
1277
|
+
|
|
1278
|
+
if (["services", "message_cache"].includes(key)) {
|
|
1279
|
+
// System stores - don't count these as sessions
|
|
1280
|
+
stats.system_stores[key] = {
|
|
1281
|
+
size:
|
|
1282
|
+
typeof value === "object" && value ? Object.keys(value).length : 0,
|
|
1283
|
+
};
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// Count all non-system non-empty objects as sessions
|
|
1288
|
+
if (value && typeof value === "object") {
|
|
1289
|
+
const sessionKeys = Object.keys(value);
|
|
1290
|
+
|
|
1291
|
+
// Only skip completely empty objects
|
|
1292
|
+
if (sessionKeys.length > 0) {
|
|
1293
|
+
stats.total_sessions++;
|
|
1294
|
+
stats.session_ids.push(key);
|
|
1295
|
+
|
|
1296
|
+
if (value._promise_manager) {
|
|
1297
|
+
stats.promise_sessions++;
|
|
1298
|
+
} else {
|
|
1299
|
+
stats.regular_sessions++;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
if (value._timer || value.timer) stats.sessions_with_timers++;
|
|
1303
|
+
if (value._heartbeat || value.heartbeat)
|
|
1304
|
+
stats.sessions_with_heartbeat++;
|
|
1305
|
+
|
|
1306
|
+
// Estimate memory usage
|
|
1307
|
+
stats.memory_usage += JSON.stringify(value).length;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
return stats;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
_force_cleanup_all_sessions() {
|
|
1316
|
+
/**
|
|
1317
|
+
* Force cleanup all sessions (for testing purposes).
|
|
1318
|
+
*/
|
|
1319
|
+
if (!this._object_store) {
|
|
1320
|
+
console.debug("Force cleaning up 0 sessions");
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
let cleaned_count = 0;
|
|
1325
|
+
const keys_to_delete = [];
|
|
1326
|
+
|
|
1327
|
+
for (const key in this._object_store) {
|
|
1328
|
+
// Don't delete system stores
|
|
1329
|
+
if (!["services", "message_cache"].includes(key)) {
|
|
1330
|
+
const value = this._object_store[key];
|
|
1331
|
+
if (
|
|
1332
|
+
value &&
|
|
1333
|
+
typeof value === "object" &&
|
|
1334
|
+
Object.keys(value).length > 0
|
|
1335
|
+
) {
|
|
1336
|
+
keys_to_delete.push(key);
|
|
1337
|
+
cleaned_count++;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// Delete the sessions
|
|
1343
|
+
for (const key of keys_to_delete) {
|
|
1344
|
+
delete this._object_store[key];
|
|
1052
1345
|
}
|
|
1346
|
+
|
|
1347
|
+
console.debug(`Force cleaning up ${cleaned_count} sessions`);
|
|
1053
1348
|
}
|
|
1054
1349
|
|
|
1055
1350
|
// Clean helper to identify promise method calls by session type
|
|
1056
1351
|
_is_promise_method_call(method_path) {
|
|
1057
1352
|
const session_id = method_path.split(".")[0];
|
|
1058
|
-
|
|
1059
|
-
return
|
|
1353
|
+
const session = this._get_session_store(session_id, false);
|
|
1354
|
+
return session && session._promise_manager;
|
|
1060
1355
|
}
|
|
1061
1356
|
|
|
1062
|
-
// Simplified Promise Manager -
|
|
1357
|
+
// Simplified Promise Manager - enhanced version
|
|
1063
1358
|
_create_promise_manager() {
|
|
1064
|
-
|
|
1359
|
+
/**
|
|
1360
|
+
* Create a promise manager to track promise state and decide cleanup.
|
|
1361
|
+
*/
|
|
1065
1362
|
return {
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
this.settled = true;
|
|
1363
|
+
should_cleanup_on_callback: (callback_name) => {
|
|
1364
|
+
return ["resolve", "reject"].includes(callback_name);
|
|
1069
1365
|
},
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
should_cleanup_on_callback(callback_name) {
|
|
1074
|
-
// Always cleanup on resolve/reject like Python
|
|
1075
|
-
return callback_name === "resolve" || callback_name === "reject";
|
|
1366
|
+
settle: () => {
|
|
1367
|
+
// Promise is settled (resolved or rejected)
|
|
1368
|
+
console.debug("Promise settled");
|
|
1076
1369
|
},
|
|
1077
1370
|
};
|
|
1078
1371
|
}
|
|
@@ -1093,10 +1386,15 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1093
1386
|
);
|
|
1094
1387
|
store = {};
|
|
1095
1388
|
}
|
|
1389
|
+
|
|
1390
|
+
// Clean promise lifecycle management - TYPE-BASED, not string-based
|
|
1391
|
+
store._promise_manager = this._create_promise_manager();
|
|
1392
|
+
console.debug(
|
|
1393
|
+
`Created PROMISE session ${session_id} (type-based detection)`,
|
|
1394
|
+
);
|
|
1395
|
+
|
|
1096
1396
|
let encoded = {};
|
|
1097
1397
|
|
|
1098
|
-
// Simplified promise lifecycle - no complex manager needed
|
|
1099
|
-
// Just store the timer if needed
|
|
1100
1398
|
if (timer && reject && this._method_timeout) {
|
|
1101
1399
|
[encoded.heartbeat, store.heartbeat] = this._encode_callback(
|
|
1102
1400
|
"heartbeat",
|
|
@@ -1108,14 +1406,15 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1108
1406
|
);
|
|
1109
1407
|
store.timer = timer;
|
|
1110
1408
|
encoded.interval = this._method_timeout / 2;
|
|
1409
|
+
} else {
|
|
1410
|
+
timer = null;
|
|
1111
1411
|
}
|
|
1112
1412
|
|
|
1113
|
-
// Always use immediate cleanup like Python
|
|
1114
1413
|
[encoded.resolve, store.resolve] = this._encode_callback(
|
|
1115
1414
|
"resolve",
|
|
1116
1415
|
resolve,
|
|
1117
1416
|
session_id,
|
|
1118
|
-
|
|
1417
|
+
clear_after_called,
|
|
1119
1418
|
timer,
|
|
1120
1419
|
local_workspace,
|
|
1121
1420
|
`resolve (${description})`,
|
|
@@ -1124,7 +1423,7 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1124
1423
|
"reject",
|
|
1125
1424
|
reject,
|
|
1126
1425
|
session_id,
|
|
1127
|
-
|
|
1426
|
+
clear_after_called,
|
|
1128
1427
|
timer,
|
|
1129
1428
|
local_workspace,
|
|
1130
1429
|
`reject (${description})`,
|
|
@@ -1379,8 +1678,13 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1379
1678
|
}
|
|
1380
1679
|
})
|
|
1381
1680
|
.catch(function (err) {
|
|
1382
|
-
|
|
1383
|
-
reject
|
|
1681
|
+
const error_msg = `Failed to send the request when calling method (${target_id}:${method_id}), error: ${err}`;
|
|
1682
|
+
if (reject) {
|
|
1683
|
+
reject(new Error(error_msg));
|
|
1684
|
+
} else {
|
|
1685
|
+
// No reject callback available, log the error to prevent unhandled promise rejections
|
|
1686
|
+
console.warn("Unhandled RPC method call error:", error_msg);
|
|
1687
|
+
}
|
|
1384
1688
|
if (timer) {
|
|
1385
1689
|
timer.clear();
|
|
1386
1690
|
}
|
|
@@ -1396,8 +1700,13 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1396
1700
|
}
|
|
1397
1701
|
})
|
|
1398
1702
|
.catch(function (err) {
|
|
1399
|
-
|
|
1400
|
-
reject
|
|
1703
|
+
const error_msg = `Failed to send the request when calling method (${target_id}:${method_id}), error: ${err}`;
|
|
1704
|
+
if (reject) {
|
|
1705
|
+
reject(new Error(error_msg));
|
|
1706
|
+
} else {
|
|
1707
|
+
// No reject callback available, log the error to prevent unhandled promise rejections
|
|
1708
|
+
console.warn("Unhandled RPC method call error:", error_msg);
|
|
1709
|
+
}
|
|
1401
1710
|
if (timer) {
|
|
1402
1711
|
timer.clear();
|
|
1403
1712
|
}
|
|
@@ -1503,17 +1812,56 @@ class RPC extends _utils_index_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
|
|
|
1503
1812
|
try {
|
|
1504
1813
|
method = indexObject(this._object_store, data["method"]);
|
|
1505
1814
|
} catch (e) {
|
|
1506
|
-
//
|
|
1507
|
-
if (
|
|
1815
|
+
// Clean promise method detection - TYPE-BASED, not string-based
|
|
1816
|
+
if (this._is_promise_method_call(data["method"])) {
|
|
1508
1817
|
console.debug(
|
|
1509
|
-
`
|
|
1818
|
+
`Promise method ${data["method"]} not available (detected by session type), ignoring: ${method_name}`,
|
|
1510
1819
|
);
|
|
1511
1820
|
return;
|
|
1512
1821
|
}
|
|
1513
1822
|
|
|
1514
|
-
|
|
1823
|
+
// Check if this is a session-based method call that might have expired
|
|
1824
|
+
const method_parts = data["method"].split(".");
|
|
1825
|
+
if (method_parts.length > 1) {
|
|
1826
|
+
const session_id = method_parts[0];
|
|
1827
|
+
// Check if the session exists but the specific method doesn't
|
|
1828
|
+
if (session_id in this._object_store) {
|
|
1829
|
+
console.debug(
|
|
1830
|
+
`Session ${session_id} exists but method ${data["method"]} not found, likely expired callback: ${method_name}`,
|
|
1831
|
+
);
|
|
1832
|
+
// For expired callbacks, don't throw an exception, just log and return
|
|
1833
|
+
if (typeof reject === "function") {
|
|
1834
|
+
reject(new Error(`Method expired or not found: ${method_name}`));
|
|
1835
|
+
}
|
|
1836
|
+
return;
|
|
1837
|
+
} else {
|
|
1838
|
+
console.debug(
|
|
1839
|
+
`Session ${session_id} not found for method ${data["method"]}, likely cleaned up: ${method_name}`,
|
|
1840
|
+
);
|
|
1841
|
+
// For cleaned up sessions, just log and return without throwing
|
|
1842
|
+
if (typeof reject === "function") {
|
|
1843
|
+
reject(new Error(`Session not found: ${method_name}`));
|
|
1844
|
+
}
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
console.debug(
|
|
1850
|
+
`Failed to find method ${method_name} at ${this._client_id}`,
|
|
1851
|
+
);
|
|
1852
|
+
const error = new Error(
|
|
1515
1853
|
`Method not found: ${method_name} at ${this._client_id}`,
|
|
1516
1854
|
);
|
|
1855
|
+
if (typeof reject === "function") {
|
|
1856
|
+
reject(error);
|
|
1857
|
+
} else {
|
|
1858
|
+
// Log the error instead of throwing to prevent unhandled exceptions
|
|
1859
|
+
console.warn(
|
|
1860
|
+
"Method not found and no reject callback:",
|
|
1861
|
+
error.message,
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
return;
|
|
1517
1865
|
}
|
|
1518
1866
|
|
|
1519
1867
|
(0,_utils_index_js__WEBPACK_IMPORTED_MODULE_0__.assert)(
|
|
@@ -5524,20 +5872,20 @@ class WebsocketRPCConnection {
|
|
|
5524
5872
|
// Clean up timers when connection closes
|
|
5525
5873
|
this._cleanup();
|
|
5526
5874
|
|
|
5527
|
-
if (
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
)
|
|
5531
|
-
|
|
5532
|
-
|
|
5875
|
+
// Even if it's a graceful closure (codes 1000, 1001), if it wasn't user-initiated,
|
|
5876
|
+
// we should attempt to reconnect (e.g., server restart, k8s upgrade)
|
|
5877
|
+
if (this._enable_reconnect) {
|
|
5878
|
+
if ([1000, 1001].includes(event.code)) {
|
|
5879
|
+
console.warn(
|
|
5880
|
+
`Websocket connection closed gracefully by server (code: ${event.code}): ${event.reason} - attempting reconnect`,
|
|
5881
|
+
);
|
|
5882
|
+
} else {
|
|
5883
|
+
console.warn(
|
|
5884
|
+
"Websocket connection closed unexpectedly (code: %s): %s",
|
|
5885
|
+
event.code,
|
|
5886
|
+
event.reason,
|
|
5887
|
+
);
|
|
5533
5888
|
}
|
|
5534
|
-
this._closed = true;
|
|
5535
|
-
} else if (this._enable_reconnect) {
|
|
5536
|
-
console.warn(
|
|
5537
|
-
"Websocket connection closed unexpectedly (code: %s): %s",
|
|
5538
|
-
event.code,
|
|
5539
|
-
event.reason,
|
|
5540
|
-
);
|
|
5541
5889
|
|
|
5542
5890
|
let retry = 0;
|
|
5543
5891
|
const baseDelay = 1000; // Start with 1 second
|