@zlink-systems/framework 0.11.0 → 0.12.0
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/.tsbuildinfo +1 -1
- package/dist/contracts/Configuration/EndpointNotation.d.ts +5 -4
- package/dist/contracts/Configuration/EndpointNotation.js +5 -4
- package/dist/contracts/Configuration/InternalDefaults.d.ts +0 -1
- package/dist/contracts/Configuration/InternalDefaults.js +1 -2
- package/dist/contracts/Configuration/RegistrationNormalizers.js +1 -2
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +2 -5
- package/dist/contracts/Configuration/RegistrationValidators.js +0 -1
- package/dist/contracts/Errors/ZLinkFrameworkException.d.ts +6 -7
- package/dist/contracts/Errors/ZLinkFrameworkException.js +6 -7
- package/dist/runtime/actors/actor-client.js +1 -1
- package/dist/runtime/actors/actor-mailbox.js +1 -5
- package/dist/runtime/backend/contracts/index.d.ts +2 -0
- package/dist/runtime/backend/mesh-completion-table.d.ts +1 -3
- package/dist/runtime/backend/mesh-completion-table.js +11 -15
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +11 -4
- package/dist/runtime/backend/mesh-dispatch-pump.js +201 -134
- package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +3 -4
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +51 -37
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
- package/dist/runtime/backend/node/node-backend-adapter-support.js +2 -2
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +2 -2
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +16 -0
- package/dist/runtime/backend/node/node-event-loop-poller.js +49 -0
- package/dist/runtime/backend/node/node-raw-binding-port.js +24 -41
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +8 -8
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +100 -107
- package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +3 -2
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +18 -67
- package/dist/runtime/backend/raw-binding-port.d.ts +1 -0
- package/dist/runtime/backend/runtime-values.d.ts +5 -1
- package/dist/runtime/channels/channel-dispatchers.js +2 -2
- package/dist/runtime/channels/channel-envelope.js +324 -121
- package/dist/runtime/channels/channel-multipart.d.ts +8 -1
- package/dist/runtime/channels/channel-outbound-operations.js +0 -2
- package/dist/runtime/channels/channel-receive-loops.d.ts +1 -3
- package/dist/runtime/channels/channel-receive-loops.js +25 -65
- package/dist/runtime/channels/channel-socket-registry.js +3 -1
- package/dist/runtime/channels/channel-transports.d.ts +2 -1
- package/dist/runtime/channels/channel-transports.js +12 -10
- package/dist/runtime/execution/serial-execution-queue.d.ts +5 -18
- package/dist/runtime/execution/serial-execution-queue.js +16 -80
- package/dist/runtime/foundation/event-loop-resources.d.ts +0 -3
- package/dist/runtime/foundation/event-loop-resources.js +2 -11
- package/dist/runtime/foundation/operation-registry.d.ts +2 -8
- package/dist/runtime/foundation/operation-registry.js +3 -21
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +19 -7
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +56 -10
- package/dist/runtime/foundation/service-mailbox.d.ts +1 -7
- package/dist/runtime/foundation/service-mailbox.js +3 -2
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -1
- package/dist/runtime/foundation/service-stateful-registry.d.ts +1 -1
- package/dist/runtime/foundation/service-stateful-registry.js +2 -2
- package/dist/runtime/foundation/service-stateful-runtime.js +14 -14
- package/dist/runtime/framework-errors-internal.d.ts +4 -4
- package/dist/runtime/framework-errors-internal.js +8 -10
- package/dist/runtime/host/actor-placement-coordinator.js +1 -1
- package/dist/runtime/host/index.js +1 -1
- package/dist/runtime/host/service-relocation-host-runtime.js +0 -4
- package/dist/runtime/host/spot-address-transport.js +1 -1
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +0 -12
- package/dist/runtime/spots/spot-node-runtime-manager.js +6 -166
- package/dist/runtime/spots/spot-serial-turn-executor.js +1 -4
- package/dist/runtime/spots/spot-timer.d.ts +3 -0
- package/dist/runtime/spots/spot-timer.js +87 -18
- package/dist/runtime/streams/session-serial-executor.js +1 -3
- package/dist/runtime/streams/stream-session-runtime.d.ts +2 -2
- package/dist/runtime/streams/stream-session-runtime.js +13 -19
- package/dist/runtime/workers/index.d.ts +0 -1
- package/dist/runtime/workers/index.js +1 -9
- package/package.json +3 -3
- package/src/contracts/Configuration/EndpointNotation.ts +5 -4
- package/src/contracts/Configuration/InternalDefaults.ts +0 -1
- package/src/contracts/Configuration/RegistrationNormalizers.ts +2 -4
- package/src/contracts/Configuration/RegistrationTypes.ts +2 -5
- package/src/contracts/Configuration/RegistrationValidators.ts +0 -1
- package/src/contracts/Errors/ZLinkFrameworkException.ts +6 -7
- package/src/runtime/actors/actor-client.ts +1 -1
- package/src/runtime/actors/actor-mailbox.ts +1 -12
- package/src/runtime/backend/contracts/index.ts +2 -0
- package/src/runtime/backend/mesh-completion-table.ts +12 -23
- package/src/runtime/backend/mesh-dispatch-pump.ts +206 -138
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +66 -35
- package/src/runtime/backend/node/node-backend-adapter-support.ts +4 -4
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +2 -2
- package/src/runtime/backend/node/node-event-loop-poller.ts +55 -0
- package/src/runtime/backend/node/node-raw-binding-port.ts +30 -45
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +97 -110
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +23 -69
- package/src/runtime/backend/raw-binding-port.ts +1 -0
- package/src/runtime/backend/runtime-values.ts +7 -1
- package/src/runtime/channels/channel-dispatchers.ts +2 -2
- package/src/runtime/channels/channel-envelope.ts +379 -109
- package/src/runtime/channels/channel-multipart.ts +9 -1
- package/src/runtime/channels/channel-outbound-operations.ts +0 -1
- package/src/runtime/channels/channel-receive-loops.ts +24 -75
- package/src/runtime/channels/channel-socket-registry.ts +4 -1
- package/src/runtime/channels/channel-transports.ts +20 -10
- package/src/runtime/execution/serial-execution-queue.ts +16 -108
- package/src/runtime/foundation/event-loop-resources.ts +2 -11
- package/src/runtime/foundation/operation-registry.ts +2 -22
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +74 -19
- package/src/runtime/foundation/service-mailbox.ts +3 -13
- package/src/runtime/foundation/service-runtime-contracts.ts +2 -1
- package/src/runtime/foundation/service-stateful-registry.ts +2 -2
- package/src/runtime/foundation/service-stateful-runtime.ts +14 -14
- package/src/runtime/framework-errors-internal.ts +8 -10
- package/src/runtime/host/actor-placement-coordinator.ts +1 -1
- package/src/runtime/host/index.ts +2 -1
- package/src/runtime/host/service-relocation-host-runtime.ts +0 -4
- package/src/runtime/host/spot-address-transport.ts +1 -1
- package/src/runtime/host/user-spot-creation-coordinator.ts +1 -1
- package/src/runtime/spots/spot-node-runtime-manager.ts +13 -233
- package/src/runtime/spots/spot-serial-turn-executor.ts +1 -8
- package/src/runtime/spots/spot-timer.ts +109 -18
- package/src/runtime/streams/session-serial-executor.ts +1 -7
- package/src/runtime/streams/stream-session-runtime.ts +13 -17
- package/src/runtime/workers/index.ts +2 -17
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '../application-jobs/application-ingress-record-owner';
|
|
18
18
|
import { OperationRegistry, type PendingOperation } from './operation-registry';
|
|
19
19
|
import { ServiceLivenessRegistry, type ServiceLivenessTick } from './service-liveness-registry';
|
|
20
|
-
import { ServiceMailbox, type
|
|
20
|
+
import { ServiceMailbox, type ServiceMailboxRecord } from './service-mailbox';
|
|
21
21
|
import {
|
|
22
22
|
ServiceTopologyRegistry,
|
|
23
23
|
sameServiceNodeDescriptor,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
type ServiceNodeDescriptor
|
|
29
29
|
} from './service-topology-registry';
|
|
30
30
|
import {
|
|
31
|
-
|
|
31
|
+
decodeApplicationPayloadView,
|
|
32
32
|
decodeChannelRequestHeader,
|
|
33
33
|
decodeChannelSendHeader,
|
|
34
34
|
decodeHeader,
|
|
@@ -72,6 +72,9 @@ export interface RawServiceRequestResult {
|
|
|
72
72
|
readonly payload?: ServiceApplicationPayload;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/** An M6A application frame already owned by the Framework runtime. */
|
|
76
|
+
type ServiceApplicationPayloadInput = ServiceApplicationPayload | Buffer;
|
|
77
|
+
|
|
75
78
|
export interface RawServiceIngressRecord {
|
|
76
79
|
readonly command: number;
|
|
77
80
|
readonly flags: number;
|
|
@@ -91,7 +94,6 @@ export type RawServiceIngressHandler = (
|
|
|
91
94
|
export interface RawServiceMeshRuntimeOptions {
|
|
92
95
|
readonly descriptor: ServiceNodeDescriptor;
|
|
93
96
|
readonly resolveAdvertisedEndpoint?: (boundEndpoint: string) => string;
|
|
94
|
-
readonly mailbox?: Partial<ServiceMailboxLimits>;
|
|
95
97
|
readonly probeIntervalMs?: number;
|
|
96
98
|
readonly peerTimeoutMs?: number;
|
|
97
99
|
readonly bindingPort: ZLinkRawBindingPort;
|
|
@@ -195,7 +197,7 @@ export class RawServiceMeshRuntime {
|
|
|
195
197
|
constructor(options: RawServiceMeshRuntimeOptions) {
|
|
196
198
|
this.descriptor = options.descriptor;
|
|
197
199
|
this.topology = new ServiceTopologyRegistry(options.descriptor);
|
|
198
|
-
this.mailbox = new ServiceMailbox(
|
|
200
|
+
this.mailbox = new ServiceMailbox(options.onMailboxReady);
|
|
199
201
|
this.liveness = new ServiceLivenessRegistry(options.probeIntervalMs, options.peerTimeoutMs);
|
|
200
202
|
this.bindingPort = options.bindingPort;
|
|
201
203
|
if (options.applicationJobQueue === undefined) {
|
|
@@ -474,23 +476,24 @@ export class RawServiceMeshRuntime {
|
|
|
474
476
|
|
|
475
477
|
async sendToNode(
|
|
476
478
|
targetNodeRoutingId: string,
|
|
477
|
-
payload:
|
|
479
|
+
payload: ServiceApplicationPayloadInput
|
|
478
480
|
): Promise<boolean> {
|
|
479
481
|
return this.send(
|
|
480
482
|
targetNodeRoutingId,
|
|
481
|
-
[encodeNodeSendHeader(),
|
|
483
|
+
[encodeNodeSendHeader(), this.applicationFrame(payload)]
|
|
482
484
|
);
|
|
483
485
|
}
|
|
484
486
|
|
|
485
487
|
async sendToChannel(
|
|
486
488
|
channelName: string,
|
|
487
|
-
payload:
|
|
489
|
+
payload: ServiceApplicationPayloadInput
|
|
488
490
|
): Promise<boolean> {
|
|
489
491
|
const selected = this.topology.selectChannel(
|
|
490
492
|
channelName,
|
|
491
493
|
peer => this.isLocalOrReadyPeer(peer.descriptor.nodeRoutingId)
|
|
492
494
|
);
|
|
493
495
|
if (selected === undefined) return false;
|
|
496
|
+
const applicationFrame = this.applicationFrame(payload);
|
|
494
497
|
if (selected.descriptor.nodeRoutingId === this.descriptor.nodeRoutingId) {
|
|
495
498
|
const applicationJobOwner = await this.reserveLocalIngress();
|
|
496
499
|
try {
|
|
@@ -498,7 +501,7 @@ export class RawServiceMeshRuntime {
|
|
|
498
501
|
const accepted = this.mailbox.tryEnqueue({
|
|
499
502
|
owner: `channel:${channelName}`,
|
|
500
503
|
domain: 'application',
|
|
501
|
-
parts: [encodeChannelSendHeader(channelName),
|
|
504
|
+
parts: [encodeChannelSendHeader(channelName), applicationFrame],
|
|
502
505
|
sourceRoutingId: this.descriptor.nodeRoutingId,
|
|
503
506
|
applicationJob
|
|
504
507
|
});
|
|
@@ -510,13 +513,13 @@ export class RawServiceMeshRuntime {
|
|
|
510
513
|
}
|
|
511
514
|
return this.send(selected.descriptor.nodeRoutingId, [
|
|
512
515
|
encodeChannelSendHeader(channelName),
|
|
513
|
-
|
|
516
|
+
applicationFrame
|
|
514
517
|
]);
|
|
515
518
|
}
|
|
516
519
|
|
|
517
520
|
requestToNode(
|
|
518
521
|
targetNodeRoutingId: string,
|
|
519
|
-
payload:
|
|
522
|
+
payload: ServiceApplicationPayloadInput,
|
|
520
523
|
timeoutMs: number
|
|
521
524
|
): PendingOperation<RawServiceRequestResult> {
|
|
522
525
|
return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs);
|
|
@@ -524,7 +527,7 @@ export class RawServiceMeshRuntime {
|
|
|
524
527
|
|
|
525
528
|
requestToChannel(
|
|
526
529
|
channelName: string,
|
|
527
|
-
payload:
|
|
530
|
+
payload: ServiceApplicationPayloadInput,
|
|
528
531
|
timeoutMs: number
|
|
529
532
|
): PendingOperation<RawServiceRequestResult> | undefined {
|
|
530
533
|
const selected = this.topology.selectChannel(
|
|
@@ -595,7 +598,7 @@ export class RawServiceMeshRuntime {
|
|
|
595
598
|
|
|
596
599
|
reply(
|
|
597
600
|
request: ServiceMailboxRecord,
|
|
598
|
-
payload:
|
|
601
|
+
payload: ServiceApplicationPayloadInput,
|
|
599
602
|
terminalResult = 0,
|
|
600
603
|
failureCode = 0
|
|
601
604
|
): void {
|
|
@@ -603,7 +606,7 @@ export class RawServiceMeshRuntime {
|
|
|
603
606
|
request.localReply(
|
|
604
607
|
terminalResult,
|
|
605
608
|
failureCode,
|
|
606
|
-
terminalResult === 0 ? payload : undefined
|
|
609
|
+
terminalResult === 0 ? this.applicationPayload(payload) : undefined
|
|
607
610
|
);
|
|
608
611
|
return;
|
|
609
612
|
}
|
|
@@ -612,7 +615,7 @@ export class RawServiceMeshRuntime {
|
|
|
612
615
|
}
|
|
613
616
|
request.reply([
|
|
614
617
|
encodeReplyHeader(request.correlation, terminalResult, failureCode),
|
|
615
|
-
...(terminalResult === 0 ? [
|
|
618
|
+
...(terminalResult === 0 ? [this.applicationFrame(payload)] : [])
|
|
616
619
|
]);
|
|
617
620
|
}
|
|
618
621
|
|
|
@@ -620,8 +623,44 @@ export class RawServiceMeshRuntime {
|
|
|
620
623
|
nowMs = performance.now(),
|
|
621
624
|
observe?: RawServicePumpObserver
|
|
622
625
|
): Promise<RawServicePumpResult> {
|
|
623
|
-
const router = this.requireStarted();
|
|
624
626
|
this.pullMonitorEvents();
|
|
627
|
+
return this.receiveOne(nowMs, observe);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
setReadableHandler(handler: () => void): void {
|
|
631
|
+
this.requireStarted().setReadableHandler(handler);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
|
|
635
|
+
async pumpBatch(receiveReady = true): Promise<boolean> {
|
|
636
|
+
await this.drainMonitorEvents();
|
|
637
|
+
const startedAtMs = performance.now();
|
|
638
|
+
let messages = 0;
|
|
639
|
+
let bytes = 0;
|
|
640
|
+
const observe: RawServicePumpObserver = (_source, byteCount) => { bytes += byteCount; };
|
|
641
|
+
while (receiveReady && messages < 64 && !this.closed) {
|
|
642
|
+
const result = await this.receiveOne(performance.now(), observe);
|
|
643
|
+
if (result === 'noData') {
|
|
644
|
+
receiveReady = false;
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
messages += 1;
|
|
648
|
+
// Core owns the per-peer fair-queue cursor. The Framework limit bounds
|
|
649
|
+
// the entire round, so changing peers does not renew its byte/count budget.
|
|
650
|
+
if (bytes >= 4 * 1024 * 1024 || performance.now() - startedAtMs >= 2) break;
|
|
651
|
+
}
|
|
652
|
+
if (!this.closed) {
|
|
653
|
+
await this.announceExpectedPeers();
|
|
654
|
+
await this.tickLiveness();
|
|
655
|
+
}
|
|
656
|
+
return receiveReady && messages > 0;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private async receiveOne(
|
|
660
|
+
nowMs: number,
|
|
661
|
+
observe?: RawServicePumpObserver
|
|
662
|
+
): Promise<RawServicePumpResult> {
|
|
663
|
+
const router = this.requireStarted();
|
|
625
664
|
let permit: ApplicationJobPermitPort;
|
|
626
665
|
try {
|
|
627
666
|
permit = await this.applicationJobQueue.acquire(this.applicationJobStop.signal);
|
|
@@ -629,6 +668,10 @@ export class RawServiceMeshRuntime {
|
|
|
629
668
|
if (this.closed || this.applicationJobStop.signal.aborted) return 'noData';
|
|
630
669
|
throw error;
|
|
631
670
|
}
|
|
671
|
+
if (this.closed) {
|
|
672
|
+
permit.releaseAfterInternalProcessing();
|
|
673
|
+
return 'noData';
|
|
674
|
+
}
|
|
632
675
|
let received: ZLinkRawReceivedRecord | undefined;
|
|
633
676
|
try {
|
|
634
677
|
received = router.receive(true);
|
|
@@ -1122,7 +1165,7 @@ export class RawServiceMeshRuntime {
|
|
|
1122
1165
|
|
|
1123
1166
|
private requestToTarget(
|
|
1124
1167
|
targetNodeRoutingId: string,
|
|
1125
|
-
payload:
|
|
1168
|
+
payload: ServiceApplicationPayloadInput,
|
|
1126
1169
|
timeoutMs: number,
|
|
1127
1170
|
channelName?: string
|
|
1128
1171
|
): PendingOperation<RawServiceRequestResult> {
|
|
@@ -1130,8 +1173,8 @@ export class RawServiceMeshRuntime {
|
|
|
1130
1173
|
const header = channelName === undefined
|
|
1131
1174
|
? encodeNodeRequestHeader(correlation)
|
|
1132
1175
|
: encodeChannelRequestHeader(correlation, channelName);
|
|
1133
|
-
const encodedPayload =
|
|
1134
|
-
const pending = this.operations.
|
|
1176
|
+
const encodedPayload = this.applicationFrame(payload);
|
|
1177
|
+
const pending = this.operations.register(timeoutMs);
|
|
1135
1178
|
let selectedTargetNodeRoutingId = targetNodeRoutingId;
|
|
1136
1179
|
if (
|
|
1137
1180
|
selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId
|
|
@@ -1263,7 +1306,7 @@ export class RawServiceMeshRuntime {
|
|
|
1263
1306
|
this.operations.complete(
|
|
1264
1307
|
pending.id,
|
|
1265
1308
|
reply.terminalResult === 0
|
|
1266
|
-
? { ...result, payload:
|
|
1309
|
+
? { ...result, payload: decodeApplicationPayloadView(replyParts[1]!) }
|
|
1267
1310
|
: result
|
|
1268
1311
|
);
|
|
1269
1312
|
} catch (error) {
|
|
@@ -1277,6 +1320,18 @@ export class RawServiceMeshRuntime {
|
|
|
1277
1320
|
return pending;
|
|
1278
1321
|
}
|
|
1279
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* The generic node/channel backend may supply its single owned M6A frame
|
|
1325
|
+
* directly. All other callers keep the typed application-payload boundary.
|
|
1326
|
+
*/
|
|
1327
|
+
private applicationFrame(payload: ServiceApplicationPayloadInput): Buffer {
|
|
1328
|
+
return Buffer.isBuffer(payload) ? payload : encodeApplicationPayload(payload);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
private applicationPayload(payload: ServiceApplicationPayloadInput): ServiceApplicationPayload {
|
|
1332
|
+
return Buffer.isBuffer(payload) ? decodeApplicationPayloadView(payload) : payload;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1280
1335
|
private admitPeer(
|
|
1281
1336
|
descriptor: ServiceNodeDescriptor,
|
|
1282
1337
|
connection: PhysicalConnectionCandidate,
|
|
@@ -55,14 +55,6 @@ interface DomainState {
|
|
|
55
55
|
bytes: number;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export interface ServiceMailboxLimits {
|
|
59
|
-
readonly applicationMessages: number;
|
|
60
|
-
readonly applicationBytes: number;
|
|
61
|
-
readonly infrastructureMessages: number;
|
|
62
|
-
readonly infrastructureBytes: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
58
|
/** Level-triggered queues with one active application claim per owner. */
|
|
67
59
|
export class ServiceMailbox {
|
|
68
60
|
private readonly application: DomainState;
|
|
@@ -78,10 +70,7 @@ export class ServiceMailbox {
|
|
|
78
70
|
private nextRelocationSerial = 1n;
|
|
79
71
|
private closed = false;
|
|
80
72
|
|
|
81
|
-
constructor(
|
|
82
|
-
_legacyLimits?: ServiceMailboxLimits,
|
|
83
|
-
private readonly onReady?: (domain: ServiceMailboxDomain) => void
|
|
84
|
-
) {
|
|
73
|
+
constructor(private readonly onReady?: (domain: ServiceMailboxDomain) => void) {
|
|
85
74
|
// Host ApplicationJobQueue permits own ordinary-record admission. The
|
|
86
75
|
// Framework-owned payload lifetime does not retain Core HWM credit. A
|
|
87
76
|
// second mailbox cap would reject already-admitted work before the shared
|
|
@@ -125,8 +114,8 @@ export class ServiceMailbox {
|
|
|
125
114
|
if (!queue.claimed && !target.indexed.has(record.owner)) {
|
|
126
115
|
target.indexed.add(record.owner);
|
|
127
116
|
target.ready.push(record.owner);
|
|
117
|
+
this.onReady?.(record.domain);
|
|
128
118
|
}
|
|
129
|
-
this.onReady?.(record.domain);
|
|
130
119
|
return true;
|
|
131
120
|
}
|
|
132
121
|
|
|
@@ -186,6 +175,7 @@ export class ServiceMailbox {
|
|
|
186
175
|
} else if (!target.indexed.has(claim.owner)) {
|
|
187
176
|
target.indexed.add(claim.owner);
|
|
188
177
|
target.ready.push(claim.owner);
|
|
178
|
+
this.onReady?.(claim.domain);
|
|
189
179
|
}
|
|
190
180
|
return true;
|
|
191
181
|
}
|
|
@@ -619,8 +619,8 @@ export class ServiceTerminalOperationRegistry<T> {
|
|
|
619
619
|
this.operations = operations;
|
|
620
620
|
}
|
|
621
621
|
|
|
622
|
-
|
|
623
|
-
return this.operations.
|
|
622
|
+
register(timeoutMs: number, timeoutOwner: 'registry' | 'sender' = 'registry'): PendingOperation<T> {
|
|
623
|
+
return this.operations.register(timeoutMs, timeoutOwner);
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
reply(id: bigint, value: T): boolean {
|
|
@@ -1240,7 +1240,7 @@ export class ServiceStatefulRuntime {
|
|
|
1240
1240
|
payload: ServiceApplicationPayload,
|
|
1241
1241
|
timeoutMs: number
|
|
1242
1242
|
): ServiceStatefulPendingOperation {
|
|
1243
|
-
const pending = this.operations.
|
|
1243
|
+
const pending = this.operations.register(timeoutMs);
|
|
1244
1244
|
const target = this.acceptSpotAuthority(requested);
|
|
1245
1245
|
if (target === undefined) {
|
|
1246
1246
|
this.operations.reply(pending.id, {
|
|
@@ -1294,7 +1294,7 @@ export class ServiceStatefulRuntime {
|
|
|
1294
1294
|
sourceActor?: ServiceActorRef,
|
|
1295
1295
|
boundSession?: { readonly sessionRid: string; readonly bindingGeneration: bigint }
|
|
1296
1296
|
): ServiceStatefulPendingOperation {
|
|
1297
|
-
const pending = this.operations.
|
|
1297
|
+
const pending = this.operations.register(timeoutMs);
|
|
1298
1298
|
const route = this.tryActorFence(target);
|
|
1299
1299
|
if (route === undefined) {
|
|
1300
1300
|
this.operations.reply(pending.id, {
|
|
@@ -1393,7 +1393,7 @@ export class ServiceStatefulRuntime {
|
|
|
1393
1393
|
sourceSpotId?: string,
|
|
1394
1394
|
metadataFrame?: Uint8Array
|
|
1395
1395
|
): ServiceStatefulPendingOperation {
|
|
1396
|
-
const pending = this.operations.
|
|
1396
|
+
const pending = this.operations.register(timeoutMs);
|
|
1397
1397
|
this.submitRequest(
|
|
1398
1398
|
pending,
|
|
1399
1399
|
route.targetNodeRid,
|
|
@@ -1442,7 +1442,7 @@ export class ServiceStatefulRuntime {
|
|
|
1442
1442
|
metadataFrame?: Uint8Array
|
|
1443
1443
|
): ServiceStatefulPendingOperation {
|
|
1444
1444
|
const timeoutMs = remainingDeadlineMs(deadlineUnixMs);
|
|
1445
|
-
const pending = this.operations.
|
|
1445
|
+
const pending = this.operations.register(timeoutMs);
|
|
1446
1446
|
this.submitRequest(
|
|
1447
1447
|
pending,
|
|
1448
1448
|
target.targetNodeRid,
|
|
@@ -1471,7 +1471,7 @@ export class ServiceStatefulRuntime {
|
|
|
1471
1471
|
actorId: string,
|
|
1472
1472
|
timeoutMs: number
|
|
1473
1473
|
): ServiceStatefulPendingOperation {
|
|
1474
|
-
const pending = this.operations.
|
|
1474
|
+
const pending = this.operations.register(timeoutMs);
|
|
1475
1475
|
this.submitRequest(
|
|
1476
1476
|
pending,
|
|
1477
1477
|
targetNodeRid,
|
|
@@ -1483,7 +1483,7 @@ export class ServiceStatefulRuntime {
|
|
|
1483
1483
|
}
|
|
1484
1484
|
|
|
1485
1485
|
destroyActor(actor: ServiceActorRef, timeoutMs: number): ServiceStatefulPendingOperation {
|
|
1486
|
-
const pending = this.operations.
|
|
1486
|
+
const pending = this.operations.register(timeoutMs);
|
|
1487
1487
|
const local = actor.nodeRid === this.nodeRid;
|
|
1488
1488
|
if (local) {
|
|
1489
1489
|
queueMicrotask(() => {
|
|
@@ -1510,7 +1510,7 @@ export class ServiceStatefulRuntime {
|
|
|
1510
1510
|
timeoutMs: number
|
|
1511
1511
|
): ServiceStatefulPendingOperation {
|
|
1512
1512
|
const deadlineMs = performance.now() + timeoutMs;
|
|
1513
|
-
const pending = this.operations.
|
|
1513
|
+
const pending = this.operations.register(timeoutMs, targetNodeRid === this.nodeRid ? 'registry' : 'sender');
|
|
1514
1514
|
const target = this.trySpotFence(targetNodeRid, {
|
|
1515
1515
|
...targetSpot,
|
|
1516
1516
|
generation: targetSpotGeneration
|
|
@@ -1537,7 +1537,7 @@ export class ServiceStatefulRuntime {
|
|
|
1537
1537
|
timeoutMs: number
|
|
1538
1538
|
): ServiceStatefulPendingOperation {
|
|
1539
1539
|
const deadlineMs = performance.now() + timeoutMs;
|
|
1540
|
-
const pending = this.operations.
|
|
1540
|
+
const pending = this.operations.register(timeoutMs, targetNodeRid === this.nodeRid ? 'registry' : 'sender');
|
|
1541
1541
|
const target = this.trySpotFence(targetNodeRid, {
|
|
1542
1542
|
...targetSpot,
|
|
1543
1543
|
generation: targetSpotGeneration
|
|
@@ -1561,7 +1561,7 @@ export class ServiceStatefulRuntime {
|
|
|
1561
1561
|
timeoutMs: number
|
|
1562
1562
|
): ServiceStatefulPendingOperation {
|
|
1563
1563
|
const deadlineMs = performance.now() + timeoutMs;
|
|
1564
|
-
const pending = this.operations.
|
|
1564
|
+
const pending = this.operations.register(timeoutMs, targetNodeRid === this.nodeRid ? 'registry' : 'sender');
|
|
1565
1565
|
this.submitActorJoin(
|
|
1566
1566
|
pending,
|
|
1567
1567
|
actor,
|
|
@@ -1582,7 +1582,7 @@ export class ServiceStatefulRuntime {
|
|
|
1582
1582
|
timeoutMs: number
|
|
1583
1583
|
): ServiceStatefulPendingOperation {
|
|
1584
1584
|
const deadlineMs = performance.now() + timeoutMs;
|
|
1585
|
-
const pending = this.operations.
|
|
1585
|
+
const pending = this.operations.register(timeoutMs, targetNodeRid === this.nodeRid ? 'registry' : 'sender');
|
|
1586
1586
|
this.submitActorJoin(
|
|
1587
1587
|
pending,
|
|
1588
1588
|
actor,
|
|
@@ -1600,7 +1600,7 @@ export class ServiceStatefulRuntime {
|
|
|
1600
1600
|
expectedMembershipEpoch: bigint,
|
|
1601
1601
|
timeoutMs: number
|
|
1602
1602
|
): ServiceStatefulPendingOperation {
|
|
1603
|
-
const pending = this.operations.
|
|
1603
|
+
const pending = this.operations.register(timeoutMs);
|
|
1604
1604
|
queueMicrotask(() => {
|
|
1605
1605
|
try {
|
|
1606
1606
|
const transition = this.registry.leaveActor(actor, expectedMembershipEpoch);
|
|
@@ -1635,7 +1635,7 @@ export class ServiceStatefulRuntime {
|
|
|
1635
1635
|
actorAuthority?: StreamSessionActorAuthorityFence
|
|
1636
1636
|
): ServiceStatefulPendingOperation {
|
|
1637
1637
|
const deadlineMs = performance.now() + timeoutMs;
|
|
1638
|
-
const pending = this.operations.
|
|
1638
|
+
const pending = this.operations.register(timeoutMs, 'sender');
|
|
1639
1639
|
const generation = this.nextSessionSequence++;
|
|
1640
1640
|
const localBinding: ServiceSessionBinding = {
|
|
1641
1641
|
actor,
|
|
@@ -1777,7 +1777,7 @@ export class ServiceStatefulRuntime {
|
|
|
1777
1777
|
expectedBindingGeneration: bigint,
|
|
1778
1778
|
timeoutMs: number
|
|
1779
1779
|
): ServiceStatefulPendingOperation {
|
|
1780
|
-
const pending = this.operations.
|
|
1780
|
+
const pending = this.operations.register(timeoutMs);
|
|
1781
1781
|
const delivery = this.sessionDeliveries.get(actorKey(actor));
|
|
1782
1782
|
if (
|
|
1783
1783
|
delivery === undefined
|
|
@@ -2644,7 +2644,7 @@ export class ServiceStatefulRuntime {
|
|
|
2644
2644
|
return;
|
|
2645
2645
|
}
|
|
2646
2646
|
|
|
2647
|
-
const pending = this.operations.
|
|
2647
|
+
const pending = this.operations.register(remainingMs);
|
|
2648
2648
|
this.submitRequest(
|
|
2649
2649
|
pending,
|
|
2650
2650
|
route.targetNodeRid,
|
|
@@ -69,7 +69,7 @@ const INTERNAL_TO_PUBLIC: Readonly<Record<ZLinkFrameworkInternalErrorKind, ZLink
|
|
|
69
69
|
[ZLinkFrameworkInternalErrorKind.RequestRejected]: ZLinkFrameworkErrorKind.Rejected,
|
|
70
70
|
[ZLinkFrameworkInternalErrorKind.RequestProtocolError]: ZLinkFrameworkErrorKind.ProtocolError,
|
|
71
71
|
[ZLinkFrameworkInternalErrorKind.RequestFailed]: ZLinkFrameworkErrorKind.InternalFailure,
|
|
72
|
-
[ZLinkFrameworkInternalErrorKind.WorkerQueueFull]: ZLinkFrameworkErrorKind.
|
|
72
|
+
[ZLinkFrameworkInternalErrorKind.WorkerQueueFull]: ZLinkFrameworkErrorKind.Unavailable,
|
|
73
73
|
[ZLinkFrameworkInternalErrorKind.WorkerTimedOut]: ZLinkFrameworkErrorKind.DeadlineExceeded,
|
|
74
74
|
[ZLinkFrameworkInternalErrorKind.WorkerFailed]: ZLinkFrameworkErrorKind.InternalFailure,
|
|
75
75
|
[ZLinkFrameworkInternalErrorKind.ActorLocationStale]: ZLinkFrameworkErrorKind.Unavailable,
|
|
@@ -82,7 +82,7 @@ const INTERNAL_TO_PUBLIC: Readonly<Record<ZLinkFrameworkInternalErrorKind, ZLink
|
|
|
82
82
|
[ZLinkFrameworkInternalErrorKind.ActorGenerationStale]: ZLinkFrameworkErrorKind.InvalidOperation,
|
|
83
83
|
[ZLinkFrameworkInternalErrorKind.ActorMoving]: ZLinkFrameworkErrorKind.Unavailable,
|
|
84
84
|
[ZLinkFrameworkInternalErrorKind.DeadlineExceeded]: ZLinkFrameworkErrorKind.DeadlineExceeded,
|
|
85
|
-
[ZLinkFrameworkInternalErrorKind.PlacementCapacityExhausted]: ZLinkFrameworkErrorKind.
|
|
85
|
+
[ZLinkFrameworkInternalErrorKind.PlacementCapacityExhausted]: ZLinkFrameworkErrorKind.Unavailable,
|
|
86
86
|
[ZLinkFrameworkInternalErrorKind.RoutingIdConflict]: ZLinkFrameworkErrorKind.AlreadyExists,
|
|
87
87
|
[ZLinkFrameworkInternalErrorKind.SpotGenerationStale]: ZLinkFrameworkErrorKind.InvalidOperation,
|
|
88
88
|
[ZLinkFrameworkInternalErrorKind.SpotMoving]: ZLinkFrameworkErrorKind.Unavailable,
|
|
@@ -145,8 +145,7 @@ const INTERNAL_KIND_BY_WIRE_FAILURE_CODE: ReadonlyMap<number, ZLinkFrameworkInte
|
|
|
145
145
|
...Object.entries(ZLINK_FRAMEWORK_INTERNAL_ERROR_KIND_VALUES)
|
|
146
146
|
.map(([kind, code]) => [code + 1, kind as ZLinkFrameworkInternalErrorKind] as const),
|
|
147
147
|
// Spec 32-framework-error-model:99-103 — a workerQueueFull(18) received in a
|
|
148
|
-
// remote reply is the target's queue state
|
|
149
|
-
// CapacityExceeded that the wire-value-minus-one derivation would give.
|
|
148
|
+
// remote reply is the target's queue state and maps to Unavailable.
|
|
150
149
|
[18, ZLinkFrameworkInternalErrorKind.RouteNotConnected]
|
|
151
150
|
]);
|
|
152
151
|
|
|
@@ -188,8 +187,8 @@ export function internalFrameworkErrorKind(
|
|
|
188
187
|
* terminal is classified identically across languages instead of collapsing to
|
|
189
188
|
* Unavailable. Spec 32-framework-error-model:81-92 (request-terminal
|
|
190
189
|
* classification); a deadline yields DeadlineExceeded, a lost route Unavailable.
|
|
191
|
-
* Backpressure
|
|
192
|
-
* one-way
|
|
190
|
+
* Backpressure waits in Core until the operation deadline, so request and
|
|
191
|
+
* one-way terminals both surface DeadlineExceeded when that wait expires.
|
|
193
192
|
*/
|
|
194
193
|
export function requestResultToPublicErrorKind(result: number): ZLinkFrameworkErrorKind {
|
|
195
194
|
switch (result) {
|
|
@@ -204,8 +203,7 @@ export function requestResultToPublicErrorKind(result: number): ZLinkFrameworkEr
|
|
|
204
203
|
case RequestResult.Rejected:
|
|
205
204
|
return ZLinkFrameworkErrorKind.Rejected;
|
|
206
205
|
case RequestResult.Backpressured:
|
|
207
|
-
|
|
208
|
-
return ZLinkFrameworkErrorKind.CapacityExceeded;
|
|
206
|
+
return ZLinkFrameworkErrorKind.DeadlineExceeded;
|
|
209
207
|
case RequestResult.Conflict:
|
|
210
208
|
case RequestResult.Busy:
|
|
211
209
|
case RequestResult.NotConnected:
|
|
@@ -229,8 +227,8 @@ export function requestResultToPublicErrorKind(result: number): ZLinkFrameworkEr
|
|
|
229
227
|
* coarse terminal; when absent (0) or unrecognised, the coarse terminal
|
|
230
228
|
* classifies. Remote another-node queue/operation-table saturation
|
|
231
229
|
* (Conflict/Busy) is Unavailable — a resource this runtime does not own — while
|
|
232
|
-
*
|
|
233
|
-
*
|
|
230
|
+
* placement admission terminal Backpressured(113) is Unavailable because no
|
|
231
|
+
* node can host the Spot. Shared by the lifecycle
|
|
234
232
|
* completion paths (Actor join, User Spot create/close) so they classify
|
|
235
233
|
* identically to the request path instead of collapsing to a single kind.
|
|
236
234
|
*/
|
|
@@ -170,7 +170,7 @@ export class ZLinkActorPlacementCoordinator {
|
|
|
170
170
|
// ownership-aware translator instead of collapsing every non-OK
|
|
171
171
|
// remote create to InternalFailure (spec 32-framework-error-model:
|
|
172
172
|
// 83-118, 99-108). Backpressured(113) still surfaces as target
|
|
173
|
-
// placement capacity ->
|
|
173
|
+
// placement capacity -> Unavailable through the shared path.
|
|
174
174
|
throw wireReplyFailureException(
|
|
175
175
|
remote.terminalResult,
|
|
176
176
|
remote.failureCode,
|
|
@@ -380,7 +380,8 @@ export class ZLinkFrameworkRuntimeHost implements
|
|
|
380
380
|
this.meshRouters.classifyManualNodeTarget(meshName, targetNodeRid),
|
|
381
381
|
(meshName, sourceNodeRid, parts) =>
|
|
382
382
|
this.submitLocalMeshRoute(meshName, sourceNodeRid, parts),
|
|
383
|
-
this.metrics
|
|
383
|
+
this.metrics,
|
|
384
|
+
() => this.flowCreationEnabled()
|
|
384
385
|
);
|
|
385
386
|
this.spotAddressTransport = new ZLinkHostSpotAddressTransport({
|
|
386
387
|
resolver: () => this.createLocationSpotRouteResolver(),
|
|
@@ -5035,10 +5035,6 @@ export function relocationFailedFailureCode(
|
|
|
5035
5035
|
return ServiceWireFrameworkErrorCode.requestRejected;
|
|
5036
5036
|
case ZLinkFrameworkErrorKind.ProtocolError:
|
|
5037
5037
|
return ServiceWireFrameworkErrorCode.requestProtocolError;
|
|
5038
|
-
// No dedicated "capacity exceeded" wire code exists; a full queue is
|
|
5039
|
-
// the closest capacity-shaped signal.
|
|
5040
|
-
case ZLinkFrameworkErrorKind.CapacityExceeded:
|
|
5041
|
-
return ServiceWireFrameworkErrorCode.workerQueueFull;
|
|
5042
5038
|
// No dedicated "deadline exceeded" wire code exists; a worker timeout
|
|
5043
5039
|
// is the closest timeout-shaped signal.
|
|
5044
5040
|
case ZLinkFrameworkErrorKind.DeadlineExceeded:
|
|
@@ -763,7 +763,7 @@ function missingInstanceRequestFailure(
|
|
|
763
763
|
? ZLinkFrameworkInternalErrorKind.RuntimeShutdown
|
|
764
764
|
: result === RequestResult.Backpressured
|
|
765
765
|
// Spec 32-framework-error-model:104-108 — the bounded admission
|
|
766
|
-
// terminal is target placement capacity:
|
|
766
|
+
// terminal is target placement capacity: Unavailable.
|
|
767
767
|
? ZLinkFrameworkInternalErrorKind.PlacementCapacityExhausted
|
|
768
768
|
: result === RequestResult.NotConnected
|
|
769
769
|
? ZLinkFrameworkInternalErrorKind.RouteNotConnected
|
|
@@ -1110,7 +1110,7 @@ function remoteUserSpotFailure(
|
|
|
1110
1110
|
// Remote operation-table saturation Busy(108)+None is Unavailable,
|
|
1111
1111
|
// InvalidState(111)+None is InvalidOperation, every fine code follows the
|
|
1112
1112
|
// shared table, and only placement admission Backpressured(113) stays
|
|
1113
|
-
//
|
|
1113
|
+
// Unavailable.
|
|
1114
1114
|
return wireReplyFailureException(
|
|
1115
1115
|
terminalResult,
|
|
1116
1116
|
failureCode,
|