@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,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RawServiceMeshRuntime = void 0;
|
|
4
|
-
const node_crypto_1 = require("node:crypto");
|
|
5
4
|
const runtime_values_1 = require("../backend/runtime-values");
|
|
6
5
|
const application_ingress_record_owner_1 = require("../application-jobs/application-ingress-record-owner");
|
|
7
6
|
const operation_registry_1 = require("./operation-registry");
|
|
@@ -11,9 +10,6 @@ const service_topology_registry_1 = require("./service-topology-registry");
|
|
|
11
10
|
const service_wire_m6a_codec_1 = require("./service-wire-m6a-codec");
|
|
12
11
|
const service_wire_codec_1 = require("./service-wire-codec");
|
|
13
12
|
const service_wire_constants_generated_1 = require("./service-wire-constants.generated");
|
|
14
|
-
const MONITOR_DISCONNECTED = 0x0200;
|
|
15
|
-
const MONITOR_CONNECTION_READY = 0x1000;
|
|
16
|
-
const MONITOR_CONNECTION_READY_EDGE = 1;
|
|
17
13
|
// Framework error code 13 (RequestTargetNotFound) is encoded as 14 on a
|
|
18
14
|
// RequestResult.NotFound reply. Boundary transport results keep failureCode 0.
|
|
19
15
|
const REQUEST_TARGET_NOT_FOUND_FAILURE_CODE = 14;
|
|
@@ -22,8 +18,6 @@ const livenessCodec = (0, service_wire_codec_1.createServiceWireCodec)({
|
|
|
22
18
|
major: 1,
|
|
23
19
|
commands: service_wire_m6a_codec_1.M6aServiceWireCommand
|
|
24
20
|
});
|
|
25
|
-
const MAX_PENDING_MONITOR_EVENTS = 8192;
|
|
26
|
-
const MAX_UNRESOLVED_CONNECTION_CANDIDATES = 4096;
|
|
27
21
|
/**
|
|
28
22
|
* RouteMesh M6A runtime built only on the public raw binding package.
|
|
29
23
|
* It owns protocol, admission, mailbox, request and liveness state.
|
|
@@ -36,17 +30,11 @@ class RawServiceMeshRuntime {
|
|
|
36
30
|
expectedPeers = new Map();
|
|
37
31
|
endpointOnlyPeers = new Set();
|
|
38
32
|
peerConnectionIntentRemoved = new Set();
|
|
39
|
-
connectionCandidates = new Map();
|
|
40
|
-
unresolvedConnectionCandidates = [];
|
|
41
|
-
connectionIds = new Map();
|
|
42
33
|
/**
|
|
43
|
-
* The
|
|
44
|
-
*
|
|
45
|
-
* longer usable by the application route.
|
|
34
|
+
* The last observed Core selected route of each RID (Core ROUTER §10.1):
|
|
35
|
+
* RID -> route generation. Only `observeSelectedRoutes` replaces it.
|
|
46
36
|
*/
|
|
47
|
-
|
|
48
|
-
monitorEvents = [];
|
|
49
|
-
monitorDrainBuffer = [];
|
|
37
|
+
selectedRoutes = new Map();
|
|
50
38
|
bindingPort;
|
|
51
39
|
applicationJobQueue;
|
|
52
40
|
peerAdmissionSealed;
|
|
@@ -59,7 +47,6 @@ class RawServiceMeshRuntime {
|
|
|
59
47
|
descriptor;
|
|
60
48
|
host;
|
|
61
49
|
router;
|
|
62
|
-
monitor;
|
|
63
50
|
nextCorrelation = 1n;
|
|
64
51
|
serviceIngress;
|
|
65
52
|
closed = false;
|
|
@@ -102,8 +89,6 @@ class RawServiceMeshRuntime {
|
|
|
102
89
|
};
|
|
103
90
|
this.topology.publishLocal(next);
|
|
104
91
|
this.descriptor = next;
|
|
105
|
-
this.monitor = router.monitor();
|
|
106
|
-
this.pullMonitorEvents();
|
|
107
92
|
this.host = host;
|
|
108
93
|
this.router = router;
|
|
109
94
|
}
|
|
@@ -237,24 +222,22 @@ class RawServiceMeshRuntime {
|
|
|
237
222
|
]);
|
|
238
223
|
}
|
|
239
224
|
isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
|
|
225
|
+
// Admission is bound to the observed selected route: the route observer
|
|
226
|
+
// removes the peer when that route ends or is replaced.
|
|
240
227
|
const peer = this.topology.peer(nodeRoutingId);
|
|
241
|
-
|
|
242
|
-
const applicationRouteReady = monitorConnection === undefined || monitorConnection === peer?.connectionId;
|
|
243
|
-
const ready = peer !== undefined &&
|
|
228
|
+
return (peer !== undefined &&
|
|
244
229
|
(lifecycleGeneration === undefined ||
|
|
245
230
|
peer.descriptor.lifecycleGeneration === lifecycleGeneration) &&
|
|
246
|
-
|
|
247
|
-
this.liveness.isReady(nodeRoutingId, peer.connectionId);
|
|
248
|
-
return ready;
|
|
231
|
+
this.liveness.isReady(nodeRoutingId, peer.connectionId));
|
|
249
232
|
}
|
|
250
233
|
async announceExpectedPeers() {
|
|
251
234
|
let accepted = 0;
|
|
252
235
|
for (const nodeRoutingId of this.expectedPeers.keys()) {
|
|
253
|
-
// Admission is a one-time fence for the current
|
|
236
|
+
// Admission is a one-time fence for the current selected route.
|
|
254
237
|
// Re-sending Hello after the peer is admitted would re-run admission on
|
|
255
238
|
// every poll and reset the liveness record before application traffic
|
|
256
|
-
// can use the route. A
|
|
257
|
-
// and remains eligible for the next admission attempt.
|
|
239
|
+
// can use the route. A peer whose selected route ended is removed by the
|
|
240
|
+
// route observer and remains eligible for the next admission attempt.
|
|
258
241
|
if (this.topology.peer(nodeRoutingId) !== undefined)
|
|
259
242
|
continue;
|
|
260
243
|
if (await this.announcePeer(nodeRoutingId))
|
|
@@ -410,7 +393,6 @@ class RawServiceMeshRuntime {
|
|
|
410
393
|
]);
|
|
411
394
|
}
|
|
412
395
|
async pumpOne(nowMs = performance.now(), observe) {
|
|
413
|
-
this.pullMonitorEvents();
|
|
414
396
|
return this.receiveOne(nowMs, observe);
|
|
415
397
|
}
|
|
416
398
|
setReadableHandler(handler) {
|
|
@@ -418,7 +400,7 @@ class RawServiceMeshRuntime {
|
|
|
418
400
|
}
|
|
419
401
|
/** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
|
|
420
402
|
async pumpBatch(receiveReady = true) {
|
|
421
|
-
await this.
|
|
403
|
+
await this.observeSelectedRoutes();
|
|
422
404
|
const startedAtMs = performance.now();
|
|
423
405
|
let messages = 0;
|
|
424
406
|
let bytes = 0;
|
|
@@ -483,22 +465,6 @@ class RawServiceMeshRuntime {
|
|
|
483
465
|
applicationJobOwner.close();
|
|
484
466
|
}
|
|
485
467
|
}
|
|
486
|
-
pullMonitorEvents() {
|
|
487
|
-
this.monitor?.drain((event) => {
|
|
488
|
-
this.observeMonitorEvent(event);
|
|
489
|
-
if (this.monitorEvents.length < MAX_PENDING_MONITOR_EVENTS) {
|
|
490
|
-
this.monitorEvents.push(event);
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
const existingIndex = this.monitorEvents.findIndex((candidate) => sameMonitorConnection(candidate, event));
|
|
494
|
-
if (existingIndex >= 0)
|
|
495
|
-
this.monitorEvents[existingIndex] = event;
|
|
496
|
-
else {
|
|
497
|
-
this.monitorEvents.shift();
|
|
498
|
-
this.monitorEvents.push(event);
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
468
|
reportProtocolError(received) {
|
|
503
469
|
const request = received.requestSeq !== undefined;
|
|
504
470
|
const replied = request && this.replyGenericProtocolError(received);
|
|
@@ -564,8 +530,7 @@ class RawServiceMeshRuntime {
|
|
|
564
530
|
await this.send(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(3)]);
|
|
565
531
|
return 'infrastructure';
|
|
566
532
|
}
|
|
567
|
-
const
|
|
568
|
-
const result = this.admitPeer(descriptor, connection, nowMs, expected);
|
|
533
|
+
const result = this.admitPeer(descriptor, routeConnectionId(received.routeGeneration), nowMs, expected);
|
|
569
534
|
if (result !== 'admitted' && result !== 'notRequired') {
|
|
570
535
|
const detail = result === 'invalidDescriptor'
|
|
571
536
|
? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
|
|
@@ -594,10 +559,8 @@ class RawServiceMeshRuntime {
|
|
|
594
559
|
if (received.parts.length !== 1)
|
|
595
560
|
return 'protocolError';
|
|
596
561
|
const reason = (0, service_wire_m6a_codec_1.decodeReject)(received.parts[0]);
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
// peer: bilateral manual connect can reject the duplicate after the
|
|
600
|
-
// other candidate has become Ready.
|
|
562
|
+
// Keep an already admitted peer: a reject of an earlier Hello on the
|
|
563
|
+
// same selected route does not end the admission that succeeded.
|
|
601
564
|
if (reason === 4 && this.topology.peer(received.sourceRid) === undefined) {
|
|
602
565
|
const expected = this.expectedPeers.get(received.sourceRid);
|
|
603
566
|
const local = this.topology.localDescriptor();
|
|
@@ -752,121 +715,48 @@ class RawServiceMeshRuntime {
|
|
|
752
715
|
const peer = this.topology.peer(nodeRoutingId);
|
|
753
716
|
if (peer === undefined)
|
|
754
717
|
continue;
|
|
755
|
-
// Liveness timeout is a semantic peer removal.
|
|
756
|
-
// physical candidate state, and auto-connect intent must be retired by
|
|
757
|
-
// the same owner so a failed endpoint cannot be selected again.
|
|
758
|
-
this.removeConnectionCandidate(nodeRoutingId, peer.connectionId);
|
|
718
|
+
// Liveness timeout is a semantic peer removal of the admitted route.
|
|
759
719
|
this.removePeer(peer);
|
|
760
720
|
}
|
|
761
721
|
return result;
|
|
762
722
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
this.
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (!this.acceptsExpectedMonitorEndpoint(nodeRoutingId, event)) {
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
const candidate = this.createConnectionCandidate(nodeRoutingId, event);
|
|
789
|
-
const existingPeer = this.topology.peer(nodeRoutingId);
|
|
790
|
-
if (existingPeer !== undefined && existingPeer.connectionId === candidate.connectionId) {
|
|
791
|
-
this.monitorConnectionStates.set(nodeRoutingId, candidate.connectionId);
|
|
792
|
-
continue;
|
|
793
|
-
}
|
|
794
|
-
if (existingPeer !== undefined) {
|
|
795
|
-
if (this.liveness.isReady(nodeRoutingId, existingPeer.connectionId)) {
|
|
796
|
-
const existingCandidate = this.connectionCandidates
|
|
797
|
-
.get(nodeRoutingId)
|
|
798
|
-
?.get(existingPeer.connectionId);
|
|
799
|
-
if (this.isDiscoveredLifecycleReplacement(existingPeer, nodeRoutingId)) {
|
|
800
|
-
// A current discovery descriptor with the same RID but a
|
|
801
|
-
// different lifecycle token denotes a replacement process.
|
|
802
|
-
// Keep its physical pair provisional until its Hello passes
|
|
803
|
-
// the descriptor fence; the old ready peer remains semantic
|
|
804
|
-
// current until then.
|
|
805
|
-
let provisionalCandidates = this.connectionCandidates.get(nodeRoutingId);
|
|
806
|
-
if (provisionalCandidates === undefined) {
|
|
807
|
-
provisionalCandidates = new Map();
|
|
808
|
-
this.connectionCandidates.set(nodeRoutingId, provisionalCandidates);
|
|
809
|
-
}
|
|
810
|
-
provisionalCandidates.set(candidate.connectionId, candidate);
|
|
811
|
-
await this.announcePeer(nodeRoutingId);
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
if (existingCandidate?.connectionId === candidate.connectionId) {
|
|
815
|
-
this.removeConnectionCandidate(nodeRoutingId, candidate.connectionId);
|
|
816
|
-
this.monitorConnectionStates.set(nodeRoutingId, existingPeer.connectionId);
|
|
817
|
-
continue;
|
|
818
|
-
}
|
|
819
|
-
// A non-replacement ready route is the current semantic owner.
|
|
820
|
-
// A second physical candidate may be admitted only after the
|
|
821
|
-
// current lease expires; this also prevents a late old-process
|
|
822
|
-
// reconnect from replacing the ready replacement by arrival order.
|
|
823
|
-
this.removeConnectionCandidate(nodeRoutingId, candidate.connectionId);
|
|
824
|
-
continue;
|
|
825
|
-
}
|
|
826
|
-
// Keep the physical candidate until the wire descriptor decides
|
|
827
|
-
// whether it is the current logical peer. READY events can race
|
|
828
|
-
// with DISCONNECTED events during reconnect; rejecting the READY
|
|
829
|
-
// here can terminate the replacement before admission evaluates its
|
|
830
|
-
// lifecycle generation.
|
|
831
|
-
let provisionalCandidates = this.connectionCandidates.get(nodeRoutingId);
|
|
832
|
-
if (provisionalCandidates === undefined) {
|
|
833
|
-
provisionalCandidates = new Map();
|
|
834
|
-
this.connectionCandidates.set(nodeRoutingId, provisionalCandidates);
|
|
835
|
-
}
|
|
836
|
-
provisionalCandidates.set(candidate.connectionId, candidate);
|
|
837
|
-
this.connectionIds.set(nodeRoutingId, candidate.connectionId);
|
|
838
|
-
await this.announcePeer(nodeRoutingId);
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
let candidates = this.connectionCandidates.get(nodeRoutingId);
|
|
842
|
-
if (candidates === undefined) {
|
|
843
|
-
candidates = new Map();
|
|
844
|
-
this.connectionCandidates.set(nodeRoutingId, candidates);
|
|
845
|
-
}
|
|
846
|
-
candidates.set(candidate.connectionId, candidate);
|
|
847
|
-
// Before wire admission the monitor candidate is the only physical
|
|
848
|
-
// route evidence available to the admission message.
|
|
849
|
-
this.connectionIds.set(nodeRoutingId, candidate.connectionId);
|
|
850
|
-
await this.announcePeer(nodeRoutingId);
|
|
851
|
-
}
|
|
852
|
-
else if (event.event === MONITOR_DISCONNECTED && nodeRoutingId !== undefined) {
|
|
853
|
-
const peer = this.topology.peer(nodeRoutingId);
|
|
854
|
-
const disconnectedId = monitorConnectionId(event, nodeRoutingId);
|
|
855
|
-
this.removeConnectionCandidate(nodeRoutingId, disconnectedId);
|
|
856
|
-
if (peer !== undefined && peer.connectionId === disconnectedId) {
|
|
857
|
-
this.removePeer(peer);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
else if (event.event === MONITOR_DISCONNECTED) {
|
|
861
|
-
const disconnectedId = monitorConnectionId(event);
|
|
862
|
-
const index = this.unresolvedConnectionCandidates.findIndex((candidate) => candidate.connectionId === disconnectedId);
|
|
863
|
-
if (index >= 0)
|
|
864
|
-
this.unresolvedConnectionCandidates.splice(index, 1);
|
|
723
|
+
/**
|
|
724
|
+
* The socket's one route observer (Core ROUTER §10.1). It replaces the
|
|
725
|
+
* observation with Core's selected-route snapshot, ends the admission of
|
|
726
|
+
* every RID whose observed route disappeared or was replaced, and starts the
|
|
727
|
+
* handshake of every newly selected route. Returns the number of changes.
|
|
728
|
+
*/
|
|
729
|
+
async observeSelectedRoutes() {
|
|
730
|
+
const router = this.router;
|
|
731
|
+
if (router === undefined || this.closed)
|
|
732
|
+
return 0;
|
|
733
|
+
const observed = new Map();
|
|
734
|
+
for (const route of router.routesSnapshot()) {
|
|
735
|
+
observed.set(route.routingId, route.routeGeneration);
|
|
736
|
+
}
|
|
737
|
+
let changes = 0;
|
|
738
|
+
for (const [nodeRoutingId, generation] of this.selectedRoutes) {
|
|
739
|
+
if (observed.get(nodeRoutingId) === generation)
|
|
740
|
+
continue;
|
|
741
|
+
changes++;
|
|
742
|
+
const peer = this.topology.peer(nodeRoutingId);
|
|
743
|
+
if (peer !== undefined && peer.connectionId === routeConnectionId(generation)) {
|
|
744
|
+
this.removePeer(peer);
|
|
865
745
|
}
|
|
866
746
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
747
|
+
const selected = [];
|
|
748
|
+
for (const [nodeRoutingId, generation] of observed) {
|
|
749
|
+
if (this.selectedRoutes.get(nodeRoutingId) === generation)
|
|
750
|
+
continue;
|
|
751
|
+
if (!this.selectedRoutes.has(nodeRoutingId))
|
|
752
|
+
changes++;
|
|
753
|
+
selected.push(nodeRoutingId);
|
|
754
|
+
}
|
|
755
|
+
this.selectedRoutes = observed;
|
|
756
|
+
// A new selected route admits only through a new handshake.
|
|
757
|
+
for (const nodeRoutingId of selected)
|
|
758
|
+
await this.announcePeer(nodeRoutingId);
|
|
759
|
+
return changes;
|
|
870
760
|
}
|
|
871
761
|
close() {
|
|
872
762
|
if (this.closed)
|
|
@@ -880,8 +770,6 @@ class RawServiceMeshRuntime {
|
|
|
880
770
|
if (router !== undefined) {
|
|
881
771
|
this.applicationJobQueue.unregisterReceiveFlowTarget?.(router);
|
|
882
772
|
}
|
|
883
|
-
this.monitor?.close();
|
|
884
|
-
this.monitor = undefined;
|
|
885
773
|
const host = this.host;
|
|
886
774
|
this.router = undefined;
|
|
887
775
|
this.host = undefined;
|
|
@@ -964,16 +852,13 @@ class RawServiceMeshRuntime {
|
|
|
964
852
|
})().catch((error) => this.operations.fail(pending.id, error));
|
|
965
853
|
return pending;
|
|
966
854
|
}
|
|
967
|
-
if (
|
|
968
|
-
//
|
|
969
|
-
//
|
|
970
|
-
//
|
|
971
|
-
// as RequestTargetNotFound without submitting an application frame.
|
|
972
|
-
const knownTarget = this.topology.peer(selectedTargetNodeRoutingId) !== undefined ||
|
|
973
|
-
this.topology.knownDescriptor(selectedTargetNodeRoutingId) !== undefined;
|
|
855
|
+
if (this.topology.peer(selectedTargetNodeRoutingId) === undefined) {
|
|
856
|
+
// Logical target selection is the requester's decision: an RID that is
|
|
857
|
+
// not an admitted peer is not a target. Whether an admitted target's
|
|
858
|
+
// route can carry the request is Core's REQUEST result.
|
|
974
859
|
this.operations.complete(pending.id, {
|
|
975
|
-
terminalResult:
|
|
976
|
-
failureCode:
|
|
860
|
+
terminalResult: runtime_values_1.RequestResult.NotFound,
|
|
861
|
+
failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
|
|
977
862
|
});
|
|
978
863
|
return pending;
|
|
979
864
|
}
|
|
@@ -1031,7 +916,7 @@ class RawServiceMeshRuntime {
|
|
|
1031
916
|
applicationPayload(payload) {
|
|
1032
917
|
return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payload) : payload;
|
|
1033
918
|
}
|
|
1034
|
-
admitPeer(descriptor,
|
|
919
|
+
admitPeer(descriptor, connectionId, nowMs, expected) {
|
|
1035
920
|
const previous = this.topology.peer(descriptor.nodeRoutingId);
|
|
1036
921
|
if (previous !== undefined &&
|
|
1037
922
|
previous.descriptor.lifecycleGeneration === descriptor.lifecycleGeneration &&
|
|
@@ -1040,190 +925,16 @@ class RawServiceMeshRuntime {
|
|
|
1040
925
|
!(0, service_topology_registry_1.sameServiceNodeDescriptor)(previous.descriptor, descriptor)))) {
|
|
1041
926
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
|
|
1042
927
|
}
|
|
1043
|
-
const result = this.topology.admit(descriptor,
|
|
928
|
+
const result = this.topology.admit(descriptor, connectionId, expected);
|
|
1044
929
|
if (result === 'admitted') {
|
|
1045
|
-
this.
|
|
1046
|
-
this.liveness.
|
|
1047
|
-
this.liveness.requestProbe(descriptor.nodeRoutingId, connection.connectionId, nowMs);
|
|
1048
|
-
this.monitorConnectionStates.set(descriptor.nodeRoutingId, connection.connectionId);
|
|
1049
|
-
if (previous !== undefined && previous.connectionId !== connection.connectionId) {
|
|
1050
|
-
const previousCandidate = this.connectionCandidates
|
|
1051
|
-
.get(descriptor.nodeRoutingId)
|
|
1052
|
-
?.get(previous.connectionId);
|
|
1053
|
-
if (previousCandidate !== undefined) {
|
|
1054
|
-
this.removeConnectionCandidate(descriptor.nodeRoutingId, previousCandidate.connectionId);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
930
|
+
this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
931
|
+
this.liveness.requestProbe(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
1057
932
|
}
|
|
1058
933
|
else if (result === 'notRequired' && previous !== undefined) {
|
|
1059
934
|
this.liveness.disconnect(descriptor.nodeRoutingId, previous.connectionId);
|
|
1060
935
|
}
|
|
1061
|
-
else if (previous !== undefined) {
|
|
1062
|
-
this.connectionIds.set(descriptor.nodeRoutingId, previous.connectionId);
|
|
1063
|
-
if (connection.connectionId !== previous.connectionId) {
|
|
1064
|
-
this.removeConnectionCandidate(descriptor.nodeRoutingId, connection.connectionId);
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
936
|
return result;
|
|
1068
937
|
}
|
|
1069
|
-
currentConnectionCandidate(nodeRoutingId, advertisedEndpoint) {
|
|
1070
|
-
let connectionId = this.connectionIds.get(nodeRoutingId);
|
|
1071
|
-
let candidate = connectionId === undefined
|
|
1072
|
-
? undefined
|
|
1073
|
-
: this.connectionCandidates.get(nodeRoutingId)?.get(connectionId);
|
|
1074
|
-
if (candidate === undefined) {
|
|
1075
|
-
candidate = this.promoteUnresolvedConnectionCandidate(nodeRoutingId, advertisedEndpoint);
|
|
1076
|
-
connectionId = candidate?.connectionId;
|
|
1077
|
-
}
|
|
1078
|
-
if (candidate === undefined) {
|
|
1079
|
-
const localRid = this.topology.localDescriptor().nodeRoutingId;
|
|
1080
|
-
const endpointOnly = this.endpointOnlyPeers.has(advertisedEndpoint);
|
|
1081
|
-
const direction = this.expectedPeers.has(nodeRoutingId)
|
|
1082
|
-
? 'outbound'
|
|
1083
|
-
: endpointOnly
|
|
1084
|
-
? localRid.localeCompare(nodeRoutingId) <= 0
|
|
1085
|
-
? 'outbound'
|
|
1086
|
-
: 'inbound'
|
|
1087
|
-
: 'inbound';
|
|
1088
|
-
const initiator = endpointOnly && localRid.localeCompare(nodeRoutingId) > 0
|
|
1089
|
-
? nodeRoutingId
|
|
1090
|
-
: direction === 'outbound'
|
|
1091
|
-
? localRid
|
|
1092
|
-
: nodeRoutingId;
|
|
1093
|
-
connectionId = `unmonitored:${direction}:${(0, node_crypto_1.randomUUID)()}`;
|
|
1094
|
-
candidate = {
|
|
1095
|
-
connectionId,
|
|
1096
|
-
direction,
|
|
1097
|
-
discriminator: `initiator:${initiator}`,
|
|
1098
|
-
localAddress: '',
|
|
1099
|
-
remoteAddress: advertisedEndpoint
|
|
1100
|
-
};
|
|
1101
|
-
let candidates = this.connectionCandidates.get(nodeRoutingId);
|
|
1102
|
-
if (candidates === undefined) {
|
|
1103
|
-
candidates = new Map();
|
|
1104
|
-
this.connectionCandidates.set(nodeRoutingId, candidates);
|
|
1105
|
-
}
|
|
1106
|
-
candidates.set(connectionId, candidate);
|
|
1107
|
-
this.connectionIds.set(nodeRoutingId, connectionId);
|
|
1108
|
-
}
|
|
1109
|
-
return candidate;
|
|
1110
|
-
}
|
|
1111
|
-
createConnectionCandidate(nodeRoutingId, event) {
|
|
1112
|
-
const local = this.topology.localDescriptor();
|
|
1113
|
-
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1114
|
-
const direction = event.localAddress === local.advertisedEndpoint
|
|
1115
|
-
? 'inbound'
|
|
1116
|
-
: expected?.endpoint === event.remoteAddress
|
|
1117
|
-
? 'outbound'
|
|
1118
|
-
: this.endpointOnlyPeers.has(event.remoteAddress)
|
|
1119
|
-
? 'outbound'
|
|
1120
|
-
: 'unknown';
|
|
1121
|
-
const initiator = direction === 'outbound'
|
|
1122
|
-
? local.nodeRoutingId
|
|
1123
|
-
: direction === 'inbound'
|
|
1124
|
-
? nodeRoutingId
|
|
1125
|
-
: undefined;
|
|
1126
|
-
return {
|
|
1127
|
-
connectionId: monitorConnectionId(event, nodeRoutingId),
|
|
1128
|
-
direction,
|
|
1129
|
-
discriminator: initiator === undefined
|
|
1130
|
-
? `unknown:${monitorConnectionId(event, nodeRoutingId)}`
|
|
1131
|
-
: `initiator:${initiator}`,
|
|
1132
|
-
localAddress: event.localAddress,
|
|
1133
|
-
remoteAddress: event.remoteAddress
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
|
-
createUnresolvedConnectionCandidate(event) {
|
|
1137
|
-
const connectionId = monitorConnectionId(event);
|
|
1138
|
-
const local = this.topology.localDescriptor();
|
|
1139
|
-
const direction = this.endpointOnlyPeers.has(event.remoteAddress) ||
|
|
1140
|
-
this.expectedPeerRoutingId(event.remoteAddress) !== undefined
|
|
1141
|
-
? 'outbound'
|
|
1142
|
-
: event.localAddress === local.advertisedEndpoint
|
|
1143
|
-
? 'inbound'
|
|
1144
|
-
: 'unknown';
|
|
1145
|
-
return {
|
|
1146
|
-
connectionId,
|
|
1147
|
-
direction,
|
|
1148
|
-
discriminator: `unresolved:${connectionId}`,
|
|
1149
|
-
localAddress: event.localAddress,
|
|
1150
|
-
remoteAddress: event.remoteAddress
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
promoteUnresolvedConnectionCandidate(nodeRoutingId, advertisedEndpoint) {
|
|
1154
|
-
const relevant = this.unresolvedConnectionCandidates
|
|
1155
|
-
.map((candidate, index) => ({ candidate, index }))
|
|
1156
|
-
.filter(({ candidate }) => candidate.remoteAddress === advertisedEndpoint || candidate.direction === 'inbound');
|
|
1157
|
-
if (relevant.length === 0)
|
|
1158
|
-
return undefined;
|
|
1159
|
-
const directions = new Set(relevant.map((value) => value.candidate.direction));
|
|
1160
|
-
const localRid = this.topology.localDescriptor().nodeRoutingId;
|
|
1161
|
-
const preferredDirection = directions.has('inbound') && directions.has('outbound')
|
|
1162
|
-
? localRid.localeCompare(nodeRoutingId) <= 0
|
|
1163
|
-
? 'outbound'
|
|
1164
|
-
: 'inbound'
|
|
1165
|
-
: relevant.at(-1).candidate.direction;
|
|
1166
|
-
const selected = [...relevant].reverse().find((value) => value.candidate.direction === preferredDirection) ??
|
|
1167
|
-
relevant.at(-1);
|
|
1168
|
-
this.unresolvedConnectionCandidates.splice(selected.index, 1);
|
|
1169
|
-
const initiator = selected.candidate.direction === 'outbound'
|
|
1170
|
-
? localRid
|
|
1171
|
-
: selected.candidate.direction === 'inbound'
|
|
1172
|
-
? nodeRoutingId
|
|
1173
|
-
: undefined;
|
|
1174
|
-
const candidate = {
|
|
1175
|
-
...selected.candidate,
|
|
1176
|
-
discriminator: initiator === undefined
|
|
1177
|
-
? `unknown:${selected.candidate.connectionId}`
|
|
1178
|
-
: `initiator:${initiator}`
|
|
1179
|
-
};
|
|
1180
|
-
let candidates = this.connectionCandidates.get(nodeRoutingId);
|
|
1181
|
-
if (candidates === undefined) {
|
|
1182
|
-
candidates = new Map();
|
|
1183
|
-
this.connectionCandidates.set(nodeRoutingId, candidates);
|
|
1184
|
-
}
|
|
1185
|
-
candidates.set(candidate.connectionId, candidate);
|
|
1186
|
-
this.connectionIds.set(nodeRoutingId, candidate.connectionId);
|
|
1187
|
-
return candidate;
|
|
1188
|
-
}
|
|
1189
|
-
removeConnectionCandidate(nodeRoutingId, connectionId) {
|
|
1190
|
-
const candidates = this.connectionCandidates.get(nodeRoutingId);
|
|
1191
|
-
candidates?.delete(connectionId);
|
|
1192
|
-
if (candidates?.size === 0)
|
|
1193
|
-
this.connectionCandidates.delete(nodeRoutingId);
|
|
1194
|
-
if (this.connectionIds.get(nodeRoutingId) === connectionId) {
|
|
1195
|
-
this.connectionIds.delete(nodeRoutingId);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
isDiscoveredLifecycleReplacement(admitted, nodeRoutingId) {
|
|
1199
|
-
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1200
|
-
// A same-RID replacement is permitted only from a complete discovery
|
|
1201
|
-
// fence. Manual/endpoint-only intent has no authority to replace a ready
|
|
1202
|
-
// peer, and lifecycle generations are opaque equality tokens.
|
|
1203
|
-
return (expected?.endpoint !== undefined &&
|
|
1204
|
-
expected.securityIdentity !== undefined &&
|
|
1205
|
-
expected.lifecycleGeneration !== undefined &&
|
|
1206
|
-
admitted.descriptor.lifecycleGeneration !== expected.lifecycleGeneration);
|
|
1207
|
-
}
|
|
1208
|
-
expectedPeerRoutingId(endpoint) {
|
|
1209
|
-
for (const [nodeRoutingId, expected] of this.expectedPeers) {
|
|
1210
|
-
if (expected.endpoint === endpoint)
|
|
1211
|
-
return nodeRoutingId;
|
|
1212
|
-
}
|
|
1213
|
-
return undefined;
|
|
1214
|
-
}
|
|
1215
|
-
acceptsExpectedMonitorEndpoint(nodeRoutingId, event) {
|
|
1216
|
-
// A monitor address is the physical socket address, which may be an
|
|
1217
|
-
// ephemeral port. Once Core has resolved the peer routing ID, that ID is
|
|
1218
|
-
// the semantic identity; comparing the physical address with the
|
|
1219
|
-
// discovery advertised endpoint would reject valid READY events.
|
|
1220
|
-
if (event.routingId === nodeRoutingId)
|
|
1221
|
-
return true;
|
|
1222
|
-
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1223
|
-
return (expected === undefined ||
|
|
1224
|
-
expected.endpoint === undefined ||
|
|
1225
|
-
expected.endpoint === event.remoteAddress);
|
|
1226
|
-
}
|
|
1227
938
|
retireNotRequiredExpectedPeer(nodeRoutingId, advertisedEndpoint) {
|
|
1228
939
|
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1229
940
|
const endpoint = expected?.endpoint ??
|
|
@@ -1254,31 +965,10 @@ class RawServiceMeshRuntime {
|
|
|
1254
965
|
this.endpointOnlyPeers.delete(endpoint);
|
|
1255
966
|
}
|
|
1256
967
|
removePeer(peer) {
|
|
1257
|
-
if (this.monitorConnectionStates.get(peer.descriptor.nodeRoutingId) === peer.connectionId) {
|
|
1258
|
-
this.monitorConnectionStates.set(peer.descriptor.nodeRoutingId, null);
|
|
1259
|
-
}
|
|
1260
968
|
this.topology.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
1261
969
|
this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
1262
970
|
this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
|
|
1263
971
|
}
|
|
1264
|
-
observeMonitorEvent(event) {
|
|
1265
|
-
const nodeRoutingId = event.routingId ?? this.expectedPeerRoutingId(event.remoteAddress);
|
|
1266
|
-
if (nodeRoutingId === undefined)
|
|
1267
|
-
return;
|
|
1268
|
-
const connectionId = monitorConnectionId(event, nodeRoutingId);
|
|
1269
|
-
if (event.event === MONITOR_CONNECTION_READY && isConnectionReadyEdge(event)) {
|
|
1270
|
-
if (!this.acceptsExpectedMonitorEndpoint(nodeRoutingId, event))
|
|
1271
|
-
return;
|
|
1272
|
-
// The event is queued for admission. Updating monitor state here would
|
|
1273
|
-
// allow a late stale READY to overwrite the admitted replacement.
|
|
1274
|
-
return;
|
|
1275
|
-
}
|
|
1276
|
-
if (event.event === MONITOR_DISCONNECTED &&
|
|
1277
|
-
this.monitorConnectionStates.get(nodeRoutingId) === connectionId &&
|
|
1278
|
-
this.topology.peer(nodeRoutingId)?.connectionId === connectionId) {
|
|
1279
|
-
this.monitorConnectionStates.set(nodeRoutingId, null);
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
972
|
requireStarted() {
|
|
1283
973
|
if (this.router === undefined)
|
|
1284
974
|
throw new Error('Raw service runtime is not started.');
|
|
@@ -1331,28 +1021,12 @@ function isAlreadyDisconnectedError(error) {
|
|
|
1331
1021
|
}
|
|
1332
1022
|
return error.nativeErrno === 2;
|
|
1333
1023
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
// socket's ready count and DISCONNECTED reports its reason. It is not a
|
|
1341
|
-
// connection identity. The public monitor record has no native
|
|
1342
|
-
// connection id, so use the stable routing and endpoint tuple instead.
|
|
1343
|
-
resolvedNodeRoutingId,
|
|
1344
|
-
event.localAddress,
|
|
1345
|
-
event.remoteAddress
|
|
1346
|
-
]);
|
|
1347
|
-
}
|
|
1348
|
-
function sameMonitorConnection(left, right) {
|
|
1349
|
-
return (monitorConnectionId(left) === monitorConnectionId(right) &&
|
|
1350
|
-
left.remoteAddress === right.remoteAddress);
|
|
1351
|
-
}
|
|
1352
|
-
function isConnectionReadyEdge(event) {
|
|
1353
|
-
return event.flags === undefined
|
|
1354
|
-
? event.value > 0n
|
|
1355
|
-
: (event.flags & MONITOR_CONNECTION_READY_EDGE) !== 0;
|
|
1024
|
+
/**
|
|
1025
|
+
* An admission belongs to one Core selected route. Its connection identity is
|
|
1026
|
+
* that route's generation, an opaque token compared only for equality.
|
|
1027
|
+
*/
|
|
1028
|
+
function routeConnectionId(routeGeneration) {
|
|
1029
|
+
return `route:${routeGeneration.toString()}`;
|
|
1356
1030
|
}
|
|
1357
1031
|
function describeInvalidAdmissionDescriptor(descriptor, expected, current) {
|
|
1358
1032
|
try {
|
|
@@ -47,6 +47,7 @@ export declare function replaceServiceAuthorityRelocationState(payload: Uint8Arr
|
|
|
47
47
|
export declare function encodeServiceUserSpotAuthorityPayload(value: ServiceUserSpotAuthorityPayload): Buffer;
|
|
48
48
|
export declare function encodeServiceInstanceAuthorityPayload(value: ServiceInstanceAuthorityPayload): Buffer;
|
|
49
49
|
export declare function decodeServiceReadySpotAuthority(payload: Uint8Array): ServiceReadySpotAuthority | undefined;
|
|
50
|
+
export declare function decodeServiceClosingSpotAuthority(payload: Uint8Array): ServiceReadySpotAuthority | undefined;
|
|
50
51
|
export declare function decodeServiceInstanceAuthorityPayload(payload: Uint8Array): ServiceDecodedInstanceAuthority | undefined;
|
|
51
52
|
export declare function rewriteServiceAuthorityOwner(payload: Uint8Array, owner: ZLinkLocationOwnerToken): Buffer | undefined;
|
|
52
53
|
export declare function rewriteServiceAuthorityRoute(payload: Uint8Array, owner: ZLinkLocationOwnerToken, target: {
|
|
@@ -4,6 +4,7 @@ exports.replaceServiceAuthorityRelocationState = replaceServiceAuthorityRelocati
|
|
|
4
4
|
exports.encodeServiceUserSpotAuthorityPayload = encodeServiceUserSpotAuthorityPayload;
|
|
5
5
|
exports.encodeServiceInstanceAuthorityPayload = encodeServiceInstanceAuthorityPayload;
|
|
6
6
|
exports.decodeServiceReadySpotAuthority = decodeServiceReadySpotAuthority;
|
|
7
|
+
exports.decodeServiceClosingSpotAuthority = decodeServiceClosingSpotAuthority;
|
|
7
8
|
exports.decodeServiceInstanceAuthorityPayload = decodeServiceInstanceAuthorityPayload;
|
|
8
9
|
exports.rewriteServiceAuthorityOwner = rewriteServiceAuthorityOwner;
|
|
9
10
|
exports.rewriteServiceAuthorityRoute = rewriteServiceAuthorityRoute;
|
|
@@ -84,6 +85,13 @@ function decodeServiceReadySpotAuthority(payload) {
|
|
|
84
85
|
const decoded = decodeSpotAuthority(payload);
|
|
85
86
|
return decoded?.state === 'ready' && decoded.operationKind === 0 ? decoded : undefined;
|
|
86
87
|
}
|
|
88
|
+
function decodeServiceClosingSpotAuthority(payload) {
|
|
89
|
+
const decoded = decodeSpotAuthority(payload);
|
|
90
|
+
return decoded?.operationKind === 3 &&
|
|
91
|
+
(decoded.kind === 'user_spot' || decoded.state === 'closing')
|
|
92
|
+
? decoded
|
|
93
|
+
: undefined;
|
|
94
|
+
}
|
|
87
95
|
function decodeServiceInstanceAuthorityPayload(payload) {
|
|
88
96
|
const decoded = decodeSpotAuthority(payload);
|
|
89
97
|
if (decoded?.kind !== 'instance_spot' ||
|