@zlink-systems/framework 0.24.0 → 0.26.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/Channels/IZLinkFanoutClient.d.ts +0 -6
- package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +1 -0
- package/dist/runtime/activation-admission.d.ts +29 -0
- package/dist/runtime/activation-admission.js +61 -0
- package/dist/runtime/actors/actor-context.js +6 -6
- package/dist/runtime/actors/actor-handoff.d.ts +9 -3
- package/dist/runtime/actors/actor-handoff.js +28 -17
- package/dist/runtime/actors/actor-local-native-join.js +2 -18
- package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
- package/dist/runtime/actors/actor-remote-joiner.js +6 -8
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
- package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
- package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
- package/dist/runtime/actors/deferred-join-completion.js +20 -0
- package/dist/runtime/actors/index.d.ts +1 -1
- package/dist/runtime/actors/index.js +15 -5
- package/dist/runtime/admission.d.ts +5 -1
- package/dist/runtime/admission.js +4 -0
- package/dist/runtime/backend/contracts/index.d.ts +2 -10
- package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
- package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
- package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
- package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
- package/dist/runtime/channels/channel-clients.d.ts +0 -1
- package/dist/runtime/channels/channel-clients.js +0 -8
- package/dist/runtime/channels/channel-outbound-operations.js +2 -10
- package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
- package/dist/runtime/channels/channel-runtime-manager.js +1 -12
- package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
- package/dist/runtime/channels/channel-socket-registry.js +49 -62
- package/dist/runtime/channels/channel-transports.d.ts +0 -3
- package/dist/runtime/channels/fanout-location-runtime.js +3 -9
- package/dist/runtime/execution/index.d.ts +18 -8
- package/dist/runtime/execution/index.js +55 -29
- package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
- package/dist/runtime/execution/serial-execution-queue.js +49 -15
- package/dist/runtime/foundation/listener-records.d.ts +11 -0
- package/dist/runtime/foundation/listener-records.js +20 -0
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
- package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
- package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
- package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
- package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
- package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
- package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
- package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
- package/dist/runtime/foundation/service-topology-registry.js +6 -30
- package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
- package/dist/runtime/host/actor-transfer-runtime.js +73 -86
- package/dist/runtime/host/index.d.ts +6 -2
- package/dist/runtime/host/index.js +63 -37
- package/dist/runtime/host/remote-bound-session-relay.js +4 -3
- package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
- package/dist/runtime/host/route-mesh-runtime.js +7 -5
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
- package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
- package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
- package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
- package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
- package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
- package/dist/runtime/locations/lifecycle.d.ts +1 -1
- package/dist/runtime/locations/lifecycle.js +2 -2
- package/dist/runtime/locations/resolvers.js +7 -2
- package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
- package/dist/runtime/locations/spot-location-claims.js +3 -27
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
- package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
- package/dist/runtime/spots/index.d.ts +25 -19
- package/dist/runtime/spots/index.js +207 -205
- package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
- package/dist/runtime/spots/spot-activation-registry.js +34 -31
- package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
- package/dist/runtime/spots/spot-activation-state.js +4 -17
- package/dist/runtime/spots/spot-activation.d.ts +8 -6
- package/dist/runtime/spots/spot-activation.js +54 -49
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
- package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
- package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
- package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
- package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
- package/dist/runtime/spots/spot-actor-membership.js +26 -12
- package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
- package/dist/runtime/spots/spot-entry-activation.js +0 -1
- package/dist/runtime/spots/spot-manager-public.js +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
- package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
- package/dist/runtime/spots/spot-outbound.js +1 -29
- package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
- package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
- package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
- package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
- package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
- package/dist/runtime/spots/spot-serial-executor.js +8 -1
- package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
- package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
- package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
- package/dist/runtime/streams/bound-session-service.js +1 -18
- package/dist/runtime/streams/index.d.ts +2 -0
- package/dist/runtime/streams/index.js +19 -19
- package/dist/runtime/streams/session-serial-executor.js +2 -2
- package/package.json +3 -3
- package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
- package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
- package/src/internal.ts +1 -0
- package/src/runtime/activation-admission.ts +78 -0
- package/src/runtime/actors/actor-context.ts +6 -6
- package/src/runtime/actors/actor-handoff.ts +31 -23
- package/src/runtime/actors/actor-local-native-join.ts +3 -42
- package/src/runtime/actors/actor-remote-joiner.ts +6 -25
- package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
- package/src/runtime/actors/actor-source-transfer.ts +5 -18
- package/src/runtime/actors/deferred-join-completion.ts +40 -0
- package/src/runtime/actors/index.ts +22 -9
- package/src/runtime/admission.ts +5 -1
- package/src/runtime/backend/contracts/index.ts +2 -13
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
- package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
- package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
- package/src/runtime/backend/raw-binding-port.ts +13 -0
- package/src/runtime/channels/channel-clients.ts +0 -11
- package/src/runtime/channels/channel-outbound-operations.ts +3 -11
- package/src/runtime/channels/channel-runtime-manager.ts +4 -15
- package/src/runtime/channels/channel-socket-registry.ts +69 -71
- package/src/runtime/channels/channel-transports.ts +0 -3
- package/src/runtime/channels/fanout-location-runtime.ts +4 -16
- package/src/runtime/execution/index.ts +68 -30
- package/src/runtime/execution/serial-execution-queue.ts +52 -20
- package/src/runtime/foundation/listener-records.ts +21 -0
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
- package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
- package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
- package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
- package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
- package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
- package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
- package/src/runtime/foundation/service-topology-registry.ts +8 -48
- package/src/runtime/host/actor-transfer-runtime.ts +94 -166
- package/src/runtime/host/index.ts +119 -54
- package/src/runtime/host/remote-bound-session-relay.ts +4 -3
- package/src/runtime/host/route-mesh-runtime.ts +9 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
- package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
- package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
- package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
- package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
- package/src/runtime/locations/lifecycle.ts +3 -2
- package/src/runtime/locations/resolvers.ts +19 -13
- package/src/runtime/locations/spot-location-claims.ts +5 -34
- package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
- package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
- package/src/runtime/spots/index.ts +341 -295
- package/src/runtime/spots/spot-activation-registry.ts +41 -31
- package/src/runtime/spots/spot-activation-state.ts +4 -16
- package/src/runtime/spots/spot-activation.ts +102 -80
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
- package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
- package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
- package/src/runtime/spots/spot-actor-membership.ts +81 -17
- package/src/runtime/spots/spot-entry-activation.ts +0 -3
- package/src/runtime/spots/spot-manager-public.ts +8 -4
- package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
- package/src/runtime/spots/spot-outbound.ts +4 -47
- package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
- package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
- package/src/runtime/spots/spot-runtime-ports.ts +6 -17
- package/src/runtime/spots/spot-serial-executor.ts +9 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
- package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
- package/src/runtime/streams/bound-session-service.ts +2 -36
- package/src/runtime/streams/index.ts +29 -27
- package/src/runtime/streams/session-serial-executor.ts +2 -2
- package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
- package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
- package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ServiceSessionBindingAdmissionResult } from '../foundation/service-session-binding-ingress-port';
|
|
2
2
|
export interface ZLinkActorSessionBindingActor {
|
|
3
3
|
readonly actorId: string;
|
|
4
4
|
}
|
|
@@ -34,14 +34,6 @@ export interface ZLinkActorSessionRetainedOutbound {
|
|
|
34
34
|
deliver(): Promise<boolean>;
|
|
35
35
|
fail(error: unknown): void;
|
|
36
36
|
}
|
|
37
|
-
export interface ZLinkActorSessionAcceptedProducerProof {
|
|
38
|
-
readonly actorId: string;
|
|
39
|
-
readonly objectGeneration: bigint;
|
|
40
|
-
readonly actorNodeRid: string;
|
|
41
|
-
readonly actorNodeGeneration: bigint;
|
|
42
|
-
readonly sessionIdentity: string;
|
|
43
|
-
readonly bindingGeneration: bigint;
|
|
44
|
-
}
|
|
45
37
|
export interface ZLinkActorSessionRelocationSnapshot extends ZLinkActorSessionRelocationClaim {
|
|
46
38
|
readonly phase: 'sealed' | 'applying' | 'applied' | 'terminal';
|
|
47
39
|
readonly applyFingerprint?: string;
|
|
@@ -139,16 +131,24 @@ export declare class ZLinkActorSessionBindingRegistry<TContext extends ZLinkActo
|
|
|
139
131
|
private relocationSnapshotCore;
|
|
140
132
|
retainRelocationOutbound(actorId: string, operation: ZLinkActorSessionRetainedOutbound, sealId?: string): Promise<ServiceSessionBindingAdmissionResult>;
|
|
141
133
|
private retainRelocationOutboundCorePublic;
|
|
142
|
-
|
|
143
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Session–Actor binding §8.1: the Session owner holds a push only while the
|
|
136
|
+
* binding's relocation seal is open, and keeps it behind earlier held pushes.
|
|
137
|
+
* Whether the push names the current binding was decided once by the Session
|
|
138
|
+
* owner's binding record before this call.
|
|
139
|
+
*/
|
|
144
140
|
private retainRelocationOutboundCore;
|
|
145
141
|
discardRelocationOutbound(actorId: string, sealId: string, error: unknown): Promise<void>;
|
|
146
142
|
private discardRelocationOutboundCore;
|
|
147
|
-
applyRelocation(actorId: string, sealId: string, applyFingerprint: string,
|
|
143
|
+
applyRelocation(actorId: string, sealId: string, applyFingerprint: string, commitOwnerTransition: () => Promise<void>): Promise<void>;
|
|
148
144
|
private prepareRelocationApply;
|
|
145
|
+
/**
|
|
146
|
+
* Command 44 commit or abort releases every push held under this seal in
|
|
147
|
+
* arrival order (Session–Actor binding §8.1). The held pushes were admitted
|
|
148
|
+
* by the current binding; the route change does not judge them again.
|
|
149
|
+
*/
|
|
149
150
|
private completeRelocationApply;
|
|
150
151
|
private failRelocationApply;
|
|
151
|
-
private currentProducerProof;
|
|
152
152
|
observeRelocationTerminal(actorId: string, sealId: string, applyFingerprint: string): Promise<void>;
|
|
153
153
|
private observeRelocationTerminalCore;
|
|
154
154
|
/**
|
|
@@ -192,8 +192,6 @@ export declare class ZLinkActorSessionBindingRegistry<TContext extends ZLinkActo
|
|
|
192
192
|
private reserveOutbound;
|
|
193
193
|
private settleOutbound;
|
|
194
194
|
private failOutbound;
|
|
195
|
-
private outboundAdmissionError;
|
|
196
|
-
private matchesCurrentProducerNode;
|
|
197
195
|
private rememberTerminalRelocation;
|
|
198
196
|
private deleteEmptyRelocationQueue;
|
|
199
197
|
private resolveSealWaiters;
|
|
@@ -5,7 +5,6 @@ const framework_errors_internal_1 = require("../framework-errors-internal");
|
|
|
5
5
|
const abort_1 = require("../abort");
|
|
6
6
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
7
7
|
const state_lane_1 = require("../execution/state-lane");
|
|
8
|
-
const routing_id_1 = require("../routing-id");
|
|
9
8
|
const detachedStateLaneResource = new node_async_hooks_1.AsyncResource('zlink:actor-session-binding-registry');
|
|
10
9
|
var ZLinkActorSessionBindingTermination;
|
|
11
10
|
(function (ZLinkActorSessionBindingTermination) {
|
|
@@ -438,42 +437,15 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
438
437
|
return 'rejected';
|
|
439
438
|
}
|
|
440
439
|
}
|
|
441
|
-
return this.retainRelocationOutboundCore(actorId, operation
|
|
440
|
+
return this.retainRelocationOutboundCore(actorId, operation);
|
|
442
441
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (error !== undefined) {
|
|
451
|
-
failRetainedOutbound(operation, error);
|
|
452
|
-
return 'rejected';
|
|
453
|
-
}
|
|
454
|
-
if (queue === undefined || state === undefined) {
|
|
455
|
-
if (!this.matchesCurrentProducerNode(claim)) {
|
|
456
|
-
failRetainedOutbound(operation, new Error(`Actor '${claim.actorId}' Session outbound admission was fenced by its current binding.`));
|
|
457
|
-
return 'rejected';
|
|
458
|
-
}
|
|
459
|
-
if (queue === undefined)
|
|
460
|
-
return 'passThrough';
|
|
461
|
-
return this.retainRelocationOutboundCore(claim.actorId, operation, 'source', claim);
|
|
462
|
-
}
|
|
463
|
-
if (state.phase === 'sealed' || state.phase === 'applying') {
|
|
464
|
-
const matchesSource = matchesRelocationSourceProof(state, claim);
|
|
465
|
-
const matchesCurrent = this.matchesCurrentProducerNode(claim);
|
|
466
|
-
const authorization = matchesSource || matchesCurrent ? 'source' : 'pendingTarget';
|
|
467
|
-
return this.retainRelocationOutboundCore(claim.actorId, operation, authorization, claim);
|
|
468
|
-
}
|
|
469
|
-
const acceptedProof = state.acceptedProducerProof;
|
|
470
|
-
if (acceptedProof === undefined || !matchesAcceptedProducerProof(acceptedProof, claim)) {
|
|
471
|
-
failRetainedOutbound(operation, new Error(`Actor '${claim.actorId}' Session outbound admission did not match its accepted producer proof.`));
|
|
472
|
-
return 'rejected';
|
|
473
|
-
}
|
|
474
|
-
return this.retainRelocationOutboundCore(claim.actorId, operation, 'source', claim);
|
|
475
|
-
}
|
|
476
|
-
retainRelocationOutboundCore(actorId, operation, authorization, claim) {
|
|
442
|
+
/**
|
|
443
|
+
* Session–Actor binding §8.1: the Session owner holds a push only while the
|
|
444
|
+
* binding's relocation seal is open, and keeps it behind earlier held pushes.
|
|
445
|
+
* Whether the push names the current binding was decided once by the Session
|
|
446
|
+
* owner's binding record before this call.
|
|
447
|
+
*/
|
|
448
|
+
retainRelocationOutboundCore(actorId, operation) {
|
|
477
449
|
const queue = this.relocations.get(actorId);
|
|
478
450
|
const state = queue?.activeSealId === undefined ? undefined : queue.seals.get(queue.activeSealId);
|
|
479
451
|
if (queue === undefined)
|
|
@@ -485,9 +457,7 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
485
457
|
return 'rejected';
|
|
486
458
|
queue.outbound.push({
|
|
487
459
|
operation,
|
|
488
|
-
authorization,
|
|
489
460
|
arrivalOrder: queue.nextArrivalOrder++,
|
|
490
|
-
...(claim === undefined ? {} : { claim }),
|
|
491
461
|
released: true,
|
|
492
462
|
settled: false
|
|
493
463
|
});
|
|
@@ -499,9 +469,7 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
499
469
|
queue.outbound.push({
|
|
500
470
|
sealId: state.sealId,
|
|
501
471
|
operation,
|
|
502
|
-
authorization,
|
|
503
472
|
arrivalOrder: queue.nextArrivalOrder++,
|
|
504
|
-
...(claim === undefined ? {} : { claim }),
|
|
505
473
|
released: false,
|
|
506
474
|
settled: false
|
|
507
475
|
});
|
|
@@ -523,8 +491,8 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
523
491
|
}
|
|
524
492
|
this.deleteEmptyRelocationQueue(queue);
|
|
525
493
|
}
|
|
526
|
-
async applyRelocation(actorId, sealId, applyFingerprint,
|
|
527
|
-
const prepared = await this.lane.run(() => this.prepareRelocationApply(actorId, sealId, applyFingerprint
|
|
494
|
+
async applyRelocation(actorId, sealId, applyFingerprint, commitOwnerTransition) {
|
|
495
|
+
const prepared = await this.lane.run(() => this.prepareRelocationApply(actorId, sealId, applyFingerprint));
|
|
528
496
|
if (prepared.applyPromise !== undefined) {
|
|
529
497
|
await prepared.applyPromise;
|
|
530
498
|
return;
|
|
@@ -544,7 +512,7 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
544
512
|
});
|
|
545
513
|
await prepared.promise;
|
|
546
514
|
}
|
|
547
|
-
prepareRelocationApply(actorId, sealId, applyFingerprint
|
|
515
|
+
prepareRelocationApply(actorId, sealId, applyFingerprint) {
|
|
548
516
|
const queue = this.relocations.get(actorId);
|
|
549
517
|
const state = queue?.seals.get(sealId);
|
|
550
518
|
if (queue === undefined || state === undefined) {
|
|
@@ -556,14 +524,6 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
556
524
|
}
|
|
557
525
|
return { queue, state, applyPromise: state.applyPromise };
|
|
558
526
|
}
|
|
559
|
-
if (action === 'commit' &&
|
|
560
|
-
acceptedProducerProof !== undefined &&
|
|
561
|
-
!validAcceptedTargetProof(state, acceptedProducerProof)) {
|
|
562
|
-
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale, `Actor '${actorId}' command 44 target producer proof did not match its Session seal.`, true);
|
|
563
|
-
}
|
|
564
|
-
if (action === 'abort' && acceptedProducerProof !== undefined) {
|
|
565
|
-
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale, `Actor '${actorId}' abort route supplied a target producer proof.`, true);
|
|
566
|
-
}
|
|
567
527
|
state.phase = 'applying';
|
|
568
528
|
state.applyFingerprint = applyFingerprint;
|
|
569
529
|
let resolve;
|
|
@@ -576,38 +536,22 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
576
536
|
return {
|
|
577
537
|
queue,
|
|
578
538
|
state,
|
|
579
|
-
action,
|
|
580
|
-
acceptedProducerProof,
|
|
581
539
|
promise,
|
|
582
540
|
resolve,
|
|
583
541
|
reject,
|
|
584
|
-
actorId,
|
|
585
542
|
sealId
|
|
586
543
|
};
|
|
587
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Command 44 commit or abort releases every push held under this seal in
|
|
547
|
+
* arrival order (Session–Actor binding §8.1). The held pushes were admitted
|
|
548
|
+
* by the current binding; the route change does not judge them again.
|
|
549
|
+
*/
|
|
588
550
|
completeRelocationApply(prepared) {
|
|
589
|
-
const { queue, state,
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
: relocationSourceProof(state);
|
|
593
|
-
state.acceptedProducerProof = proof;
|
|
594
|
-
for (let index = queue.outbound.length - 1; index >= 0; index--) {
|
|
595
|
-
const entry = queue.outbound[index];
|
|
596
|
-
if (entry.sealId !== sealId)
|
|
597
|
-
continue;
|
|
598
|
-
if (entry.authorization !== 'pendingTarget') {
|
|
599
|
-
entry.released = true;
|
|
600
|
-
continue;
|
|
601
|
-
}
|
|
602
|
-
if (action === 'commit' &&
|
|
603
|
-
proof !== undefined &&
|
|
604
|
-
entry.claim !== undefined &&
|
|
605
|
-
matchesAcceptedProducerProof(proof, entry.claim)) {
|
|
551
|
+
const { queue, state, sealId } = prepared;
|
|
552
|
+
for (const entry of queue.outbound) {
|
|
553
|
+
if (entry.sealId === sealId)
|
|
606
554
|
entry.released = true;
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
queue.outbound.splice(index, 1);
|
|
610
|
-
this.failOutbound(queue, entry, new Error(`Actor '${actorId}' pending Session producer did not match command 44 proof.`));
|
|
611
555
|
}
|
|
612
556
|
this.startOutboundDrain(queue);
|
|
613
557
|
state.phase = 'applied';
|
|
@@ -616,27 +560,6 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
616
560
|
prepared.state.phase = 'sealed';
|
|
617
561
|
prepared.state.applyFingerprint = undefined;
|
|
618
562
|
prepared.state.applyPromise = undefined;
|
|
619
|
-
prepared.state.acceptedProducerProof = undefined;
|
|
620
|
-
}
|
|
621
|
-
currentProducerProof(actorId) {
|
|
622
|
-
const route = this.routes.get(actorId);
|
|
623
|
-
const actorRef = (route?.actor).ref;
|
|
624
|
-
const sessionIdentity = route?.sessionIdentity;
|
|
625
|
-
if (route === undefined ||
|
|
626
|
-
actorRef === undefined ||
|
|
627
|
-
sessionIdentity === undefined ||
|
|
628
|
-
actorRef.ownerNodeGeneration === undefined)
|
|
629
|
-
return undefined;
|
|
630
|
-
return {
|
|
631
|
-
actorId,
|
|
632
|
-
objectGeneration: BigInt(actorRef.objectGeneration ??
|
|
633
|
-
actorRef.generation ??
|
|
634
|
-
-1),
|
|
635
|
-
actorNodeRid: String(actorRef.nodeRid ?? ''),
|
|
636
|
-
actorNodeGeneration: BigInt(actorRef.ownerNodeGeneration),
|
|
637
|
-
sessionIdentity: String(sessionIdentity),
|
|
638
|
-
bindingGeneration: BigInt(actorRef.bindingGeneration ?? -1)
|
|
639
|
-
};
|
|
640
563
|
}
|
|
641
564
|
async observeRelocationTerminal(actorId, sealId, applyFingerprint) {
|
|
642
565
|
await this.lane.run(() => this.observeRelocationTerminalCore(actorId, sealId, applyFingerprint));
|
|
@@ -971,42 +894,6 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
971
894
|
this.settleOutbound(queue, entry);
|
|
972
895
|
failRetainedOutbound(entry.operation, error);
|
|
973
896
|
}
|
|
974
|
-
outboundAdmissionError(claim) {
|
|
975
|
-
if (claim.actorId.length === 0 ||
|
|
976
|
-
claim.objectGeneration <= 0n ||
|
|
977
|
-
claim.actorNodeRid.length === 0 ||
|
|
978
|
-
claim.actorNodeGeneration <= 0n ||
|
|
979
|
-
claim.producerNodeRid.length === 0 ||
|
|
980
|
-
claim.producerNodeGeneration <= 0n ||
|
|
981
|
-
claim.bindingGeneration <= 0n ||
|
|
982
|
-
claim.sessionIdentity.length === 0 ||
|
|
983
|
-
!(0, routing_id_1.routingIdsEqual)(claim.producerNodeRid, claim.actorNodeRid) ||
|
|
984
|
-
claim.producerNodeGeneration !== claim.actorNodeGeneration) {
|
|
985
|
-
return new Error(`Actor '${claim.actorId}' Session outbound admission claim is invalid.`);
|
|
986
|
-
}
|
|
987
|
-
const route = this.routes.get(claim.actorId);
|
|
988
|
-
const ref = route?.actor;
|
|
989
|
-
const actorRef = ref?.ref;
|
|
990
|
-
const routeSessionIdentity = route?.sessionIdentity;
|
|
991
|
-
if (route === undefined ||
|
|
992
|
-
actorRef === undefined ||
|
|
993
|
-
String(actorRef.actorId ?? claim.actorId) !== claim.actorId ||
|
|
994
|
-
BigInt(actorRef.objectGeneration ??
|
|
995
|
-
actorRef.generation ??
|
|
996
|
-
-1) !== claim.objectGeneration ||
|
|
997
|
-
BigInt(actorRef.bindingGeneration ?? -1) !== claim.bindingGeneration ||
|
|
998
|
-
String(routeSessionIdentity ?? '') !== claim.sessionIdentity) {
|
|
999
|
-
return new Error(`Actor '${claim.actorId}' Session outbound admission was fenced by its current binding.`);
|
|
1000
|
-
}
|
|
1001
|
-
return undefined;
|
|
1002
|
-
}
|
|
1003
|
-
matchesCurrentProducerNode(claim) {
|
|
1004
|
-
const route = this.routes.get(claim.actorId);
|
|
1005
|
-
const actorRef = (route?.actor).ref;
|
|
1006
|
-
return (route !== undefined &&
|
|
1007
|
-
actorRef !== undefined &&
|
|
1008
|
-
(0, routing_id_1.routingIdsEqual)(String(actorRef.nodeRid ?? ''), claim.actorNodeRid));
|
|
1009
|
-
}
|
|
1010
897
|
rememberTerminalRelocation(state) {
|
|
1011
898
|
this.terminalRelocations.delete(state);
|
|
1012
899
|
this.terminalRelocations.set(state, true);
|
|
@@ -1061,45 +948,6 @@ function assertRelocationClaim(state, claim) {
|
|
|
1061
948
|
function startOutsideStateLane(work) {
|
|
1062
949
|
return detachedStateLaneResource.runInAsyncScope(work);
|
|
1063
950
|
}
|
|
1064
|
-
function matchesRelocationSourceProof(state, claim) {
|
|
1065
|
-
return (state.actorId === claim.actorId &&
|
|
1066
|
-
state.actorGeneration === claim.objectGeneration &&
|
|
1067
|
-
state.bindingGeneration === claim.bindingGeneration &&
|
|
1068
|
-
state.sessionIdentity === claim.sessionIdentity &&
|
|
1069
|
-
state.actorNodeRid !== undefined &&
|
|
1070
|
-
(0, routing_id_1.routingIdsEqual)(state.actorNodeRid, claim.actorNodeRid) &&
|
|
1071
|
-
state.actorNodeGeneration === claim.actorNodeGeneration);
|
|
1072
|
-
}
|
|
1073
|
-
function matchesAcceptedProducerProof(proof, claim) {
|
|
1074
|
-
return (proof.actorId === claim.actorId &&
|
|
1075
|
-
proof.objectGeneration === claim.objectGeneration &&
|
|
1076
|
-
(0, routing_id_1.routingIdsEqual)(proof.actorNodeRid, claim.actorNodeRid) &&
|
|
1077
|
-
proof.actorNodeGeneration === claim.actorNodeGeneration &&
|
|
1078
|
-
proof.sessionIdentity === claim.sessionIdentity &&
|
|
1079
|
-
proof.bindingGeneration === claim.bindingGeneration);
|
|
1080
|
-
}
|
|
1081
|
-
function validAcceptedTargetProof(state, proof) {
|
|
1082
|
-
return (proof.actorId === state.actorId &&
|
|
1083
|
-
proof.objectGeneration === state.actorGeneration &&
|
|
1084
|
-
proof.actorNodeRid.length > 0 &&
|
|
1085
|
-
proof.actorNodeGeneration > 0n &&
|
|
1086
|
-
proof.sessionIdentity === state.sessionIdentity &&
|
|
1087
|
-
proof.bindingGeneration === state.bindingGeneration);
|
|
1088
|
-
}
|
|
1089
|
-
function relocationSourceProof(state) {
|
|
1090
|
-
if (state.sessionIdentity === undefined ||
|
|
1091
|
-
state.actorNodeRid === undefined ||
|
|
1092
|
-
state.actorNodeGeneration === undefined)
|
|
1093
|
-
return undefined;
|
|
1094
|
-
return {
|
|
1095
|
-
actorId: state.actorId,
|
|
1096
|
-
objectGeneration: state.actorGeneration,
|
|
1097
|
-
actorNodeRid: state.actorNodeRid,
|
|
1098
|
-
actorNodeGeneration: state.actorNodeGeneration,
|
|
1099
|
-
sessionIdentity: state.sessionIdentity,
|
|
1100
|
-
bindingGeneration: state.bindingGeneration
|
|
1101
|
-
};
|
|
1102
|
-
}
|
|
1103
951
|
function failRetainedOutbound(operation, error) {
|
|
1104
952
|
try {
|
|
1105
953
|
operation.fail(error);
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { ActorRef } from '../../contracts';
|
|
2
|
-
import type {
|
|
3
|
-
import type { ZLinkActorSessionAuthorityFence,
|
|
2
|
+
import type { ServiceSessionBindingAdmissionResult } from '../foundation/service-session-binding-ingress-port';
|
|
3
|
+
import type { ZLinkActorSessionAuthorityFence, ZLinkActorSessionRelocationClaim, ZLinkActorSessionRelocationSnapshot, ZLinkActorSessionRetainedOutbound, ZLinkActorSessionRouteFence } from './actor-session-binding-registry';
|
|
4
4
|
export interface ZLinkActorSessionBindingRuntimeOwner {
|
|
5
5
|
actorSlot(actorId: string, sessionRid: string): Promise<number | undefined>;
|
|
6
6
|
sealRelocation(claim: ZLinkActorSessionRelocationClaim, expected: ZLinkActorSessionRouteFence, signal?: AbortSignal): Promise<void>;
|
|
7
7
|
relocationSnapshot(actorId: string, sealId: string): Promise<ZLinkActorSessionRelocationSnapshot | undefined>;
|
|
8
8
|
retainRelocationOutbound(actorId: string, operation: ZLinkActorSessionRetainedOutbound, sealId?: string): Promise<ServiceSessionBindingAdmissionResult>;
|
|
9
|
-
admitRelocationOutbound(claim: ServiceSessionBindingAdmissionClaim, operation: ZLinkActorSessionRetainedOutbound): Promise<ServiceSessionBindingAdmissionResult>;
|
|
10
9
|
discardRelocationOutbound(actorId: string, sealId: string, error: unknown): Promise<void>;
|
|
11
|
-
applyRelocation(actorId: string, sealId: string, applyFingerprint: string,
|
|
10
|
+
applyRelocation(actorId: string, sealId: string, applyFingerprint: string, commitOwnerTransition: () => Promise<void>): Promise<void>;
|
|
12
11
|
observeRelocationTerminal(actorId: string, sealId: string, applyFingerprint: string): Promise<void>;
|
|
13
12
|
clearRelocation(actorId: string, error: unknown): Promise<void>;
|
|
14
13
|
committedRoute(actorId: string): Promise<{
|
|
@@ -157,7 +157,7 @@ class ZLinkBoundSessionService {
|
|
|
157
157
|
async submitNativeBoundSessionFrame(node, actorRef, frame, signal) {
|
|
158
158
|
const backendActorRef = toBoundSessionSendActorRef(actorRef);
|
|
159
159
|
(0, abort_1.throwIfAborted)(signal);
|
|
160
|
-
return await node.sendActorBoundSession(backendActorRef, requireBoundSessionGeneration(actorRef), [frame], ZLINK_SEND_DONT_WAIT
|
|
160
|
+
return await node.sendActorBoundSession(backendActorRef, requireBoundSessionGeneration(actorRef), [frame], ZLINK_SEND_DONT_WAIT);
|
|
161
161
|
}
|
|
162
162
|
requireTransport() {
|
|
163
163
|
if (this.options.transport === undefined) {
|
|
@@ -184,20 +184,3 @@ function toBoundSessionSendActorRef(actor) {
|
|
|
184
184
|
generation: actor.objectGeneration
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
|
-
function boundSessionSendFence(node, backendActor, actor) {
|
|
188
|
-
const internal = actor;
|
|
189
|
-
const ownerNodeGeneration = internal.ownerNodeGeneration ?? node.actorNodeGeneration?.(backendActor);
|
|
190
|
-
if (internal.ownershipGeneration === undefined ||
|
|
191
|
-
internal.ownershipGeneration <= 0n ||
|
|
192
|
-
internal.ownerLeaseGeneration === undefined ||
|
|
193
|
-
internal.ownerLeaseGeneration <= 0n ||
|
|
194
|
-
ownerNodeGeneration === undefined ||
|
|
195
|
-
ownerNodeGeneration <= 0n) {
|
|
196
|
-
return undefined;
|
|
197
|
-
}
|
|
198
|
-
return Object.freeze({
|
|
199
|
-
targetNodeGeneration: ownerNodeGeneration,
|
|
200
|
-
authorityOwnerGeneration: internal.ownershipGeneration,
|
|
201
|
-
ownerLeaseGeneration: internal.ownerLeaseGeneration
|
|
202
|
-
});
|
|
203
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ZLinkListenerRecords } from '../foundation/listener-records';
|
|
1
2
|
import type { ActorRef, ZLinkActor, ZLinkBoundSession, ZLinkSessionActor, ZLinkMessageSerializer, ZLinkStreamCompressionOptions } from '../../contracts';
|
|
2
3
|
import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
|
|
3
4
|
import type { ZLinkSubmitResult } from '../messaging/submission-result';
|
|
@@ -68,6 +69,7 @@ export interface ZLinkStreamSessionNodeRuntimeOptions extends Omit<ZLinkStreamSe
|
|
|
68
69
|
readonly bindingRuntime?: ZLinkStreamBindingRuntime;
|
|
69
70
|
}
|
|
70
71
|
export interface ZLinkStreamRuntimeManagerOptions {
|
|
72
|
+
readonly listenerRecords?: ZLinkListenerRecords;
|
|
71
73
|
readonly registration: ZLinkFrameworkRegistration;
|
|
72
74
|
readonly backendAdapterFactory: ZLinkBackendAdapterFactory;
|
|
73
75
|
readonly context: ZLinkBackendContext;
|
|
@@ -56,6 +56,12 @@ class ZLinkStreamRuntimeManager {
|
|
|
56
56
|
const nativeMeshNode = actorDispatchEnabled ? this.options.nativeMeshNode : undefined;
|
|
57
57
|
const meshCompletions = actorDispatchEnabled ? this.options.meshCompletions : undefined;
|
|
58
58
|
const socket = streamAdapter.createStreamSocket(this.options.context);
|
|
59
|
+
const node = {
|
|
60
|
+
meshName: applicationMeshName,
|
|
61
|
+
socket,
|
|
62
|
+
nativeSessionServices: []
|
|
63
|
+
};
|
|
64
|
+
this.nodes.set(nodeName, node);
|
|
59
65
|
// Core uses -1 as the explicit unlimited value. The Framework value 0
|
|
60
66
|
// means that it adds no separate STREAM cap, so preserve that meaning
|
|
61
67
|
// when applying the socket option.
|
|
@@ -71,7 +77,6 @@ class ZLinkStreamRuntimeManager {
|
|
|
71
77
|
if (advertisedEndpoint === undefined) {
|
|
72
78
|
throw new configuration_1.ZLinkConfigurationException(`STREAM node '${nodeName}' advertised host requires a TCP endpoint, received '${boundEndpoint}'.`);
|
|
73
79
|
}
|
|
74
|
-
const readablePoller = streamAdapter.createReadablePoller(socket);
|
|
75
80
|
const nativeSessionRoutes = new Map();
|
|
76
81
|
if (actorDispatchEnabled) {
|
|
77
82
|
for (const [meshName, mesh] of this.options.registration.spotNodes) {
|
|
@@ -86,10 +91,11 @@ class ZLinkStreamRuntimeManager {
|
|
|
86
91
|
if (typeof createService !== 'function' || completions === undefined)
|
|
87
92
|
continue;
|
|
88
93
|
const service = createService.call(meshNode, socket.nativeInstance);
|
|
94
|
+
node.nativeSessionServices.push(service);
|
|
89
95
|
const bindingOwner = (0, actor_session_binding_runtime_owner_1.actorSessionBindingRuntimeOwner)(this.options.bindingRuntime);
|
|
90
96
|
(0, service_session_binding_ingress_port_1.registerServiceSessionBindingIngressPort)(service, {
|
|
91
97
|
actorSlot: (actorId, sessionRid) => bindingOwner.actorSlot(actorId, sessionRid),
|
|
92
|
-
retainOutbound: (
|
|
98
|
+
retainOutbound: (actorId, delivery) => bindingOwner.retainRelocationOutbound(actorId, delivery),
|
|
93
99
|
clearOutbound: (actorId, error) => bindingOwner.clearRelocation(actorId, error)
|
|
94
100
|
});
|
|
95
101
|
nativeSessionRoutes.set(meshName, {
|
|
@@ -102,8 +108,12 @@ class ZLinkStreamRuntimeManager {
|
|
|
102
108
|
? undefined
|
|
103
109
|
: nativeSessionRoutes.get(applicationMeshName)?.service;
|
|
104
110
|
const monitor = monitoringAdapter.openSocketMonitor(socket);
|
|
111
|
+
node.monitor = monitor;
|
|
105
112
|
const sessionType = streamNode.session;
|
|
106
113
|
const sessionHandlerTypes = streamNode[Symbol.for('@zlink-systems/framework:session-handler-types')] ?? [];
|
|
114
|
+
// The runtime disposes the poller, so the poller is created where nothing
|
|
115
|
+
// can fail before the runtime owns it.
|
|
116
|
+
const readablePoller = streamAdapter.createReadablePoller(socket);
|
|
107
117
|
const runtime = new stream_session_runtime_1.ZLinkStreamSessionNodeRuntime({
|
|
108
118
|
nodeName,
|
|
109
119
|
socket,
|
|
@@ -123,42 +133,33 @@ class ZLinkStreamRuntimeManager {
|
|
|
123
133
|
replacementCallbackTimeoutMs: this.options.registration.sessionReplacementCallbackTimeoutMs,
|
|
124
134
|
sessionFactory: (context) => (0, session_provider_1.createStreamSessionInstance)(sessionType, this.options.providerResolver, context, sessionHandlerTypes)
|
|
125
135
|
});
|
|
136
|
+
node.runtime = runtime;
|
|
126
137
|
runtime.start();
|
|
127
|
-
this.
|
|
128
|
-
meshName: applicationMeshName,
|
|
129
|
-
advertisedEndpoint,
|
|
130
|
-
runtime,
|
|
131
|
-
socket,
|
|
132
|
-
monitor,
|
|
133
|
-
nativeSessionService,
|
|
134
|
-
nativeSessionServices: [...nativeSessionRoutes.values()].map((route) => route.service)
|
|
135
|
-
});
|
|
138
|
+
this.options.listenerRecords?.record('stream', nodeName, advertisedEndpoint);
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
async dispose() {
|
|
139
142
|
const nodes = [...this.nodes.values()];
|
|
140
143
|
this.nodes.clear();
|
|
141
144
|
for (const node of nodes.reverse()) {
|
|
142
|
-
await node.runtime
|
|
143
|
-
const
|
|
144
|
-
(node.nativeSessionService === undefined ? [] : [node.nativeSessionService]);
|
|
145
|
-
for (const service of nativeServices) {
|
|
145
|
+
await node.runtime?.dispose();
|
|
146
|
+
for (const service of node.nativeSessionServices) {
|
|
146
147
|
service.shutdown(1000);
|
|
147
148
|
service.close();
|
|
148
149
|
}
|
|
149
|
-
await node.monitor
|
|
150
|
+
await node.monitor?.dispose();
|
|
150
151
|
await node.socket.dispose();
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
async notifyServerDrain(meshName) {
|
|
154
155
|
await Promise.all([...this.nodes.values()]
|
|
155
156
|
.filter((node) => node.meshName === meshName)
|
|
156
|
-
.map((node) => node.runtime
|
|
157
|
+
.map((node) => node.runtime?.drainCloseSessions()));
|
|
157
158
|
}
|
|
158
159
|
async notifyUnscopedServerDrain() {
|
|
159
160
|
await Promise.all([...this.nodes.values()]
|
|
160
161
|
.filter((node) => node.meshName === undefined)
|
|
161
|
-
.map((node) => node.runtime
|
|
162
|
+
.map((node) => node.runtime?.drainCloseSessions()));
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
exports.ZLinkStreamRuntimeManager = ZLinkStreamRuntimeManager;
|
|
@@ -224,7 +225,6 @@ class ZLinkStreamBindingRuntime {
|
|
|
224
225
|
sealRelocation: (claim, expected, signal) => this.routes.sealRelocation(claim, expected, signal),
|
|
225
226
|
relocationSnapshot: (actorId, sealId) => this.routes.relocationSnapshot(actorId, sealId),
|
|
226
227
|
retainRelocationOutbound: (actorId, operation, sealId) => this.routes.retainRelocationOutbound(actorId, operation, sealId),
|
|
227
|
-
admitRelocationOutbound: (claim, operation) => this.routes.admitRelocationOutbound(claim, operation),
|
|
228
228
|
discardRelocationOutbound: (actorId, sealId, error) => this.routes.discardRelocationOutbound(actorId, sealId, error),
|
|
229
229
|
applyRelocation: (...args) => this.routes.applyRelocation(...args),
|
|
230
230
|
observeRelocationTerminal: (...args) => this.routes.observeRelocationTerminal(...args),
|
|
@@ -22,8 +22,8 @@ class ZLinkSessionSerialExecutor {
|
|
|
22
22
|
}
|
|
23
23
|
const boundWork = (0, application_job_queue_scope_1.bindApplicationJobPermit)(work);
|
|
24
24
|
return (0, application_job_queue_scope_1.hasApplicationJobPermit)()
|
|
25
|
-
? this.scheduler.submitPreAdmitted(boundWork, { lane: '
|
|
26
|
-
: this.scheduler.submit(boundWork, { lane: '
|
|
25
|
+
? this.scheduler.submitPreAdmitted(boundWork, { lane: 'application' })
|
|
26
|
+
: this.scheduler.submit(boundWork, { lane: 'application' });
|
|
27
27
|
}
|
|
28
28
|
submit(work, lane, options = {}, onRejected) {
|
|
29
29
|
if (this.closed)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zlink-systems/framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@opentelemetry/api": "^1.9.1",
|
|
21
21
|
"@opentelemetry/api-logs": "^0.221.0",
|
|
22
|
-
"@zlink-systems/stream-wire": "0.
|
|
23
|
-
"@zlink-systems/zlink": "1.
|
|
22
|
+
"@zlink-systems/stream-wire": "0.26.0",
|
|
23
|
+
"@zlink-systems/zlink": "1.10.0"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import type { ZLinkFanoutPublishCall } from './Calls';
|
|
2
2
|
|
|
3
|
-
export interface ZLinkFanoutListenerStatus {
|
|
4
|
-
readonly channelName: string;
|
|
5
|
-
readonly endpoint: string;
|
|
6
|
-
readonly observedAt: Date;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
3
|
export interface ZLinkFanoutClient {
|
|
10
4
|
publish(channelName: string, event: unknown): ZLinkFanoutPublishCall;
|
|
11
5
|
publish(channelName: string, topic: string, event: unknown): ZLinkFanoutPublishCall;
|
|
12
|
-
getListenerStatus(channelName: string): ZLinkFanoutListenerStatus;
|
|
13
6
|
}
|
|
@@ -142,12 +142,22 @@ export interface ZLinkHostCapacityStatus {
|
|
|
142
142
|
|
|
143
143
|
export interface ZLinkFrameworkRuntime {
|
|
144
144
|
readonly status: ZLinkFrameworkRuntimeStatus;
|
|
145
|
+
getListenerStatus(kind: ZLinkListenerKind, name: string): ZLinkListenerStatus;
|
|
145
146
|
observe(signal?: AbortSignal): AsyncIterable<ZLinkObservedStatus<ZLinkFrameworkRuntimeStatus>>;
|
|
146
147
|
resetCapacityMetrics(): void;
|
|
147
148
|
relocate(options: ZLinkFrameworkRelocationOptions): Promise<ZLinkFrameworkRelocationResult>;
|
|
148
149
|
shutdown(options?: ZLinkFrameworkLifecycleOptions): Promise<ZLinkFrameworkTerminationResult>;
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
export type ZLinkListenerKind = 'routeMesh' | 'clientServer' | 'fanout' | 'stream';
|
|
153
|
+
|
|
154
|
+
export interface ZLinkListenerStatus {
|
|
155
|
+
readonly kind: ZLinkListenerKind;
|
|
156
|
+
readonly name: string;
|
|
157
|
+
readonly endpoint: string;
|
|
158
|
+
readonly observedAt: Date;
|
|
159
|
+
}
|
|
160
|
+
|
|
151
161
|
export type ZLinkClientServerRole = 'client' | 'server' | 'clientAndServer';
|
|
152
162
|
|
|
153
163
|
export interface ZLinkClientServerTargetStatus {
|
package/src/internal.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './index';
|
|
|
3
3
|
export * from './runtime/diagnostics';
|
|
4
4
|
export * from './runtime/host';
|
|
5
5
|
export * from './runtime/admission';
|
|
6
|
+
export * from './runtime/activation-admission';
|
|
6
7
|
export * from './runtime/streams';
|
|
7
8
|
export * from './runtime/streams/protocol';
|
|
8
9
|
export * from './runtime/actors';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ZLinkFrameworkInternalErrorKind,
|
|
3
|
+
createInternalFrameworkException
|
|
4
|
+
} from './framework-errors-internal';
|
|
5
|
+
|
|
6
|
+
/** Current activation admission count and limit of one MeshNode. */
|
|
7
|
+
export interface ZLinkActivationConcurrency {
|
|
8
|
+
readonly active: number;
|
|
9
|
+
readonly limit: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ZLinkActivationRecord {
|
|
13
|
+
readonly meshName: string;
|
|
14
|
+
readonly limit: number;
|
|
15
|
+
active: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* MeshNode §5.1 "Pending activation": the single per-MeshNode record of activation admissions.
|
|
20
|
+
*
|
|
21
|
+
* Actor creation, User Spot creation, Instance Spot cold activation and a relocation target's
|
|
22
|
+
* Restore each hold one admission from the moment the target MeshNode receives the operation
|
|
23
|
+
* until Ready or its target commit, or until it ends by rejection, failure or cleanup. Entry Spot
|
|
24
|
+
* and Actor Join never acquire one. The limit is enforced here, and the status current value and
|
|
25
|
+
* the placement `IsAvailable` headroom both read this record.
|
|
26
|
+
*/
|
|
27
|
+
export class ZLinkActivationAdmission {
|
|
28
|
+
private readonly records = new Map<string, ZLinkActivationRecord>();
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
private readonly limitOf: (meshName: string) => number,
|
|
32
|
+
private readonly changed?: (meshName: string) => void
|
|
33
|
+
) {}
|
|
34
|
+
|
|
35
|
+
current(meshName: string): ZLinkActivationConcurrency {
|
|
36
|
+
const record = this.records.get(meshName);
|
|
37
|
+
return { active: record?.active ?? 0, limit: record?.limit ?? this.limitOf(meshName) };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
hasHeadroom(meshName: string): boolean {
|
|
41
|
+
const { active, limit } = this.current(meshName);
|
|
42
|
+
return active < limit;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Holds one admission for `meshName`. A MeshNode without headroom does not accept a new
|
|
47
|
+
* admission (MeshNode §5.1): the operation fails as Unavailable at once. The returned release
|
|
48
|
+
* is idempotent.
|
|
49
|
+
*/
|
|
50
|
+
async acquire(meshName: string, signal?: AbortSignal): Promise<() => void> {
|
|
51
|
+
signal?.throwIfAborted();
|
|
52
|
+
const record = this.record(meshName);
|
|
53
|
+
if (record.active >= record.limit) {
|
|
54
|
+
throw createInternalFrameworkException(
|
|
55
|
+
ZLinkFrameworkInternalErrorKind.PlacementCapacityExhausted,
|
|
56
|
+
`MeshNode '${meshName}' has no activation admission headroom.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
record.active += 1;
|
|
60
|
+
this.changed?.(meshName);
|
|
61
|
+
let released = false;
|
|
62
|
+
return () => {
|
|
63
|
+
if (released) return;
|
|
64
|
+
released = true;
|
|
65
|
+
record.active -= 1;
|
|
66
|
+
this.changed?.(meshName);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private record(meshName: string): ZLinkActivationRecord {
|
|
71
|
+
let record = this.records.get(meshName);
|
|
72
|
+
if (record === undefined) {
|
|
73
|
+
record = { meshName, limit: this.limitOf(meshName), active: 0 };
|
|
74
|
+
this.records.set(meshName, record);
|
|
75
|
+
}
|
|
76
|
+
return record;
|
|
77
|
+
}
|
|
78
|
+
}
|