@naylence/runtime 0.3.5-test.954 → 0.3.5-test.955
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/browser/index.cjs +103 -18
- package/dist/browser/index.mjs +103 -18
- package/dist/cjs/naylence/fame/channel/flow-controller.js +38 -1
- package/dist/cjs/naylence/fame/connector/broadcast-channel-connector.browser.js +50 -1
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/channel/flow-controller.js +38 -1
- package/dist/esm/naylence/fame/connector/broadcast-channel-connector.browser.js +50 -1
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +103 -18
- package/dist/node/index.mjs +103 -18
- package/dist/node/node.cjs +103 -18
- package/dist/node/node.mjs +103 -18
- package/dist/types/naylence/fame/connector/broadcast-channel-connector.browser.d.ts +3 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/node/node.cjs
CHANGED
|
@@ -725,7 +725,7 @@ class TaskCancelledError extends Error {
|
|
|
725
725
|
* Provides functionality similar to Python's asyncio TaskSpawner with proper
|
|
726
726
|
* error handling, cancellation, and graceful shutdown capabilities.
|
|
727
727
|
*/
|
|
728
|
-
const logger$
|
|
728
|
+
const logger$1h = getLogger('naylence.fame.util.task_spawner');
|
|
729
729
|
function firstDefined(source, keys) {
|
|
730
730
|
for (const key of keys) {
|
|
731
731
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
@@ -886,7 +886,7 @@ class TaskSpawner {
|
|
|
886
886
|
const taskId = `task-${++this._taskCounter}`;
|
|
887
887
|
const taskName = normalizedOptions.name || `unnamed-${taskId}`;
|
|
888
888
|
const timeout = normalizedOptions.timeout ?? this._config.defaultTimeout;
|
|
889
|
-
logger$
|
|
889
|
+
logger$1h.debug('starting_background_task', {
|
|
890
890
|
task_name: taskName,
|
|
891
891
|
task_id: taskId,
|
|
892
892
|
});
|
|
@@ -903,7 +903,7 @@ class TaskSpawner {
|
|
|
903
903
|
task.promise
|
|
904
904
|
.then(() => {
|
|
905
905
|
if (!this._suppressCompletionLogging) {
|
|
906
|
-
logger$
|
|
906
|
+
logger$1h.debug('task_completed_successfully', {
|
|
907
907
|
task_name: taskName,
|
|
908
908
|
task_id: taskId,
|
|
909
909
|
duration_ms: Date.now() - task.startTime,
|
|
@@ -957,7 +957,7 @@ class TaskSpawner {
|
|
|
957
957
|
error.name === 'AbortError' ||
|
|
958
958
|
error.message === 'Task cancelled' ||
|
|
959
959
|
error.message === 'Aborted') {
|
|
960
|
-
logger$
|
|
960
|
+
logger$1h.debug('task_cancelled', {
|
|
961
961
|
task_name: taskName,
|
|
962
962
|
note: 'Task cancelled as requested',
|
|
963
963
|
});
|
|
@@ -965,7 +965,7 @@ class TaskSpawner {
|
|
|
965
965
|
}
|
|
966
966
|
// Handle timeout
|
|
967
967
|
if (error instanceof TaskTimeoutError) {
|
|
968
|
-
logger$
|
|
968
|
+
logger$1h.warning('task_timed_out', {
|
|
969
969
|
task_name: taskName,
|
|
970
970
|
error: error.message,
|
|
971
971
|
});
|
|
@@ -977,7 +977,7 @@ class TaskSpawner {
|
|
|
977
977
|
// Handle known WebSocket shutdown race condition (similar to Python version)
|
|
978
978
|
if (error.message.includes("await wasn't used with future") ||
|
|
979
979
|
error.message.includes('WebSocket closed during receive')) {
|
|
980
|
-
logger$
|
|
980
|
+
logger$1h.debug('task_shutdown_race_condition_handled', {
|
|
981
981
|
task_name: taskName,
|
|
982
982
|
note: 'Normal WebSocket close timing during shutdown - not an error',
|
|
983
983
|
});
|
|
@@ -987,7 +987,7 @@ class TaskSpawner {
|
|
|
987
987
|
if (error.name === 'FameTransportClose' ||
|
|
988
988
|
error.message.includes('normal closure') ||
|
|
989
989
|
error.message.includes('Connection closed')) {
|
|
990
|
-
logger$
|
|
990
|
+
logger$1h.debug('task_shutdown_completed_normally', {
|
|
991
991
|
task_name: taskName,
|
|
992
992
|
note: 'Task closed normally during shutdown',
|
|
993
993
|
});
|
|
@@ -1000,14 +1000,14 @@ class TaskSpawner {
|
|
|
1000
1000
|
// Log retriable errors as warnings (they'll be retried by upstream logic)
|
|
1001
1001
|
// Log non-retriable errors as errors (fatal failures)
|
|
1002
1002
|
if (isRetriableError) {
|
|
1003
|
-
logger$
|
|
1003
|
+
logger$1h.warning('background_task_failed', {
|
|
1004
1004
|
task_name: taskName,
|
|
1005
1005
|
error: error.message,
|
|
1006
1006
|
retriable: true,
|
|
1007
1007
|
});
|
|
1008
1008
|
}
|
|
1009
1009
|
else {
|
|
1010
|
-
logger$
|
|
1010
|
+
logger$1h.error('background_task_failed', {
|
|
1011
1011
|
task_name: taskName,
|
|
1012
1012
|
error: error.message,
|
|
1013
1013
|
stack: error.stack,
|
|
@@ -1026,11 +1026,11 @@ class TaskSpawner {
|
|
|
1026
1026
|
async shutdownTasks(options = {}) {
|
|
1027
1027
|
const { gracePeriod, cancelHanging, joinTimeout } = normalizeShutdownOptions(options);
|
|
1028
1028
|
if (this._tasks.size === 0) {
|
|
1029
|
-
logger$
|
|
1029
|
+
logger$1h.debug('shutdown_tasks_no_tasks_to_shutdown');
|
|
1030
1030
|
return;
|
|
1031
1031
|
}
|
|
1032
1032
|
this._suppressCompletionLogging = true;
|
|
1033
|
-
logger$
|
|
1033
|
+
logger$1h.debug('shutting_down_tasks', {
|
|
1034
1034
|
task_count: this._tasks.size,
|
|
1035
1035
|
task_names: Array.from(this._tasks.values()).map((t) => t.name),
|
|
1036
1036
|
grace_period_ms: gracePeriod,
|
|
@@ -1045,7 +1045,7 @@ class TaskSpawner {
|
|
|
1045
1045
|
if (cancelHanging) {
|
|
1046
1046
|
const stillRunning = tasks.filter((task) => task.getState() === TaskState.RUNNING && !completed.has(task));
|
|
1047
1047
|
if (stillRunning.length > 0) {
|
|
1048
|
-
logger$
|
|
1048
|
+
logger$1h.debug('tasks_did_not_complete_within_grace_period', {
|
|
1049
1049
|
hanging_count: stillRunning.length,
|
|
1050
1050
|
});
|
|
1051
1051
|
// Wait for them to finish with individual timeouts
|
|
@@ -1055,7 +1055,7 @@ class TaskSpawner {
|
|
|
1055
1055
|
}
|
|
1056
1056
|
catch (error) {
|
|
1057
1057
|
if (error instanceof TaskTimeoutError) {
|
|
1058
|
-
logger$
|
|
1058
|
+
logger$1h.warning('task_did_not_shutdown', {
|
|
1059
1059
|
task_name: task.name || task.id,
|
|
1060
1060
|
join_timeout_ms: joinTimeout,
|
|
1061
1061
|
});
|
|
@@ -1066,7 +1066,7 @@ class TaskSpawner {
|
|
|
1066
1066
|
}
|
|
1067
1067
|
else if (!(error instanceof TaskCancelledError)) {
|
|
1068
1068
|
/* istanbul ignore next - unreachable defensive branch */
|
|
1069
|
-
logger$
|
|
1069
|
+
logger$1h.error('task_raised_during_cancellation', {
|
|
1070
1070
|
task_name: task.name || task.id,
|
|
1071
1071
|
error: error instanceof Error ? error.message : String(error),
|
|
1072
1072
|
});
|
|
@@ -1185,6 +1185,7 @@ class TaskSpawner {
|
|
|
1185
1185
|
* condition/promise and ensure at most one notifier coroutine exists for a
|
|
1186
1186
|
* flow at any time.
|
|
1187
1187
|
*/
|
|
1188
|
+
const logger$1g = getLogger('naylence.fame.flow.flow_controller');
|
|
1188
1189
|
/**
|
|
1189
1190
|
* Simple condition variable implementation for TypeScript/Node.js
|
|
1190
1191
|
* Similar to Python's asyncio.Condition
|
|
@@ -1310,8 +1311,17 @@ class FlowController {
|
|
|
1310
1311
|
// clamp into [0, initialWindow]
|
|
1311
1312
|
const newBalance = Math.max(0, Math.min(this.initialWindow, prev + delta));
|
|
1312
1313
|
this.credits.set(flowId, newBalance);
|
|
1314
|
+
const crossedZero = prev <= 0 && newBalance > 0;
|
|
1315
|
+
logger$1g.debug('flow_controller_add_credits', {
|
|
1316
|
+
flow_id: flowId,
|
|
1317
|
+
delta,
|
|
1318
|
+
prev_balance: prev,
|
|
1319
|
+
new_balance: newBalance,
|
|
1320
|
+
initial_window: this.initialWindow,
|
|
1321
|
+
crossed_zero: crossedZero,
|
|
1322
|
+
});
|
|
1313
1323
|
// wake waiters only if we crossed the zero boundary
|
|
1314
|
-
if (
|
|
1324
|
+
if (crossedZero) {
|
|
1315
1325
|
this.wakeWaiters(flowId);
|
|
1316
1326
|
}
|
|
1317
1327
|
return newBalance;
|
|
@@ -1322,11 +1332,27 @@ class FlowController {
|
|
|
1322
1332
|
async acquire(flowId) {
|
|
1323
1333
|
this.ensureFlow(flowId);
|
|
1324
1334
|
const condition = this.conditions.get(flowId);
|
|
1335
|
+
logger$1g.debug('flow_controller_acquire_attempt', {
|
|
1336
|
+
flow_id: flowId,
|
|
1337
|
+
current_balance: this.credits.get(flowId),
|
|
1338
|
+
});
|
|
1325
1339
|
while (this.credits.get(flowId) <= 0) {
|
|
1340
|
+
logger$1g.debug('flow_controller_waiting_for_credit', {
|
|
1341
|
+
flow_id: flowId,
|
|
1342
|
+
});
|
|
1326
1343
|
await condition.wait();
|
|
1344
|
+
logger$1g.debug('flow_controller_woke_with_credit', {
|
|
1345
|
+
flow_id: flowId,
|
|
1346
|
+
balance_after_wake: this.credits.get(flowId),
|
|
1347
|
+
});
|
|
1327
1348
|
}
|
|
1328
1349
|
const current = this.credits.get(flowId);
|
|
1329
1350
|
this.credits.set(flowId, current - 1);
|
|
1351
|
+
logger$1g.debug('flow_controller_credit_consumed', {
|
|
1352
|
+
flow_id: flowId,
|
|
1353
|
+
prev_balance: current,
|
|
1354
|
+
remaining_balance: current - 1,
|
|
1355
|
+
});
|
|
1330
1356
|
}
|
|
1331
1357
|
/**
|
|
1332
1358
|
* Consume *credits* immediately (non-blocking).
|
|
@@ -1346,6 +1372,12 @@ class FlowController {
|
|
|
1346
1372
|
const current = this.credits.get(flowId);
|
|
1347
1373
|
const remaining = Math.max(current - credits, 0);
|
|
1348
1374
|
this.credits.set(flowId, remaining);
|
|
1375
|
+
logger$1g.debug('flow_controller_consume', {
|
|
1376
|
+
flow_id: flowId,
|
|
1377
|
+
requested: credits,
|
|
1378
|
+
prev_balance: current,
|
|
1379
|
+
remaining_balance: remaining,
|
|
1380
|
+
});
|
|
1349
1381
|
return remaining;
|
|
1350
1382
|
}
|
|
1351
1383
|
/**
|
|
@@ -1366,6 +1398,10 @@ class FlowController {
|
|
|
1366
1398
|
this.windowIds.delete(flowId);
|
|
1367
1399
|
this.credits.set(flowId, this.initialWindow);
|
|
1368
1400
|
this.wakeWaiters(flowId);
|
|
1401
|
+
logger$1g.debug('flow_controller_flow_reset', {
|
|
1402
|
+
flow_id: flowId,
|
|
1403
|
+
reset_balance: this.initialWindow,
|
|
1404
|
+
});
|
|
1369
1405
|
}
|
|
1370
1406
|
/**
|
|
1371
1407
|
* Return `[windowId, flags]` for the next outbound envelope.
|
|
@@ -5478,12 +5514,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
|
|
|
5478
5514
|
}
|
|
5479
5515
|
|
|
5480
5516
|
// This file is auto-generated during build - do not edit manually
|
|
5481
|
-
// Generated from package.json version: 0.3.5-test.
|
|
5517
|
+
// Generated from package.json version: 0.3.5-test.955
|
|
5482
5518
|
/**
|
|
5483
5519
|
* The package version, injected at build time.
|
|
5484
5520
|
* @internal
|
|
5485
5521
|
*/
|
|
5486
|
-
const VERSION = '0.3.5-test.
|
|
5522
|
+
const VERSION = '0.3.5-test.955';
|
|
5487
5523
|
|
|
5488
5524
|
/**
|
|
5489
5525
|
* Fame errors module - Fame protocol specific error classes
|
|
@@ -11534,6 +11570,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11534
11570
|
? Math.floor(config.inboxCapacity)
|
|
11535
11571
|
: DEFAULT_INBOX_CAPACITY$7;
|
|
11536
11572
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
11573
|
+
this.inboxCapacity = preferredCapacity;
|
|
11537
11574
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
11538
11575
|
this.channel = new BroadcastChannel(this.channelName);
|
|
11539
11576
|
logger$10.debug('broadcast_channel_connector_created', {
|
|
@@ -11593,15 +11630,27 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11593
11630
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
11594
11631
|
const accepted = this.inbox.tryEnqueue(payload);
|
|
11595
11632
|
if (accepted) {
|
|
11633
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
11634
|
+
source: 'listener',
|
|
11635
|
+
enqueue_strategy: 'try',
|
|
11636
|
+
payload_length: payload.byteLength,
|
|
11637
|
+
});
|
|
11596
11638
|
return;
|
|
11597
11639
|
}
|
|
11598
11640
|
}
|
|
11599
11641
|
this.inbox.enqueue(payload);
|
|
11642
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
11643
|
+
source: 'listener',
|
|
11644
|
+
enqueue_strategy: 'enqueue',
|
|
11645
|
+
payload_length: payload.byteLength,
|
|
11646
|
+
});
|
|
11600
11647
|
}
|
|
11601
11648
|
catch (error) {
|
|
11602
11649
|
if (error instanceof QueueFullError) {
|
|
11603
11650
|
logger$10.warning('broadcast_channel_receive_queue_full', {
|
|
11604
11651
|
channel: this.channelName,
|
|
11652
|
+
inbox_capacity: this.inboxCapacity,
|
|
11653
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11605
11654
|
});
|
|
11606
11655
|
}
|
|
11607
11656
|
else {
|
|
@@ -11685,15 +11734,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11685
11734
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
11686
11735
|
const accepted = this.inbox.tryEnqueue(item);
|
|
11687
11736
|
if (accepted) {
|
|
11737
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
11738
|
+
enqueue_strategy: 'try',
|
|
11739
|
+
item_type: this._describeInboxItem(item),
|
|
11740
|
+
});
|
|
11688
11741
|
return;
|
|
11689
11742
|
}
|
|
11690
11743
|
}
|
|
11691
11744
|
this.inbox.enqueue(item);
|
|
11745
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
11746
|
+
enqueue_strategy: 'enqueue',
|
|
11747
|
+
item_type: this._describeInboxItem(item),
|
|
11748
|
+
});
|
|
11692
11749
|
}
|
|
11693
11750
|
catch (error) {
|
|
11694
11751
|
if (error instanceof QueueFullError) {
|
|
11695
11752
|
logger$10.warning('broadcast_channel_push_queue_full', {
|
|
11696
11753
|
channel: this.channelName,
|
|
11754
|
+
inbox_capacity: this.inboxCapacity,
|
|
11755
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11697
11756
|
});
|
|
11698
11757
|
throw error;
|
|
11699
11758
|
}
|
|
@@ -11716,7 +11775,11 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11716
11775
|
});
|
|
11717
11776
|
}
|
|
11718
11777
|
async _transportReceive() {
|
|
11719
|
-
|
|
11778
|
+
const item = await this.inbox.dequeue();
|
|
11779
|
+
this.logInboxSnapshot('broadcast_channel_inbox_dequeued', {
|
|
11780
|
+
item_type: this._describeInboxItem(item),
|
|
11781
|
+
});
|
|
11782
|
+
return item;
|
|
11720
11783
|
}
|
|
11721
11784
|
async _transportClose(code, reason) {
|
|
11722
11785
|
logger$10.debug('broadcast_channel_transport_closing', {
|
|
@@ -11770,6 +11833,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11770
11833
|
}
|
|
11771
11834
|
return rawOrEnvelope;
|
|
11772
11835
|
}
|
|
11836
|
+
_describeInboxItem(item) {
|
|
11837
|
+
if (item instanceof Uint8Array) {
|
|
11838
|
+
return 'bytes';
|
|
11839
|
+
}
|
|
11840
|
+
if (item.envelope) {
|
|
11841
|
+
return 'channel_message';
|
|
11842
|
+
}
|
|
11843
|
+
if (item.frame) {
|
|
11844
|
+
return 'envelope';
|
|
11845
|
+
}
|
|
11846
|
+
return 'unknown';
|
|
11847
|
+
}
|
|
11848
|
+
logInboxSnapshot(event, extra = {}) {
|
|
11849
|
+
logger$10.debug(event, {
|
|
11850
|
+
channel: this.channelName,
|
|
11851
|
+
connector_id: this.connectorId,
|
|
11852
|
+
connector_state: this.state,
|
|
11853
|
+
inbox_capacity: this.inboxCapacity,
|
|
11854
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11855
|
+
...extra,
|
|
11856
|
+
});
|
|
11857
|
+
}
|
|
11773
11858
|
_shouldSkipDuplicateAck(senderId, payload) {
|
|
11774
11859
|
const dedupKey = this._extractAckDedupKey(payload);
|
|
11775
11860
|
if (!dedupKey) {
|
package/dist/node/node.mjs
CHANGED
|
@@ -724,7 +724,7 @@ class TaskCancelledError extends Error {
|
|
|
724
724
|
* Provides functionality similar to Python's asyncio TaskSpawner with proper
|
|
725
725
|
* error handling, cancellation, and graceful shutdown capabilities.
|
|
726
726
|
*/
|
|
727
|
-
const logger$
|
|
727
|
+
const logger$1h = getLogger('naylence.fame.util.task_spawner');
|
|
728
728
|
function firstDefined(source, keys) {
|
|
729
729
|
for (const key of keys) {
|
|
730
730
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
@@ -885,7 +885,7 @@ class TaskSpawner {
|
|
|
885
885
|
const taskId = `task-${++this._taskCounter}`;
|
|
886
886
|
const taskName = normalizedOptions.name || `unnamed-${taskId}`;
|
|
887
887
|
const timeout = normalizedOptions.timeout ?? this._config.defaultTimeout;
|
|
888
|
-
logger$
|
|
888
|
+
logger$1h.debug('starting_background_task', {
|
|
889
889
|
task_name: taskName,
|
|
890
890
|
task_id: taskId,
|
|
891
891
|
});
|
|
@@ -902,7 +902,7 @@ class TaskSpawner {
|
|
|
902
902
|
task.promise
|
|
903
903
|
.then(() => {
|
|
904
904
|
if (!this._suppressCompletionLogging) {
|
|
905
|
-
logger$
|
|
905
|
+
logger$1h.debug('task_completed_successfully', {
|
|
906
906
|
task_name: taskName,
|
|
907
907
|
task_id: taskId,
|
|
908
908
|
duration_ms: Date.now() - task.startTime,
|
|
@@ -956,7 +956,7 @@ class TaskSpawner {
|
|
|
956
956
|
error.name === 'AbortError' ||
|
|
957
957
|
error.message === 'Task cancelled' ||
|
|
958
958
|
error.message === 'Aborted') {
|
|
959
|
-
logger$
|
|
959
|
+
logger$1h.debug('task_cancelled', {
|
|
960
960
|
task_name: taskName,
|
|
961
961
|
note: 'Task cancelled as requested',
|
|
962
962
|
});
|
|
@@ -964,7 +964,7 @@ class TaskSpawner {
|
|
|
964
964
|
}
|
|
965
965
|
// Handle timeout
|
|
966
966
|
if (error instanceof TaskTimeoutError) {
|
|
967
|
-
logger$
|
|
967
|
+
logger$1h.warning('task_timed_out', {
|
|
968
968
|
task_name: taskName,
|
|
969
969
|
error: error.message,
|
|
970
970
|
});
|
|
@@ -976,7 +976,7 @@ class TaskSpawner {
|
|
|
976
976
|
// Handle known WebSocket shutdown race condition (similar to Python version)
|
|
977
977
|
if (error.message.includes("await wasn't used with future") ||
|
|
978
978
|
error.message.includes('WebSocket closed during receive')) {
|
|
979
|
-
logger$
|
|
979
|
+
logger$1h.debug('task_shutdown_race_condition_handled', {
|
|
980
980
|
task_name: taskName,
|
|
981
981
|
note: 'Normal WebSocket close timing during shutdown - not an error',
|
|
982
982
|
});
|
|
@@ -986,7 +986,7 @@ class TaskSpawner {
|
|
|
986
986
|
if (error.name === 'FameTransportClose' ||
|
|
987
987
|
error.message.includes('normal closure') ||
|
|
988
988
|
error.message.includes('Connection closed')) {
|
|
989
|
-
logger$
|
|
989
|
+
logger$1h.debug('task_shutdown_completed_normally', {
|
|
990
990
|
task_name: taskName,
|
|
991
991
|
note: 'Task closed normally during shutdown',
|
|
992
992
|
});
|
|
@@ -999,14 +999,14 @@ class TaskSpawner {
|
|
|
999
999
|
// Log retriable errors as warnings (they'll be retried by upstream logic)
|
|
1000
1000
|
// Log non-retriable errors as errors (fatal failures)
|
|
1001
1001
|
if (isRetriableError) {
|
|
1002
|
-
logger$
|
|
1002
|
+
logger$1h.warning('background_task_failed', {
|
|
1003
1003
|
task_name: taskName,
|
|
1004
1004
|
error: error.message,
|
|
1005
1005
|
retriable: true,
|
|
1006
1006
|
});
|
|
1007
1007
|
}
|
|
1008
1008
|
else {
|
|
1009
|
-
logger$
|
|
1009
|
+
logger$1h.error('background_task_failed', {
|
|
1010
1010
|
task_name: taskName,
|
|
1011
1011
|
error: error.message,
|
|
1012
1012
|
stack: error.stack,
|
|
@@ -1025,11 +1025,11 @@ class TaskSpawner {
|
|
|
1025
1025
|
async shutdownTasks(options = {}) {
|
|
1026
1026
|
const { gracePeriod, cancelHanging, joinTimeout } = normalizeShutdownOptions(options);
|
|
1027
1027
|
if (this._tasks.size === 0) {
|
|
1028
|
-
logger$
|
|
1028
|
+
logger$1h.debug('shutdown_tasks_no_tasks_to_shutdown');
|
|
1029
1029
|
return;
|
|
1030
1030
|
}
|
|
1031
1031
|
this._suppressCompletionLogging = true;
|
|
1032
|
-
logger$
|
|
1032
|
+
logger$1h.debug('shutting_down_tasks', {
|
|
1033
1033
|
task_count: this._tasks.size,
|
|
1034
1034
|
task_names: Array.from(this._tasks.values()).map((t) => t.name),
|
|
1035
1035
|
grace_period_ms: gracePeriod,
|
|
@@ -1044,7 +1044,7 @@ class TaskSpawner {
|
|
|
1044
1044
|
if (cancelHanging) {
|
|
1045
1045
|
const stillRunning = tasks.filter((task) => task.getState() === TaskState.RUNNING && !completed.has(task));
|
|
1046
1046
|
if (stillRunning.length > 0) {
|
|
1047
|
-
logger$
|
|
1047
|
+
logger$1h.debug('tasks_did_not_complete_within_grace_period', {
|
|
1048
1048
|
hanging_count: stillRunning.length,
|
|
1049
1049
|
});
|
|
1050
1050
|
// Wait for them to finish with individual timeouts
|
|
@@ -1054,7 +1054,7 @@ class TaskSpawner {
|
|
|
1054
1054
|
}
|
|
1055
1055
|
catch (error) {
|
|
1056
1056
|
if (error instanceof TaskTimeoutError) {
|
|
1057
|
-
logger$
|
|
1057
|
+
logger$1h.warning('task_did_not_shutdown', {
|
|
1058
1058
|
task_name: task.name || task.id,
|
|
1059
1059
|
join_timeout_ms: joinTimeout,
|
|
1060
1060
|
});
|
|
@@ -1065,7 +1065,7 @@ class TaskSpawner {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
else if (!(error instanceof TaskCancelledError)) {
|
|
1067
1067
|
/* istanbul ignore next - unreachable defensive branch */
|
|
1068
|
-
logger$
|
|
1068
|
+
logger$1h.error('task_raised_during_cancellation', {
|
|
1069
1069
|
task_name: task.name || task.id,
|
|
1070
1070
|
error: error instanceof Error ? error.message : String(error),
|
|
1071
1071
|
});
|
|
@@ -1184,6 +1184,7 @@ class TaskSpawner {
|
|
|
1184
1184
|
* condition/promise and ensure at most one notifier coroutine exists for a
|
|
1185
1185
|
* flow at any time.
|
|
1186
1186
|
*/
|
|
1187
|
+
const logger$1g = getLogger('naylence.fame.flow.flow_controller');
|
|
1187
1188
|
/**
|
|
1188
1189
|
* Simple condition variable implementation for TypeScript/Node.js
|
|
1189
1190
|
* Similar to Python's asyncio.Condition
|
|
@@ -1309,8 +1310,17 @@ class FlowController {
|
|
|
1309
1310
|
// clamp into [0, initialWindow]
|
|
1310
1311
|
const newBalance = Math.max(0, Math.min(this.initialWindow, prev + delta));
|
|
1311
1312
|
this.credits.set(flowId, newBalance);
|
|
1313
|
+
const crossedZero = prev <= 0 && newBalance > 0;
|
|
1314
|
+
logger$1g.debug('flow_controller_add_credits', {
|
|
1315
|
+
flow_id: flowId,
|
|
1316
|
+
delta,
|
|
1317
|
+
prev_balance: prev,
|
|
1318
|
+
new_balance: newBalance,
|
|
1319
|
+
initial_window: this.initialWindow,
|
|
1320
|
+
crossed_zero: crossedZero,
|
|
1321
|
+
});
|
|
1312
1322
|
// wake waiters only if we crossed the zero boundary
|
|
1313
|
-
if (
|
|
1323
|
+
if (crossedZero) {
|
|
1314
1324
|
this.wakeWaiters(flowId);
|
|
1315
1325
|
}
|
|
1316
1326
|
return newBalance;
|
|
@@ -1321,11 +1331,27 @@ class FlowController {
|
|
|
1321
1331
|
async acquire(flowId) {
|
|
1322
1332
|
this.ensureFlow(flowId);
|
|
1323
1333
|
const condition = this.conditions.get(flowId);
|
|
1334
|
+
logger$1g.debug('flow_controller_acquire_attempt', {
|
|
1335
|
+
flow_id: flowId,
|
|
1336
|
+
current_balance: this.credits.get(flowId),
|
|
1337
|
+
});
|
|
1324
1338
|
while (this.credits.get(flowId) <= 0) {
|
|
1339
|
+
logger$1g.debug('flow_controller_waiting_for_credit', {
|
|
1340
|
+
flow_id: flowId,
|
|
1341
|
+
});
|
|
1325
1342
|
await condition.wait();
|
|
1343
|
+
logger$1g.debug('flow_controller_woke_with_credit', {
|
|
1344
|
+
flow_id: flowId,
|
|
1345
|
+
balance_after_wake: this.credits.get(flowId),
|
|
1346
|
+
});
|
|
1326
1347
|
}
|
|
1327
1348
|
const current = this.credits.get(flowId);
|
|
1328
1349
|
this.credits.set(flowId, current - 1);
|
|
1350
|
+
logger$1g.debug('flow_controller_credit_consumed', {
|
|
1351
|
+
flow_id: flowId,
|
|
1352
|
+
prev_balance: current,
|
|
1353
|
+
remaining_balance: current - 1,
|
|
1354
|
+
});
|
|
1329
1355
|
}
|
|
1330
1356
|
/**
|
|
1331
1357
|
* Consume *credits* immediately (non-blocking).
|
|
@@ -1345,6 +1371,12 @@ class FlowController {
|
|
|
1345
1371
|
const current = this.credits.get(flowId);
|
|
1346
1372
|
const remaining = Math.max(current - credits, 0);
|
|
1347
1373
|
this.credits.set(flowId, remaining);
|
|
1374
|
+
logger$1g.debug('flow_controller_consume', {
|
|
1375
|
+
flow_id: flowId,
|
|
1376
|
+
requested: credits,
|
|
1377
|
+
prev_balance: current,
|
|
1378
|
+
remaining_balance: remaining,
|
|
1379
|
+
});
|
|
1348
1380
|
return remaining;
|
|
1349
1381
|
}
|
|
1350
1382
|
/**
|
|
@@ -1365,6 +1397,10 @@ class FlowController {
|
|
|
1365
1397
|
this.windowIds.delete(flowId);
|
|
1366
1398
|
this.credits.set(flowId, this.initialWindow);
|
|
1367
1399
|
this.wakeWaiters(flowId);
|
|
1400
|
+
logger$1g.debug('flow_controller_flow_reset', {
|
|
1401
|
+
flow_id: flowId,
|
|
1402
|
+
reset_balance: this.initialWindow,
|
|
1403
|
+
});
|
|
1368
1404
|
}
|
|
1369
1405
|
/**
|
|
1370
1406
|
* Return `[windowId, flags]` for the next outbound envelope.
|
|
@@ -5477,12 +5513,12 @@ for (const [name, config] of Object.entries(SQLITE_PROFILES)) {
|
|
|
5477
5513
|
}
|
|
5478
5514
|
|
|
5479
5515
|
// This file is auto-generated during build - do not edit manually
|
|
5480
|
-
// Generated from package.json version: 0.3.5-test.
|
|
5516
|
+
// Generated from package.json version: 0.3.5-test.955
|
|
5481
5517
|
/**
|
|
5482
5518
|
* The package version, injected at build time.
|
|
5483
5519
|
* @internal
|
|
5484
5520
|
*/
|
|
5485
|
-
const VERSION = '0.3.5-test.
|
|
5521
|
+
const VERSION = '0.3.5-test.955';
|
|
5486
5522
|
|
|
5487
5523
|
/**
|
|
5488
5524
|
* Fame errors module - Fame protocol specific error classes
|
|
@@ -11533,6 +11569,7 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11533
11569
|
? Math.floor(config.inboxCapacity)
|
|
11534
11570
|
: DEFAULT_INBOX_CAPACITY$7;
|
|
11535
11571
|
this.inbox = new BoundedAsyncQueue(preferredCapacity);
|
|
11572
|
+
this.inboxCapacity = preferredCapacity;
|
|
11536
11573
|
this.connectorId = BroadcastChannelConnector.generateConnectorId();
|
|
11537
11574
|
this.channel = new BroadcastChannel(this.channelName);
|
|
11538
11575
|
logger$10.debug('broadcast_channel_connector_created', {
|
|
@@ -11592,15 +11629,27 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11592
11629
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
11593
11630
|
const accepted = this.inbox.tryEnqueue(payload);
|
|
11594
11631
|
if (accepted) {
|
|
11632
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
11633
|
+
source: 'listener',
|
|
11634
|
+
enqueue_strategy: 'try',
|
|
11635
|
+
payload_length: payload.byteLength,
|
|
11636
|
+
});
|
|
11595
11637
|
return;
|
|
11596
11638
|
}
|
|
11597
11639
|
}
|
|
11598
11640
|
this.inbox.enqueue(payload);
|
|
11641
|
+
this.logInboxSnapshot('broadcast_channel_inbox_enqueued', {
|
|
11642
|
+
source: 'listener',
|
|
11643
|
+
enqueue_strategy: 'enqueue',
|
|
11644
|
+
payload_length: payload.byteLength,
|
|
11645
|
+
});
|
|
11599
11646
|
}
|
|
11600
11647
|
catch (error) {
|
|
11601
11648
|
if (error instanceof QueueFullError) {
|
|
11602
11649
|
logger$10.warning('broadcast_channel_receive_queue_full', {
|
|
11603
11650
|
channel: this.channelName,
|
|
11651
|
+
inbox_capacity: this.inboxCapacity,
|
|
11652
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11604
11653
|
});
|
|
11605
11654
|
}
|
|
11606
11655
|
else {
|
|
@@ -11684,15 +11733,25 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11684
11733
|
if (typeof this.inbox.tryEnqueue === 'function') {
|
|
11685
11734
|
const accepted = this.inbox.tryEnqueue(item);
|
|
11686
11735
|
if (accepted) {
|
|
11736
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
11737
|
+
enqueue_strategy: 'try',
|
|
11738
|
+
item_type: this._describeInboxItem(item),
|
|
11739
|
+
});
|
|
11687
11740
|
return;
|
|
11688
11741
|
}
|
|
11689
11742
|
}
|
|
11690
11743
|
this.inbox.enqueue(item);
|
|
11744
|
+
this.logInboxSnapshot('broadcast_channel_push_enqueued', {
|
|
11745
|
+
enqueue_strategy: 'enqueue',
|
|
11746
|
+
item_type: this._describeInboxItem(item),
|
|
11747
|
+
});
|
|
11691
11748
|
}
|
|
11692
11749
|
catch (error) {
|
|
11693
11750
|
if (error instanceof QueueFullError) {
|
|
11694
11751
|
logger$10.warning('broadcast_channel_push_queue_full', {
|
|
11695
11752
|
channel: this.channelName,
|
|
11753
|
+
inbox_capacity: this.inboxCapacity,
|
|
11754
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11696
11755
|
});
|
|
11697
11756
|
throw error;
|
|
11698
11757
|
}
|
|
@@ -11715,7 +11774,11 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11715
11774
|
});
|
|
11716
11775
|
}
|
|
11717
11776
|
async _transportReceive() {
|
|
11718
|
-
|
|
11777
|
+
const item = await this.inbox.dequeue();
|
|
11778
|
+
this.logInboxSnapshot('broadcast_channel_inbox_dequeued', {
|
|
11779
|
+
item_type: this._describeInboxItem(item),
|
|
11780
|
+
});
|
|
11781
|
+
return item;
|
|
11719
11782
|
}
|
|
11720
11783
|
async _transportClose(code, reason) {
|
|
11721
11784
|
logger$10.debug('broadcast_channel_transport_closing', {
|
|
@@ -11769,6 +11832,28 @@ let BroadcastChannelConnector$2 = class BroadcastChannelConnector extends BaseAs
|
|
|
11769
11832
|
}
|
|
11770
11833
|
return rawOrEnvelope;
|
|
11771
11834
|
}
|
|
11835
|
+
_describeInboxItem(item) {
|
|
11836
|
+
if (item instanceof Uint8Array) {
|
|
11837
|
+
return 'bytes';
|
|
11838
|
+
}
|
|
11839
|
+
if (item.envelope) {
|
|
11840
|
+
return 'channel_message';
|
|
11841
|
+
}
|
|
11842
|
+
if (item.frame) {
|
|
11843
|
+
return 'envelope';
|
|
11844
|
+
}
|
|
11845
|
+
return 'unknown';
|
|
11846
|
+
}
|
|
11847
|
+
logInboxSnapshot(event, extra = {}) {
|
|
11848
|
+
logger$10.debug(event, {
|
|
11849
|
+
channel: this.channelName,
|
|
11850
|
+
connector_id: this.connectorId,
|
|
11851
|
+
connector_state: this.state,
|
|
11852
|
+
inbox_capacity: this.inboxCapacity,
|
|
11853
|
+
inbox_remaining_capacity: this.inbox.remainingCapacity,
|
|
11854
|
+
...extra,
|
|
11855
|
+
});
|
|
11856
|
+
}
|
|
11772
11857
|
_shouldSkipDuplicateAck(senderId, payload) {
|
|
11773
11858
|
const dedupKey = this._extractAckDedupKey(payload);
|
|
11774
11859
|
if (!dedupKey) {
|
|
@@ -12,6 +12,7 @@ type BroadcastChannelInboxItem = Uint8Array | FameEnvelope | FameChannelMessage;
|
|
|
12
12
|
export declare class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
13
13
|
private readonly channelName;
|
|
14
14
|
private readonly inbox;
|
|
15
|
+
private readonly inboxCapacity;
|
|
15
16
|
private listenerRegistered;
|
|
16
17
|
private readonly connectorId;
|
|
17
18
|
private readonly onMsg;
|
|
@@ -31,6 +32,8 @@ export declare class BroadcastChannelConnector extends BaseAsyncConnector {
|
|
|
31
32
|
protected _transportReceive(): Promise<BroadcastChannelInboxItem>;
|
|
32
33
|
protected _transportClose(code: number, reason: string): Promise<void>;
|
|
33
34
|
private _normalizeInboxItem;
|
|
35
|
+
private _describeInboxItem;
|
|
36
|
+
private logInboxSnapshot;
|
|
34
37
|
private _shouldSkipDuplicateAck;
|
|
35
38
|
private _shouldSkipDuplicateAckFromInboxItem;
|
|
36
39
|
private _checkDuplicateAck;
|
package/dist/types/version.d.ts
CHANGED