@zlink-systems/framework 0.29.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +1 -2
- package/dist/contracts/Configuration/Configs.d.ts +0 -5
- package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
- package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
- package/dist/contracts/Configuration/index.d.ts +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/runtime/actors/actor-handoff.d.ts +3 -2
- package/dist/runtime/actors/actor-handoff.js +9 -4
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +3 -1
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +6 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +3 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.js +5 -0
- package/dist/runtime/application-jobs/contracts.d.ts +5 -1
- package/dist/runtime/backend/contracts/index.d.ts +10 -19
- package/dist/runtime/backend/mesh-completion-table.d.ts +6 -4
- package/dist/runtime/backend/mesh-completion-table.js +28 -18
- package/dist/runtime/backend/mesh-dispatch-pump.js +21 -25
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +24 -29
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -6
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +10 -12
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +64 -98
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +10 -5
- package/dist/runtime/backend/raw-binding-port.d.ts +9 -2
- package/dist/runtime/channels/channel-receive-loops.js +3 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
- package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
- package/dist/runtime/channels/channel-socket-registry.js +59 -82
- package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow.js +3 -3
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +15 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +193 -64
- package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
- package/dist/runtime/foundation/service-liveness-registry.js +57 -44
- package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
- package/dist/runtime/foundation/service-mailbox.js +2 -1
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +7 -6
- package/dist/runtime/foundation/service-stateful-runtime.js +34 -23
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -2
- package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
- package/dist/runtime/foundation/service-topology-registry.d.ts +5 -3
- package/dist/runtime/foundation/service-topology-registry.js +9 -4
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-runtime-options-factory.js +1 -1
- package/dist/runtime/host/application-job-queue.d.ts +11 -4
- package/dist/runtime/host/application-job-queue.js +66 -10
- package/dist/runtime/host/entry-actor-runtime.js +1 -1
- package/dist/runtime/host/index.js +15 -11
- package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
- package/dist/runtime/host/instance-activation-authority.js +89 -25
- package/dist/runtime/host/service-relocation-host-runtime.js +2 -2
- package/dist/runtime/host/spot-address-transport.d.ts +1 -0
- package/dist/runtime/host/spot-address-transport.js +25 -12
- package/dist/runtime/host/spot-runtime-options-factory.js +2 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
- package/dist/runtime/locations/domain-store-contract.d.ts +2 -2
- package/dist/runtime/locations/in-memory-authority-store.d.ts +4 -2
- package/dist/runtime/locations/in-memory-authority-store.js +80 -8
- package/dist/runtime/locations/in-memory-location-store.d.ts +2 -2
- package/dist/runtime/locations/in-memory-location-store.js +19 -3
- package/dist/runtime/locations/internal-location-contracts.d.ts +3 -0
- package/dist/runtime/locations/location-store-repository.d.ts +3 -2
- package/dist/runtime/locations/location-store-repository.js +165 -22
- package/dist/runtime/locations/resolvers.d.ts +2 -1
- package/dist/runtime/locations/resolvers.js +10 -1
- package/dist/runtime/messaging/submission-result.d.ts +1 -1
- package/dist/runtime/messaging/submission-result.js +2 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +2 -0
- package/dist/runtime/spots/index.d.ts +4 -3
- package/dist/runtime/spots/index.js +14 -14
- package/dist/runtime/spots/spot-activation.d.ts +2 -1
- package/dist/runtime/spots/spot-activation.js +4 -4
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
- package/dist/runtime/spots/spot-entry-activation.js +3 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +2 -1
- package/dist/runtime/spots/spot-node-runtime-manager.js +4 -11
- package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
- package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -1
- package/dist/runtime/streams/stream-session-runtime.js +1 -1
- package/package.json +3 -3
- package/src/contracts/Configuration/Builders.ts +1 -2
- package/src/contracts/Configuration/Configs.ts +0 -6
- package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
- package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
- package/src/contracts/Configuration/index.ts +1 -6
- package/src/internal.ts +1 -0
- package/src/runtime/actors/actor-handoff.ts +13 -4
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +12 -2
- package/src/runtime/application-jobs/application-job-queue-scope.ts +6 -1
- package/src/runtime/application-jobs/contracts.ts +14 -1
- package/src/runtime/backend/contracts/index.ts +10 -18
- package/src/runtime/backend/mesh-completion-table.ts +36 -19
- package/src/runtime/backend/mesh-dispatch-pump.ts +19 -22
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
- package/src/runtime/backend/node/node-backend-adapter-support.ts +31 -29
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
- package/src/runtime/backend/node/node-raw-binding-port.ts +19 -10
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +81 -111
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +12 -8
- package/src/runtime/backend/raw-binding-port.ts +12 -2
- package/src/runtime/channels/channel-receive-loops.ts +3 -3
- package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
- package/src/runtime/channels/channel-socket-registry.ts +84 -130
- package/src/runtime/diagnostics/message-flow.ts +1 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +268 -70
- package/src/runtime/foundation/service-liveness-registry.ts +68 -59
- package/src/runtime/foundation/service-mailbox.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +61 -35
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
- package/src/runtime/foundation/service-topology-registry.ts +13 -7
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-runtime-options-factory.ts +1 -0
- package/src/runtime/host/application-job-queue.ts +77 -10
- package/src/runtime/host/entry-actor-runtime.ts +1 -0
- package/src/runtime/host/index.ts +24 -5
- package/src/runtime/host/instance-activation-authority.ts +132 -27
- package/src/runtime/host/service-relocation-host-runtime.ts +2 -0
- package/src/runtime/host/spot-address-transport.ts +45 -22
- package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
- package/src/runtime/locations/domain-store-contract.ts +6 -2
- package/src/runtime/locations/in-memory-authority-store.ts +113 -9
- package/src/runtime/locations/in-memory-location-store.ts +25 -3
- package/src/runtime/locations/internal-location-contracts.ts +4 -0
- package/src/runtime/locations/location-store-repository.ts +220 -15
- package/src/runtime/locations/resolvers.ts +25 -2
- package/src/runtime/messaging/submission-result.ts +2 -2
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +2 -0
- package/src/runtime/spots/index.ts +16 -0
- package/src/runtime/spots/spot-activation.ts +5 -0
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
- package/src/runtime/spots/spot-entry-activation.ts +3 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +2 -0
- package/src/runtime/streams/stream-session-runtime.ts +1 -1
|
@@ -46,6 +46,12 @@ class RawServiceMeshRuntime {
|
|
|
46
46
|
applicationJobQueue;
|
|
47
47
|
peerAdmissionSealed;
|
|
48
48
|
applicationJobStop = new AbortController();
|
|
49
|
+
receiveAcquisition;
|
|
50
|
+
receivePermit;
|
|
51
|
+
controlSends = new Map();
|
|
52
|
+
infrastructureFailure;
|
|
53
|
+
onReceiveReady;
|
|
54
|
+
infrastructureTaskRunner;
|
|
49
55
|
onPeerNotRequired;
|
|
50
56
|
onPeerDisconnected;
|
|
51
57
|
onProtocolError;
|
|
@@ -58,6 +64,8 @@ class RawServiceMeshRuntime {
|
|
|
58
64
|
serviceIngress;
|
|
59
65
|
closed = false;
|
|
60
66
|
constructor(options) {
|
|
67
|
+
this.onReceiveReady = options.onReceiveReady;
|
|
68
|
+
this.infrastructureTaskRunner = options.infrastructureTaskRunner;
|
|
61
69
|
this.operations = new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged);
|
|
62
70
|
this.descriptor = options.descriptor;
|
|
63
71
|
this.topology = new service_topology_registry_1.ServiceTopologyRegistry(options.descriptor);
|
|
@@ -222,22 +230,22 @@ class RawServiceMeshRuntime {
|
|
|
222
230
|
for (const listener of this.peerConnectionIntentRemoved)
|
|
223
231
|
listener(nodeRoutingId);
|
|
224
232
|
}
|
|
225
|
-
|
|
233
|
+
announcePeer(nodeRoutingId) {
|
|
226
234
|
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
227
235
|
const generation = this.selectedRoutes.get(nodeRoutingId);
|
|
228
236
|
if (expected === undefined ||
|
|
229
237
|
generation === undefined ||
|
|
230
238
|
expected.helloSubmittedGeneration === generation ||
|
|
231
239
|
this.peerAdmissionSealed?.() === true)
|
|
232
|
-
return false;
|
|
233
|
-
const
|
|
240
|
+
return Promise.resolve(false);
|
|
241
|
+
const current = () => this.expectedPeers.get(nodeRoutingId) === expected &&
|
|
242
|
+
this.selectedRoutes.get(nodeRoutingId) === generation;
|
|
243
|
+
return Promise.resolve(this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [
|
|
234
244
|
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
|
|
235
|
-
])
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
expected.helloSubmittedGeneration = generation;
|
|
240
|
-
return accepted;
|
|
245
|
+
], () => {
|
|
246
|
+
if (current())
|
|
247
|
+
expected.helloSubmittedGeneration = generation;
|
|
248
|
+
}), current));
|
|
241
249
|
}
|
|
242
250
|
isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
|
|
243
251
|
// Admission is bound to the observed selected route: the route observer
|
|
@@ -245,8 +253,7 @@ class RawServiceMeshRuntime {
|
|
|
245
253
|
const peer = this.topology.peer(nodeRoutingId);
|
|
246
254
|
return (peer !== undefined &&
|
|
247
255
|
(lifecycleGeneration === undefined ||
|
|
248
|
-
peer.descriptor.lifecycleGeneration === lifecycleGeneration)
|
|
249
|
-
this.liveness.isReady(nodeRoutingId, peer.connectionId));
|
|
256
|
+
peer.descriptor.lifecycleGeneration === lifecycleGeneration));
|
|
250
257
|
}
|
|
251
258
|
async announceExpectedPeers() {
|
|
252
259
|
let accepted = 0;
|
|
@@ -351,14 +358,15 @@ class RawServiceMeshRuntime {
|
|
|
351
358
|
const waitSignal = signal === undefined
|
|
352
359
|
? this.applicationJobStop.signal
|
|
353
360
|
: AbortSignal.any([this.applicationJobStop.signal, signal]);
|
|
354
|
-
const permit = await this.applicationJobQueue.acquire(waitSignal);
|
|
361
|
+
const permit = await this.applicationJobQueue.acquire(waitSignal, 'local');
|
|
355
362
|
return application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, { close() { } });
|
|
356
363
|
}
|
|
357
364
|
async sendService(targetNodeRoutingId, parts) {
|
|
358
365
|
return this.send(targetNodeRoutingId, parts);
|
|
359
366
|
}
|
|
360
367
|
requestService(targetNodeRoutingId, parts, timeoutMs) {
|
|
361
|
-
|
|
368
|
+
const admission = this.topology.peer(targetNodeRoutingId)?.liveness;
|
|
369
|
+
return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived);
|
|
362
370
|
}
|
|
363
371
|
replyService(record, parts) {
|
|
364
372
|
if (record.requestSequence === undefined) {
|
|
@@ -383,6 +391,22 @@ class RawServiceMeshRuntime {
|
|
|
383
391
|
]);
|
|
384
392
|
}
|
|
385
393
|
async pumpOne(nowMs = performance.now(), observe) {
|
|
394
|
+
const result = await this.receiveOne(nowMs, observe);
|
|
395
|
+
const acquisition = this.receiveAcquisition;
|
|
396
|
+
if (acquisition === undefined)
|
|
397
|
+
return result;
|
|
398
|
+
// A single receive operation may await its FIFO grant. Infrastructure
|
|
399
|
+
// rounds use receiveOne directly and end while that grant is pending.
|
|
400
|
+
try {
|
|
401
|
+
await acquisition;
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
if (this.closed)
|
|
405
|
+
return 'noData';
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
if (this.closed)
|
|
409
|
+
return 'noData';
|
|
386
410
|
return this.receiveOne(nowMs, observe);
|
|
387
411
|
}
|
|
388
412
|
setReadableHandler(handler) {
|
|
@@ -390,6 +414,7 @@ class RawServiceMeshRuntime {
|
|
|
390
414
|
}
|
|
391
415
|
/** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
|
|
392
416
|
async pumpBatch(receiveReady = true, routeReady = false) {
|
|
417
|
+
this.observeInfrastructureFailure();
|
|
393
418
|
if (routeReady)
|
|
394
419
|
await this.observeSelectedRoutes();
|
|
395
420
|
const startedAtMs = performance.now();
|
|
@@ -412,22 +437,49 @@ class RawServiceMeshRuntime {
|
|
|
412
437
|
break;
|
|
413
438
|
}
|
|
414
439
|
if (!this.closed) {
|
|
415
|
-
|
|
416
|
-
|
|
440
|
+
for (const nodeRoutingId of this.expectedPeers.keys()) {
|
|
441
|
+
if (this.topology.peer(nodeRoutingId) === undefined)
|
|
442
|
+
await this.announcePeer(nodeRoutingId);
|
|
443
|
+
}
|
|
444
|
+
this.tickLiveness();
|
|
417
445
|
}
|
|
418
446
|
return receiveReady && messages > 0;
|
|
419
447
|
}
|
|
420
448
|
async receiveOne(nowMs, observe) {
|
|
421
449
|
const router = this.requireStarted();
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
450
|
+
this.observeInfrastructureFailure();
|
|
451
|
+
if (this.receivePermit === undefined && this.receiveAcquisition === undefined) {
|
|
452
|
+
let resolveAcquisition;
|
|
453
|
+
let rejectAcquisition;
|
|
454
|
+
const acquisition = new Promise((resolve, reject) => {
|
|
455
|
+
resolveAcquisition = resolve;
|
|
456
|
+
rejectAcquisition = reject;
|
|
457
|
+
});
|
|
458
|
+
const permit = this.applicationJobQueue.acquireOrResume((permit) => {
|
|
459
|
+
this.receiveAcquisition = undefined;
|
|
460
|
+
if (this.closed)
|
|
461
|
+
permit.releaseAfterInternalProcessing();
|
|
462
|
+
else {
|
|
463
|
+
this.receivePermit = permit;
|
|
464
|
+
this.onReceiveReady?.();
|
|
465
|
+
}
|
|
466
|
+
resolveAcquisition(permit);
|
|
467
|
+
}, rejectAcquisition, this.applicationJobStop.signal, 'remote');
|
|
468
|
+
if (permit !== undefined)
|
|
469
|
+
this.receivePermit = permit;
|
|
470
|
+
else {
|
|
471
|
+
this.receiveAcquisition = acquisition;
|
|
472
|
+
acquisition.catch((error) => {
|
|
473
|
+
this.receiveAcquisition = undefined;
|
|
474
|
+
if (!this.applicationJobStop.signal.aborted)
|
|
475
|
+
this.reportInfrastructureFailure(error);
|
|
476
|
+
});
|
|
477
|
+
}
|
|
430
478
|
}
|
|
479
|
+
const permit = this.receivePermit;
|
|
480
|
+
this.receivePermit = undefined;
|
|
481
|
+
if (permit === undefined)
|
|
482
|
+
return 'noData';
|
|
431
483
|
if (this.closed) {
|
|
432
484
|
permit.releaseAfterInternalProcessing();
|
|
433
485
|
return 'noData';
|
|
@@ -498,7 +550,7 @@ class RawServiceMeshRuntime {
|
|
|
498
550
|
(received.parts.length === 1 && received.parts[0].byteLength === 0)) {
|
|
499
551
|
if (this.peerAdmissionSealed?.() === true)
|
|
500
552
|
return 'dropped';
|
|
501
|
-
return (await this.
|
|
553
|
+
return (await this.sendControl(received.sourceRid, [
|
|
502
554
|
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
|
|
503
555
|
]))
|
|
504
556
|
? 'infrastructure'
|
|
@@ -519,19 +571,19 @@ class RawServiceMeshRuntime {
|
|
|
519
571
|
if (expected !== undefined &&
|
|
520
572
|
(expected.meshName !== descriptor.meshName ||
|
|
521
573
|
expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
|
|
522
|
-
await this.
|
|
574
|
+
await this.sendControl(received.sourceRid, [
|
|
523
575
|
(0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
|
|
524
576
|
]);
|
|
525
577
|
return 'infrastructure';
|
|
526
578
|
}
|
|
527
|
-
const result = this.admitPeer(descriptor,
|
|
579
|
+
const result = this.admitPeer(descriptor, received.routeGeneration, nowMs, expected);
|
|
528
580
|
if (result !== 'admitted' && result !== 'notRequired') {
|
|
529
581
|
const detail = result === 'invalidDescriptor'
|
|
530
582
|
? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
|
|
531
583
|
: undefined;
|
|
532
584
|
console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
|
|
533
585
|
(detail === undefined ? '.' : ` (${detail}).`));
|
|
534
|
-
await this.
|
|
586
|
+
await this.sendControl(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
|
|
535
587
|
return 'infrastructure';
|
|
536
588
|
}
|
|
537
589
|
if (result === 'admitted')
|
|
@@ -540,7 +592,7 @@ class RawServiceMeshRuntime {
|
|
|
540
592
|
// Hello supplies only the sender's descriptor. Even NotRequired
|
|
541
593
|
// peers must receive ours before the intent owner closes transport;
|
|
542
594
|
// submitting a response does not guarantee delivery before close.
|
|
543
|
-
await this.
|
|
595
|
+
await this.sendControl(received.sourceRid, [
|
|
544
596
|
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, this.topology.localDescriptor())
|
|
545
597
|
]);
|
|
546
598
|
}
|
|
@@ -558,16 +610,18 @@ class RawServiceMeshRuntime {
|
|
|
558
610
|
const peer = this.topology.peer(received.sourceRid);
|
|
559
611
|
if (peer === undefined)
|
|
560
612
|
return 'protocolError';
|
|
613
|
+
if (peer.liveness !== undefined && peer.liveness.connectionId === received.routeGeneration)
|
|
614
|
+
this.liveness.recordReceived(peer.liveness, nowMs);
|
|
561
615
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe ||
|
|
562
616
|
header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck) {
|
|
563
617
|
if (received.parts.length !== 1)
|
|
564
618
|
return 'protocolError';
|
|
565
619
|
const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
|
|
566
620
|
if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
|
|
567
|
-
const ack = this.liveness.acknowledgeProbe(received.sourceRid,
|
|
621
|
+
const ack = this.liveness.acknowledgeProbe(received.sourceRid, received.routeGeneration, record.probeId);
|
|
568
622
|
if (ack === undefined)
|
|
569
623
|
return 'protocolError';
|
|
570
|
-
const sent = await this.
|
|
624
|
+
const sent = await this.sendControl(received.sourceRid, [
|
|
571
625
|
livenessCodec.encodeLivenessRecord({
|
|
572
626
|
command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
|
|
573
627
|
probeId: record.probeId
|
|
@@ -577,7 +631,7 @@ class RawServiceMeshRuntime {
|
|
|
577
631
|
return 'dropped';
|
|
578
632
|
}
|
|
579
633
|
else {
|
|
580
|
-
this.liveness.acknowledge(received.sourceRid,
|
|
634
|
+
this.liveness.acknowledge(received.sourceRid, received.routeGeneration, record.probeId, nowMs);
|
|
581
635
|
}
|
|
582
636
|
return 'infrastructure';
|
|
583
637
|
}
|
|
@@ -684,22 +738,23 @@ class RawServiceMeshRuntime {
|
|
|
684
738
|
get pendingOperationCount() {
|
|
685
739
|
return this.operations.size;
|
|
686
740
|
}
|
|
687
|
-
|
|
741
|
+
tickLiveness(nowMs = performance.now()) {
|
|
688
742
|
const result = this.liveness.tick(nowMs);
|
|
689
743
|
this.requireStarted();
|
|
690
744
|
for (const probe of result.probes) {
|
|
691
|
-
|
|
745
|
+
const parts = [
|
|
692
746
|
livenessCodec.encodeLivenessRecord({
|
|
693
747
|
command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe,
|
|
694
748
|
probeId: probe.probeId
|
|
695
749
|
})
|
|
696
|
-
]
|
|
750
|
+
];
|
|
751
|
+
this.startControlSend(probe.nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe, () => this.submitControl(probe.nodeRoutingId, parts));
|
|
697
752
|
}
|
|
698
753
|
for (const nodeRoutingId of result.timedOutNodes) {
|
|
699
754
|
const peer = this.topology.peer(nodeRoutingId);
|
|
700
755
|
if (peer === undefined)
|
|
701
756
|
continue;
|
|
702
|
-
|
|
757
|
+
this.requireStarted().disconnectRid(nodeRoutingId);
|
|
703
758
|
this.removePeer(peer);
|
|
704
759
|
}
|
|
705
760
|
return result;
|
|
@@ -727,7 +782,7 @@ class RawServiceMeshRuntime {
|
|
|
727
782
|
if (expected !== undefined)
|
|
728
783
|
delete expected.helloSubmittedGeneration;
|
|
729
784
|
const peer = this.topology.peer(nodeRoutingId);
|
|
730
|
-
if (peer
|
|
785
|
+
if (peer?.liveness?.connectionId === generation) {
|
|
731
786
|
this.removePeer(peer);
|
|
732
787
|
}
|
|
733
788
|
}
|
|
@@ -748,7 +803,12 @@ class RawServiceMeshRuntime {
|
|
|
748
803
|
close() {
|
|
749
804
|
if (this.closed)
|
|
750
805
|
return;
|
|
806
|
+
this.closed = true;
|
|
751
807
|
this.applicationJobStop.abort(new Error('Raw service runtime application job admission stopped.'));
|
|
808
|
+
this.receivePermit?.releaseAfterInternalProcessing();
|
|
809
|
+
this.receivePermit = undefined;
|
|
810
|
+
for (const send of this.controlSends.values())
|
|
811
|
+
delete send.next;
|
|
752
812
|
this.mailbox.close();
|
|
753
813
|
this.operations.close('Raw service runtime closed.');
|
|
754
814
|
this.serviceIngress = undefined;
|
|
@@ -761,7 +821,6 @@ class RawServiceMeshRuntime {
|
|
|
761
821
|
host.close();
|
|
762
822
|
this.router = undefined;
|
|
763
823
|
this.host = undefined;
|
|
764
|
-
this.closed = true;
|
|
765
824
|
}
|
|
766
825
|
requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName) {
|
|
767
826
|
const correlation = this.nextCorrelation++;
|
|
@@ -836,7 +895,8 @@ class RawServiceMeshRuntime {
|
|
|
836
895
|
})().catch((error) => this.operations.fail(pending.id, error));
|
|
837
896
|
return pending;
|
|
838
897
|
}
|
|
839
|
-
|
|
898
|
+
const selectedPeer = this.topology.peer(selectedTargetNodeRoutingId);
|
|
899
|
+
if (selectedPeer === undefined) {
|
|
840
900
|
// Logical target selection is the requester's decision: an RID that is
|
|
841
901
|
// not an admitted peer is not a target. Whether an admitted target's
|
|
842
902
|
// route can carry the request is Core's REQUEST result.
|
|
@@ -847,11 +907,9 @@ class RawServiceMeshRuntime {
|
|
|
847
907
|
return pending;
|
|
848
908
|
}
|
|
849
909
|
const parts = [header, encodedPayload];
|
|
850
|
-
let router;
|
|
851
910
|
let request;
|
|
852
911
|
try {
|
|
853
|
-
|
|
854
|
-
request = router.request(selectedTargetNodeRoutingId, parts, timeoutMs);
|
|
912
|
+
request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived);
|
|
855
913
|
}
|
|
856
914
|
catch (error) {
|
|
857
915
|
this.operations.fail(pending.id, error);
|
|
@@ -909,13 +967,14 @@ class RawServiceMeshRuntime {
|
|
|
909
967
|
!(0, service_topology_registry_1.sameServiceNodeDescriptor)(previous.descriptor, descriptor)))) {
|
|
910
968
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
|
|
911
969
|
}
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
915
|
-
this.liveness.
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
970
|
+
const topologyConnectionId = typeof connectionId === 'bigint' ? `route:${connectionId}` : connectionId;
|
|
971
|
+
const result = this.topology.admit(descriptor, topologyConnectionId, expected, () => {
|
|
972
|
+
const admission = this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
973
|
+
this.liveness.recordReceived(admission, nowMs);
|
|
974
|
+
return admission;
|
|
975
|
+
});
|
|
976
|
+
if (result === 'notRequired' && previous !== undefined) {
|
|
977
|
+
this.liveness.disconnect(descriptor.nodeRoutingId, previous.liveness?.connectionId ?? previous.connectionId);
|
|
919
978
|
}
|
|
920
979
|
return result;
|
|
921
980
|
}
|
|
@@ -950,7 +1009,7 @@ class RawServiceMeshRuntime {
|
|
|
950
1009
|
}
|
|
951
1010
|
removePeer(peer) {
|
|
952
1011
|
this.topology.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
953
|
-
this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
1012
|
+
this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.liveness?.connectionId ?? peer.connectionId);
|
|
954
1013
|
this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
|
|
955
1014
|
}
|
|
956
1015
|
requireStarted() {
|
|
@@ -958,19 +1017,96 @@ class RawServiceMeshRuntime {
|
|
|
958
1017
|
throw new Error('Raw service runtime is not started.');
|
|
959
1018
|
return this.router;
|
|
960
1019
|
}
|
|
961
|
-
async
|
|
1020
|
+
async sendControl(targetNodeRoutingId, parts) {
|
|
1021
|
+
return this.startControlSend(targetNodeRoutingId, (0, service_wire_m6a_codec_1.decodeHeader)(parts[0]).command, () => this.submitControl(targetNodeRoutingId, parts));
|
|
1022
|
+
}
|
|
1023
|
+
submitControl(target, parts, accepted) {
|
|
1024
|
+
let submission;
|
|
962
1025
|
try {
|
|
963
|
-
|
|
964
|
-
return true;
|
|
1026
|
+
submission = this.requireStarted().submitSend(target, parts);
|
|
965
1027
|
}
|
|
966
1028
|
catch (error) {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1029
|
+
return this.sendFailure(error);
|
|
1030
|
+
}
|
|
1031
|
+
if (submission.result === runtime_values_1.SubmitResult.Ok) {
|
|
1032
|
+
accepted?.();
|
|
1033
|
+
return true;
|
|
1034
|
+
}
|
|
1035
|
+
return submission.admitted.then(() => {
|
|
1036
|
+
accepted?.();
|
|
1037
|
+
return true;
|
|
1038
|
+
}, (error) => this.sendFailure(error));
|
|
1039
|
+
}
|
|
1040
|
+
startControlSend(target, command, attempt, current) {
|
|
1041
|
+
const key = JSON.stringify([target, command]);
|
|
1042
|
+
const existing = this.controlSends.get(key);
|
|
1043
|
+
if (existing !== undefined &&
|
|
1044
|
+
(command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello || existing.current?.() === true)) {
|
|
1045
|
+
if (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
|
|
1046
|
+
existing.next = attempt;
|
|
1047
|
+
existing.current = current;
|
|
971
1048
|
}
|
|
972
|
-
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
const first = attempt();
|
|
1052
|
+
if (typeof first === 'boolean')
|
|
1053
|
+
return first;
|
|
1054
|
+
const owner = this;
|
|
1055
|
+
const state = {
|
|
1056
|
+
current,
|
|
1057
|
+
task: first.then(function drain(accepted) {
|
|
1058
|
+
if (!owner.closed && state.next !== undefined) {
|
|
1059
|
+
const next = state.next;
|
|
1060
|
+
delete state.next;
|
|
1061
|
+
return Promise.resolve(next()).then(drain);
|
|
1062
|
+
}
|
|
1063
|
+
if (owner.controlSends.get(key) === state)
|
|
1064
|
+
owner.controlSends.delete(key);
|
|
1065
|
+
return accepted;
|
|
1066
|
+
})
|
|
1067
|
+
};
|
|
1068
|
+
this.controlSends.set(key, state);
|
|
1069
|
+
state.task.then(() => { }, (error) => {
|
|
1070
|
+
if (this.controlSends.get(key) === state)
|
|
1071
|
+
this.controlSends.delete(key);
|
|
1072
|
+
if (this.infrastructureTaskRunner === undefined)
|
|
1073
|
+
this.reportInfrastructureFailure(error);
|
|
1074
|
+
});
|
|
1075
|
+
this.infrastructureTaskRunner?.runDetached('RouteMesh control SEND', async () => {
|
|
1076
|
+
await state.task;
|
|
1077
|
+
});
|
|
1078
|
+
return true;
|
|
1079
|
+
}
|
|
1080
|
+
reportInfrastructureFailure(error) {
|
|
1081
|
+
this.infrastructureFailure = {
|
|
1082
|
+
error: this.infrastructureFailure === undefined
|
|
1083
|
+
? error
|
|
1084
|
+
: new AggregateError([this.infrastructureFailure.error, error], 'RouteMesh infrastructure failed.')
|
|
1085
|
+
};
|
|
1086
|
+
this.onReceiveReady?.();
|
|
1087
|
+
}
|
|
1088
|
+
observeInfrastructureFailure() {
|
|
1089
|
+
const failure = this.infrastructureFailure;
|
|
1090
|
+
this.infrastructureFailure = undefined;
|
|
1091
|
+
if (failure !== undefined)
|
|
1092
|
+
throw failure.error;
|
|
1093
|
+
}
|
|
1094
|
+
send(targetNodeRoutingId, parts) {
|
|
1095
|
+
return this.requireStarted()
|
|
1096
|
+
.send(targetNodeRoutingId, parts)
|
|
1097
|
+
.then(() => {
|
|
1098
|
+
return true;
|
|
1099
|
+
}, (error) => {
|
|
1100
|
+
return this.sendFailure(error);
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
sendFailure(error) {
|
|
1104
|
+
if ((0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'submit') {
|
|
1105
|
+
const terminal = (0, submission_result_1.submitToRequestResult)(error.result, error.phase);
|
|
1106
|
+
if (terminal === runtime_values_1.RequestResult.NotConnected || terminal === runtime_values_1.RequestResult.NotFound)
|
|
1107
|
+
return false;
|
|
973
1108
|
}
|
|
1109
|
+
throw error;
|
|
974
1110
|
}
|
|
975
1111
|
}
|
|
976
1112
|
exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
|
|
@@ -1010,13 +1146,6 @@ function isAlreadyDisconnectedError(error) {
|
|
|
1010
1146
|
}
|
|
1011
1147
|
return error.nativeErrno === nativeErrnoValues.ENOENT;
|
|
1012
1148
|
}
|
|
1013
|
-
/**
|
|
1014
|
-
* An admission belongs to one Core selected route. Its connection identity is
|
|
1015
|
-
* that route's generation, an opaque token compared only for equality.
|
|
1016
|
-
*/
|
|
1017
|
-
function routeConnectionId(routeGeneration) {
|
|
1018
|
-
return `route:${routeGeneration.toString()}`;
|
|
1019
|
-
}
|
|
1020
1149
|
function describeInvalidAdmissionDescriptor(descriptor, expected, current) {
|
|
1021
1150
|
try {
|
|
1022
1151
|
(0, service_topology_registry_1.validateDescriptor)(descriptor);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface ServiceProbe {
|
|
2
2
|
readonly nodeRoutingId: string;
|
|
3
|
-
readonly connectionId: string;
|
|
3
|
+
readonly connectionId: string | bigint;
|
|
4
4
|
readonly probeId: bigint;
|
|
5
5
|
}
|
|
6
6
|
export interface ServiceLivenessTick {
|
|
@@ -9,6 +9,19 @@ export interface ServiceLivenessTick {
|
|
|
9
9
|
}
|
|
10
10
|
export declare const DEFAULT_SERVICE_PROBE_INTERVAL_MS = 5000;
|
|
11
11
|
export declare const DEFAULT_SERVICE_PEER_TIMEOUT_MS = 15000;
|
|
12
|
+
export declare class ServiceLivenessConnection {
|
|
13
|
+
readonly connectionId: string | bigint;
|
|
14
|
+
private readonly probeIntervalMs;
|
|
15
|
+
private readonly peerTimeoutMs;
|
|
16
|
+
deadlineMs: number;
|
|
17
|
+
nextProbeMs: number;
|
|
18
|
+
outstandingProbe?: bigint;
|
|
19
|
+
constructor(connectionId: string | bigint, nowMs: number, probeIntervalMs?: number, peerTimeoutMs?: number);
|
|
20
|
+
readonly recordReceived: (nowMs?: number) => void;
|
|
21
|
+
isExpired(nowMs: number): boolean;
|
|
22
|
+
tryGetProbe(nowMs: number, allocateProbeId: () => bigint): bigint | undefined;
|
|
23
|
+
acknowledge(probeId: bigint, nowMs: number): boolean;
|
|
24
|
+
}
|
|
12
25
|
/** Uses monotonic milliseconds and never treats application traffic as a probe ACK. */
|
|
13
26
|
export declare class ServiceLivenessRegistry {
|
|
14
27
|
private readonly probeIntervalMs;
|
|
@@ -16,13 +29,12 @@ export declare class ServiceLivenessRegistry {
|
|
|
16
29
|
private readonly peers;
|
|
17
30
|
private nextProbeId;
|
|
18
31
|
constructor(probeIntervalMs?: number, peerTimeoutMs?: number);
|
|
19
|
-
admit(nodeRoutingId: string, connectionId: string, nowMs: number):
|
|
20
|
-
|
|
21
|
-
disconnect(nodeRoutingId: string, connectionId: string): boolean;
|
|
22
|
-
acknowledge(nodeRoutingId: string, connectionId: string, probeId: bigint, nowMs: number): boolean;
|
|
23
|
-
acknowledgeProbe(nodeRoutingId: string, connectionId: string, probeId: bigint): ServiceProbe | undefined;
|
|
32
|
+
admit(nodeRoutingId: string, connectionId: string | bigint, nowMs: number): ServiceLivenessConnection;
|
|
33
|
+
recordReceived(connection: ServiceLivenessConnection, nowMs: number): void;
|
|
34
|
+
disconnect(nodeRoutingId: string, connectionId: string | bigint): boolean;
|
|
35
|
+
acknowledge(nodeRoutingId: string, connectionId: string | bigint, probeId: bigint, nowMs: number): boolean;
|
|
36
|
+
acknowledgeProbe(nodeRoutingId: string, connectionId: string | bigint, probeId: bigint): ServiceProbe | undefined;
|
|
24
37
|
tick(nowMs: number): ServiceLivenessTick;
|
|
25
38
|
get size(): number;
|
|
26
|
-
|
|
27
|
-
private allocateProbeId;
|
|
39
|
+
private readonly allocateProbeId;
|
|
28
40
|
}
|
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ServiceLivenessRegistry = exports.DEFAULT_SERVICE_PEER_TIMEOUT_MS = exports.DEFAULT_SERVICE_PROBE_INTERVAL_MS = void 0;
|
|
3
|
+
exports.ServiceLivenessRegistry = exports.ServiceLivenessConnection = exports.DEFAULT_SERVICE_PEER_TIMEOUT_MS = exports.DEFAULT_SERVICE_PROBE_INTERVAL_MS = void 0;
|
|
4
4
|
const stream_wire_1 = require("@zlink-systems/stream-wire");
|
|
5
5
|
exports.DEFAULT_SERVICE_PROBE_INTERVAL_MS = 5_000;
|
|
6
6
|
exports.DEFAULT_SERVICE_PEER_TIMEOUT_MS = 15_000;
|
|
7
|
+
class ServiceLivenessConnection {
|
|
8
|
+
connectionId;
|
|
9
|
+
probeIntervalMs;
|
|
10
|
+
peerTimeoutMs;
|
|
11
|
+
deadlineMs;
|
|
12
|
+
nextProbeMs;
|
|
13
|
+
outstandingProbe;
|
|
14
|
+
constructor(connectionId, nowMs, probeIntervalMs = exports.DEFAULT_SERVICE_PROBE_INTERVAL_MS, peerTimeoutMs = exports.DEFAULT_SERVICE_PEER_TIMEOUT_MS) {
|
|
15
|
+
this.connectionId = connectionId;
|
|
16
|
+
this.probeIntervalMs = probeIntervalMs;
|
|
17
|
+
this.peerTimeoutMs = peerTimeoutMs;
|
|
18
|
+
this.deadlineMs = nowMs + peerTimeoutMs;
|
|
19
|
+
this.nextProbeMs = nowMs;
|
|
20
|
+
}
|
|
21
|
+
recordReceived = (nowMs = performance.now()) => {
|
|
22
|
+
this.deadlineMs = Math.max(this.deadlineMs, nowMs + this.peerTimeoutMs);
|
|
23
|
+
};
|
|
24
|
+
isExpired(nowMs) {
|
|
25
|
+
return nowMs >= this.deadlineMs;
|
|
26
|
+
}
|
|
27
|
+
tryGetProbe(nowMs, allocateProbeId) {
|
|
28
|
+
if (nowMs < this.nextProbeMs)
|
|
29
|
+
return undefined;
|
|
30
|
+
this.outstandingProbe ??= allocateProbeId();
|
|
31
|
+
do {
|
|
32
|
+
this.nextProbeMs += this.probeIntervalMs;
|
|
33
|
+
} while (this.nextProbeMs <= nowMs);
|
|
34
|
+
return this.outstandingProbe;
|
|
35
|
+
}
|
|
36
|
+
acknowledge(probeId, nowMs) {
|
|
37
|
+
this.recordReceived(nowMs);
|
|
38
|
+
if (this.outstandingProbe !== probeId)
|
|
39
|
+
return false;
|
|
40
|
+
this.outstandingProbe = undefined;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.ServiceLivenessConnection = ServiceLivenessConnection;
|
|
7
45
|
/** Uses monotonic milliseconds and never treats application traffic as a probe ACK. */
|
|
8
46
|
class ServiceLivenessRegistry {
|
|
9
47
|
probeIntervalMs;
|
|
@@ -22,26 +60,19 @@ class ServiceLivenessRegistry {
|
|
|
22
60
|
}
|
|
23
61
|
admit(nodeRoutingId, connectionId, nowMs) {
|
|
24
62
|
requireIdentity(nodeRoutingId, 'nodeRoutingId');
|
|
25
|
-
|
|
63
|
+
if (typeof connectionId === 'string')
|
|
64
|
+
requireIdentity(connectionId, 'connectionId');
|
|
65
|
+
else if (connectionId === 0n)
|
|
66
|
+
throw new TypeError('connectionId must be nonzero.');
|
|
26
67
|
const current = this.peers.get(nodeRoutingId);
|
|
27
68
|
if (current?.connectionId === connectionId)
|
|
28
|
-
return;
|
|
29
|
-
this.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
nextProbeMs: nowMs + this.probeIntervalMs,
|
|
33
|
-
ready: false
|
|
34
|
-
});
|
|
69
|
+
return current;
|
|
70
|
+
const admitted = new ServiceLivenessConnection(connectionId, nowMs, this.probeIntervalMs, this.peerTimeoutMs);
|
|
71
|
+
this.peers.set(nodeRoutingId, admitted);
|
|
72
|
+
return admitted;
|
|
35
73
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (current === undefined ||
|
|
39
|
-
current.connectionId !== connectionId ||
|
|
40
|
-
current.ready ||
|
|
41
|
-
current.outstandingProbe !== undefined)
|
|
42
|
-
return false;
|
|
43
|
-
current.nextProbeMs = Math.min(current.nextProbeMs, nowMs);
|
|
44
|
-
return true;
|
|
74
|
+
recordReceived(connection, nowMs) {
|
|
75
|
+
connection.recordReceived(nowMs);
|
|
45
76
|
}
|
|
46
77
|
disconnect(nodeRoutingId, connectionId) {
|
|
47
78
|
const current = this.peers.get(nodeRoutingId);
|
|
@@ -52,15 +83,9 @@ class ServiceLivenessRegistry {
|
|
|
52
83
|
}
|
|
53
84
|
acknowledge(nodeRoutingId, connectionId, probeId, nowMs) {
|
|
54
85
|
const current = this.peers.get(nodeRoutingId);
|
|
55
|
-
if (current === undefined ||
|
|
56
|
-
current.connectionId !== connectionId ||
|
|
57
|
-
current.outstandingProbe !== probeId) {
|
|
86
|
+
if (current === undefined || current.connectionId !== connectionId)
|
|
58
87
|
return false;
|
|
59
|
-
|
|
60
|
-
current.outstandingProbe = undefined;
|
|
61
|
-
current.deadlineMs = nowMs + this.peerTimeoutMs;
|
|
62
|
-
current.ready = true;
|
|
63
|
-
return true;
|
|
88
|
+
return current.acknowledge(probeId, nowMs);
|
|
64
89
|
}
|
|
65
90
|
acknowledgeProbe(nodeRoutingId, connectionId, probeId) {
|
|
66
91
|
const current = this.peers.get(nodeRoutingId);
|
|
@@ -73,22 +98,14 @@ class ServiceLivenessRegistry {
|
|
|
73
98
|
const probes = [];
|
|
74
99
|
const timedOutNodes = [];
|
|
75
100
|
for (const [nodeRoutingId, peer] of this.peers) {
|
|
76
|
-
if (peer.
|
|
101
|
+
if (peer.isExpired(nowMs)) {
|
|
77
102
|
timedOutNodes.push(nodeRoutingId);
|
|
78
103
|
this.peers.delete(nodeRoutingId);
|
|
79
104
|
continue;
|
|
80
105
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
probes.push({
|
|
85
|
-
nodeRoutingId,
|
|
86
|
-
connectionId: peer.connectionId,
|
|
87
|
-
probeId: peer.outstandingProbe
|
|
88
|
-
});
|
|
89
|
-
do {
|
|
90
|
-
peer.nextProbeMs += this.probeIntervalMs;
|
|
91
|
-
} while (peer.nextProbeMs <= nowMs);
|
|
106
|
+
const probeId = peer.tryGetProbe(nowMs, this.allocateProbeId);
|
|
107
|
+
if (probeId !== undefined)
|
|
108
|
+
probes.push({ nodeRoutingId, connectionId: peer.connectionId, probeId });
|
|
92
109
|
}
|
|
93
110
|
timedOutNodes.sort();
|
|
94
111
|
return { probes, timedOutNodes };
|
|
@@ -96,16 +113,12 @@ class ServiceLivenessRegistry {
|
|
|
96
113
|
get size() {
|
|
97
114
|
return this.peers.size;
|
|
98
115
|
}
|
|
99
|
-
|
|
100
|
-
const current = this.peers.get(nodeRoutingId);
|
|
101
|
-
return current?.connectionId === connectionId && current.ready;
|
|
102
|
-
}
|
|
103
|
-
allocateProbeId() {
|
|
116
|
+
allocateProbeId = () => {
|
|
104
117
|
const result = this.nextProbeId++;
|
|
105
118
|
if (this.nextProbeId > stream_wire_1.UINT64_MAX)
|
|
106
119
|
this.nextProbeId = 1n;
|
|
107
120
|
return result;
|
|
108
|
-
}
|
|
121
|
+
};
|
|
109
122
|
}
|
|
110
123
|
exports.ServiceLivenessRegistry = ServiceLivenessRegistry;
|
|
111
124
|
function requireIdentity(value, field) {
|