@ricsam/isolate 0.1.7 → 0.1.8

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/isolate",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "commonjs"
5
5
  }
@@ -287,6 +287,45 @@ function logRuntimeLifecycle(state, event, instance, reason, level = "log") {
287
287
  const reasonSuffix = reason ? `: ${reason}` : "";
288
288
  logger(`[isolate-daemon] ${event} runtime ${formatRuntimeLabel(instance)}${poisonedSuffix}${reasonSuffix}; ${formatRuntimePoolSnapshot(collectRuntimePoolSnapshot(state))}`);
289
289
  }
290
+ function formatDebugValue(value) {
291
+ if (typeof value === "string") {
292
+ return JSON.stringify(value);
293
+ }
294
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
295
+ return String(value);
296
+ }
297
+ try {
298
+ return JSON.stringify(value);
299
+ } catch {
300
+ return JSON.stringify(String(value));
301
+ }
302
+ }
303
+ function formatDebugFields(fields) {
304
+ return Object.entries(fields).filter(([, value]) => value !== undefined).map(([key, value]) => `${key}=${formatDebugValue(value)}`).join(" ");
305
+ }
306
+ function isDisposedOperationError(error) {
307
+ const text = getErrorText(error).toLowerCase();
308
+ return text.includes("disposed");
309
+ }
310
+ function buildRuntimeDebugFields(instance, connection, extras = {}) {
311
+ return {
312
+ isolateId: instance.isolateId,
313
+ namespaceId: instance.namespaceId ?? null,
314
+ pooled: instance.isDisposed,
315
+ ownerMatches: instance.ownerConnection === connection.socket,
316
+ connectionOwnsIsolate: connection.isolates.has(instance.isolateId),
317
+ runtimeAbortAborted: instance.runtimeAbortController?.signal.aborted ?? null,
318
+ disposedForMs: instance.disposedAt !== undefined ? Date.now() - instance.disposedAt : null,
319
+ callbackConnectionPresent: !!instance.callbackContext?.connection,
320
+ reconnectPending: !!instance.callbackContext?.reconnectionPromise,
321
+ callbackRegistrations: instance.callbacks.size,
322
+ ...extras
323
+ };
324
+ }
325
+ function logSuspiciousRuntimeOperation(state, operation, instance, connection, extras = {}, level = "warn") {
326
+ const logger = level === "warn" ? console.warn : console.log;
327
+ logger(`[isolate-daemon] ${operation} runtime ${formatRuntimeLabel(instance)}; ${formatRuntimePoolSnapshot(collectRuntimePoolSnapshot(state))} ${formatDebugFields(buildRuntimeDebugFields(instance, connection, extras))}`);
328
+ }
290
329
  async function hardDeleteRuntime(instance, state, reason) {
291
330
  const wasPooled = instance.isDisposed;
292
331
  try {
@@ -319,6 +358,8 @@ async function hardDeleteRuntime(instance, state, reason) {
319
358
  }
320
359
  var RECONNECTION_TIMEOUT_MS = 30000;
321
360
  function softDeleteRuntime(instance, state, reason) {
361
+ const runtimeAbortWasAborted = instance.runtimeAbortController?.signal.aborted ?? false;
362
+ const hadCallbackConnection = !!instance.callbackContext?.connection;
322
363
  if (instance.runtimeAbortController && !instance.runtimeAbortController.signal.aborted) {
323
364
  instance.runtimeAbortController.abort(new Error(reason ?? "Runtime was soft-disposed"));
324
365
  }
@@ -356,8 +397,19 @@ function softDeleteRuntime(instance, state, reason) {
356
397
  instance.returnedIterators?.clear();
357
398
  instance.runtime.clearModuleCache();
358
399
  logRuntimeLifecycle(state, "soft-disposed", instance, reason);
400
+ console.warn(`[isolate-daemon] soft-dispose state runtime ${formatRuntimeLabel(instance)}; ${formatRuntimePoolSnapshot(collectRuntimePoolSnapshot(state))} ${formatDebugFields({
401
+ runtimeAbortWasAborted,
402
+ runtimeAbortAborted: instance.runtimeAbortController?.signal.aborted ?? null,
403
+ hadCallbackConnection,
404
+ callbackConnectionPresent: !!instance.callbackContext?.connection,
405
+ reconnectPending: !!instance.callbackContext?.reconnectionPromise,
406
+ callbackRegistrations: instance.callbacks.size
407
+ })}`);
359
408
  }
360
409
  function reuseNamespacedRuntime(instance, connection, message, state) {
410
+ const disposedForMs = instance.disposedAt !== undefined ? Date.now() - instance.disposedAt : null;
411
+ const runtimeAbortWasAborted = instance.runtimeAbortController?.signal.aborted ?? false;
412
+ const reconnectWasPending = !!instance.callbackContext?.reconnectionPromise;
361
413
  instance.ownerConnection = connection.socket;
362
414
  instance.isDisposed = false;
363
415
  instance.isPoisoned = false;
@@ -468,6 +520,11 @@ function reuseNamespacedRuntime(instance, connection, message, state) {
468
520
  instance.returnedIterators = new Map;
469
521
  instance.nextLocalCallbackId = 1e6;
470
522
  logRuntimeLifecycle(state, "reused pooled", instance);
523
+ logSuspiciousRuntimeOperation(state, "reuse state", instance, connection, {
524
+ disposedForMs,
525
+ runtimeAbortWasAborted,
526
+ reconnectWasPending
527
+ }, "log");
471
528
  }
472
529
  async function waitForConnection(callbackContext) {
473
530
  if (callbackContext.connection) {
@@ -1138,6 +1195,12 @@ async function handleDispatchRequest(message, connection, state) {
1138
1195
  sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1139
1196
  return;
1140
1197
  }
1198
+ if (instance.isDisposed) {
1199
+ logSuspiciousRuntimeOperation(state, "dispatchRequest received for pooled", instance, connection, {
1200
+ method: message.request.method,
1201
+ url: message.request.url
1202
+ });
1203
+ }
1141
1204
  instance.lastActivity = Date.now();
1142
1205
  const dispatchAbortController = new AbortController;
1143
1206
  connection.dispatchAbortControllers.set(message.requestId, dispatchAbortController);
@@ -1183,6 +1246,13 @@ async function handleDispatchRequest(message, connection, state) {
1183
1246
  }
1184
1247
  } catch (err) {
1185
1248
  const error = err;
1249
+ if (instance.isDisposed || isDisposedOperationError(error)) {
1250
+ logSuspiciousRuntimeOperation(state, "dispatchRequest failed", instance, connection, {
1251
+ method: message.request.method,
1252
+ url: message.request.url,
1253
+ error: error.message
1254
+ });
1255
+ }
1186
1256
  sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1187
1257
  } finally {
1188
1258
  connection.dispatchAbortControllers.delete(message.requestId);
@@ -1301,12 +1371,20 @@ async function handleFetchGetUpgradeRequest(message, connection, state) {
1301
1371
  sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1302
1372
  return;
1303
1373
  }
1374
+ if (instance.isDisposed) {
1375
+ logSuspiciousRuntimeOperation(state, "getUpgradeRequest received for pooled", instance, connection);
1376
+ }
1304
1377
  instance.lastActivity = Date.now();
1305
1378
  try {
1306
1379
  const upgradeRequest = instance.runtime.fetch.getUpgradeRequest();
1307
1380
  sendOk(connection.socket, message.requestId, upgradeRequest);
1308
1381
  } catch (err) {
1309
1382
  const error = err;
1383
+ if (instance.isDisposed || isDisposedOperationError(error)) {
1384
+ logSuspiciousRuntimeOperation(state, "getUpgradeRequest failed", instance, connection, {
1385
+ error: error.message
1386
+ });
1387
+ }
1310
1388
  sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1311
1389
  }
1312
1390
  }
@@ -1316,12 +1394,20 @@ async function handleFetchHasServeHandler(message, connection, state) {
1316
1394
  sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1317
1395
  return;
1318
1396
  }
1397
+ if (instance.isDisposed) {
1398
+ logSuspiciousRuntimeOperation(state, "hasServeHandler received for pooled", instance, connection);
1399
+ }
1319
1400
  instance.lastActivity = Date.now();
1320
1401
  try {
1321
1402
  const hasHandler = instance.runtime.fetch.hasServeHandler();
1322
1403
  sendOk(connection.socket, message.requestId, hasHandler);
1323
1404
  } catch (err) {
1324
1405
  const error = err;
1406
+ if (instance.isDisposed || isDisposedOperationError(error)) {
1407
+ logSuspiciousRuntimeOperation(state, "hasServeHandler failed", instance, connection, {
1408
+ error: error.message
1409
+ });
1410
+ }
1325
1411
  sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1326
1412
  }
1327
1413
  }
@@ -1331,12 +1417,20 @@ async function handleFetchHasActiveConnections(message, connection, state) {
1331
1417
  sendError(connection.socket, message.requestId, ErrorCode.ISOLATE_NOT_FOUND, `Isolate not found: ${message.isolateId}`);
1332
1418
  return;
1333
1419
  }
1420
+ if (instance.isDisposed) {
1421
+ logSuspiciousRuntimeOperation(state, "hasActiveConnections received for pooled", instance, connection);
1422
+ }
1334
1423
  instance.lastActivity = Date.now();
1335
1424
  try {
1336
1425
  const hasConnections = instance.runtime.fetch.hasActiveConnections();
1337
1426
  sendOk(connection.socket, message.requestId, hasConnections);
1338
1427
  } catch (err) {
1339
1428
  const error = err;
1429
+ if (instance.isDisposed || isDisposedOperationError(error)) {
1430
+ logSuspiciousRuntimeOperation(state, "hasActiveConnections failed", instance, connection, {
1431
+ error: error.message
1432
+ });
1433
+ }
1340
1434
  sendError(connection.socket, message.requestId, ErrorCode.SCRIPT_ERROR, error.message, { name: error.name, stack: error.stack });
1341
1435
  }
1342
1436
  }
@@ -1993,4 +2087,4 @@ export {
1993
2087
  handleConnection
1994
2088
  };
1995
2089
 
1996
- //# debugId=665A564AAE317D3264756E2164756E21
2090
+ //# debugId=46DF7C47935922C664756E2164756E21