@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
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type { SubmitResult } from './runtime-values';
|
|
2
|
+
|
|
3
|
+
export interface ZLinkRawSendSubmission {
|
|
4
|
+
readonly result: typeof SubmitResult.Ok | typeof SubmitResult.Backpressured;
|
|
5
|
+
readonly admitted: Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
export interface ZLinkRawReceivedRecord {
|
|
2
9
|
readonly sourceRid: string;
|
|
3
10
|
readonly sourceRoute: Uint8Array;
|
|
@@ -31,7 +38,6 @@ export interface ZLinkRawSocketPort {
|
|
|
31
38
|
unbind(endpoint: string): void;
|
|
32
39
|
connect(endpoint: string): void;
|
|
33
40
|
disconnect(endpoint: string): void;
|
|
34
|
-
setReceiveFlowState(state: 'running' | 'paused'): void;
|
|
35
41
|
monitor(): ZLinkRawMonitorPort;
|
|
36
42
|
close(): void;
|
|
37
43
|
}
|
|
@@ -49,6 +55,9 @@ export interface ZLinkRawRouterRoute {
|
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
export interface ZLinkRawRouterPort extends ZLinkRawSocketPort {
|
|
58
|
+
setReceiveFlowState(state: 'running' | 'paused'): void;
|
|
59
|
+
/** Reports Core submit synchronously; admitted observes only pending admission. */
|
|
60
|
+
submitSend(targetRid: string, parts: readonly Uint8Array[]): ZLinkRawSendSubmission;
|
|
52
61
|
disconnectRid?(routingId: string): void;
|
|
53
62
|
localEndpoint(): string;
|
|
54
63
|
setRoutingId(routingId: string): void;
|
|
@@ -57,7 +66,8 @@ export interface ZLinkRawRouterPort extends ZLinkRawSocketPort {
|
|
|
57
66
|
request(
|
|
58
67
|
targetRid: string,
|
|
59
68
|
parts: readonly Uint8Array[],
|
|
60
|
-
timeoutMs: number
|
|
69
|
+
timeoutMs: number,
|
|
70
|
+
recordReceived?: () => void
|
|
61
71
|
): Promise<readonly Buffer[]>;
|
|
62
72
|
receive(dontWait?: boolean): ZLinkRawReceivedRecord | undefined;
|
|
63
73
|
/** The selected route of every RID. The socket's one route observer calls it. */
|
|
@@ -359,7 +359,7 @@ export class ZLinkChannelReceiveLoop {
|
|
|
359
359
|
|
|
360
360
|
private async acquirePermit(signal: AbortSignal): Promise<ApplicationJobQueuePermit | undefined> {
|
|
361
361
|
try {
|
|
362
|
-
return await this.applicationJobQueue.acquire(signal);
|
|
362
|
+
return await this.applicationJobQueue.acquire(signal, 'remote');
|
|
363
363
|
} catch (error) {
|
|
364
364
|
if (this.isStopped() || signal.aborted) return undefined;
|
|
365
365
|
throw error;
|
|
@@ -585,7 +585,7 @@ export class ZLinkSubscriberReceiveLoop {
|
|
|
585
585
|
|
|
586
586
|
private async acquirePermit(signal: AbortSignal): Promise<ApplicationJobQueuePermit | undefined> {
|
|
587
587
|
try {
|
|
588
|
-
return await this.applicationJobQueue.acquire(signal);
|
|
588
|
+
return await this.applicationJobQueue.acquire(signal, 'remote');
|
|
589
589
|
} catch (error) {
|
|
590
590
|
if (this.isStopped() || signal.aborted) return undefined;
|
|
591
591
|
throw error;
|
|
@@ -795,7 +795,7 @@ export class ZLinkRouteReceiveLoop {
|
|
|
795
795
|
|
|
796
796
|
private async acquirePermit(signal: AbortSignal): Promise<ApplicationJobQueuePermit | undefined> {
|
|
797
797
|
try {
|
|
798
|
-
return await this.applicationJobQueue.acquire(signal);
|
|
798
|
+
return await this.applicationJobQueue.acquire(signal, 'remote');
|
|
799
799
|
} catch (error) {
|
|
800
800
|
if (this.isStopped() || signal.aborted) return undefined;
|
|
801
801
|
throw error;
|
|
@@ -551,13 +551,19 @@ export class ZLinkChannelRuntimeLifecycle {
|
|
|
551
551
|
unhandled: this.options.registration.dispatch?.unhandled
|
|
552
552
|
});
|
|
553
553
|
const spotRouteBridge = this.createSpotRouteBridgeForRouter(channelName, router);
|
|
554
|
+
const serverPeers = this.options.sockets.clientServerServerPeersForChannel(channelName);
|
|
554
555
|
const loop = new ZLinkChannelReceiveLoop(
|
|
555
556
|
channelName,
|
|
556
557
|
router,
|
|
557
558
|
dispatcher,
|
|
558
559
|
spotRouteBridge,
|
|
559
560
|
(received, socket) =>
|
|
560
|
-
this.options.sockets.tryHandleClientServerControl(
|
|
561
|
+
this.options.sockets.tryHandleClientServerControl(
|
|
562
|
+
channelName,
|
|
563
|
+
received,
|
|
564
|
+
socket,
|
|
565
|
+
serverPeers
|
|
566
|
+
),
|
|
561
567
|
this.options.adapter.createReadablePoller(router),
|
|
562
568
|
this.options.applicationJobQueue,
|
|
563
569
|
(error) =>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RuntimeDisposal } from '../disposal';
|
|
2
2
|
import { UINT64_MAX } from '@zlink-systems/stream-wire';
|
|
3
3
|
import { randomBytes, randomUUID } from 'node:crypto';
|
|
4
|
+
import { ReceiveFlowState } from '@zlink-systems/zlink';
|
|
4
5
|
import {
|
|
5
6
|
ZLinkFrameworkRuntimeState,
|
|
6
7
|
type RoutingId,
|
|
@@ -41,6 +42,7 @@ import { ZLinkListenerRecords } from '../foundation/listener-records';
|
|
|
41
42
|
import { discoveryAvailabilityForRuntimeState } from '../foundation/runtime-state-projections';
|
|
42
43
|
import { ServiceDiscoveryRegistry } from '../foundation/service-discovery-registry';
|
|
43
44
|
import {
|
|
45
|
+
ServiceLivenessConnection,
|
|
44
46
|
DEFAULT_SERVICE_PEER_TIMEOUT_MS,
|
|
45
47
|
DEFAULT_SERVICE_PROBE_INTERVAL_MS
|
|
46
48
|
} from '../foundation/service-liveness-registry';
|
|
@@ -101,9 +103,7 @@ interface ClientServerPhysicalConnection {
|
|
|
101
103
|
physicalConnectionId: symbol;
|
|
102
104
|
readyConnectionId?: string;
|
|
103
105
|
admittedDescriptor?: ClientServerDiscoveryDescriptor;
|
|
104
|
-
|
|
105
|
-
deadlineAt?: number;
|
|
106
|
-
outstandingProbeId?: bigint;
|
|
106
|
+
liveness?: ServiceLivenessConnection;
|
|
107
107
|
admissionAttempt?: symbol;
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -112,6 +112,13 @@ export interface ZLinkFanoutConnectionCallbacks {
|
|
|
112
112
|
readonly onTerminated: (reason: 'disconnect' | 'deadline' | 'protocol') => void;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
interface ClientServerServerPeer {
|
|
116
|
+
readonly channelName: string;
|
|
117
|
+
readonly routingId: RoutingId;
|
|
118
|
+
readonly normalizedEffectiveMaxMessageBytes: number;
|
|
119
|
+
readonly liveness: ServiceLivenessConnection;
|
|
120
|
+
}
|
|
121
|
+
|
|
115
122
|
interface FanoutPublisherConnection {
|
|
116
123
|
readonly channelName: string;
|
|
117
124
|
readonly endpoint: string;
|
|
@@ -124,8 +131,6 @@ interface FanoutPublisherConnection {
|
|
|
124
131
|
deadlineAt?: number;
|
|
125
132
|
}
|
|
126
133
|
|
|
127
|
-
type ReceiveFlowSocket = ZLinkBackendDealerSocket | ZLinkBackendRouterSocket;
|
|
128
|
-
|
|
129
134
|
export class ZLinkChannelSocketRegistry {
|
|
130
135
|
private readonly clientDealers = new Map<string, ZLinkBackendDealerSocket>();
|
|
131
136
|
private readonly channelRouters = new Map<string, ZLinkBackendRouterSocket>();
|
|
@@ -155,18 +160,9 @@ export class ZLinkChannelSocketRegistry {
|
|
|
155
160
|
>();
|
|
156
161
|
private readonly clientServerPublicWeights = new Map<string, number>();
|
|
157
162
|
private readonly routeMeshPublicWeights = new Map<string, number>();
|
|
158
|
-
private readonly clientServerAdmittedClients = new Map<string, Set<RoutingId>>();
|
|
159
163
|
private readonly clientServerServerPeers = new Map<
|
|
160
164
|
string,
|
|
161
|
-
|
|
162
|
-
readonly channelName: string;
|
|
163
|
-
readonly routingId: RoutingId;
|
|
164
|
-
readonly physicalConnectionId: symbol;
|
|
165
|
-
readonly normalizedEffectiveMaxMessageBytes: number;
|
|
166
|
-
nextProbeAt: number;
|
|
167
|
-
deadlineAt: number;
|
|
168
|
-
outstandingProbeId?: bigint;
|
|
169
|
-
}
|
|
165
|
+
Map<RoutingId, ClientServerServerPeer>
|
|
170
166
|
>();
|
|
171
167
|
private readonly disposal = new RuntimeDisposal();
|
|
172
168
|
private readonly ownedResources = new Set<
|
|
@@ -226,9 +222,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
226
222
|
...this.publishers.values(),
|
|
227
223
|
...this.routeRouters.values()
|
|
228
224
|
];
|
|
229
|
-
for (const socket of new Set<
|
|
230
|
-
...this.clientDealers.values(),
|
|
231
|
-
...clientServerConnections.map((value) => value.dealer),
|
|
225
|
+
for (const socket of new Set<ZLinkBackendRouterSocket>([
|
|
232
226
|
...this.channelRouters.values(),
|
|
233
227
|
...this.routeRouters.values()
|
|
234
228
|
]))
|
|
@@ -237,7 +231,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
237
231
|
this.clientServerServerDescriptors.clear();
|
|
238
232
|
this.clientServerPublicWeights.clear();
|
|
239
233
|
this.routeMeshPublicWeights.clear();
|
|
240
|
-
this.
|
|
234
|
+
for (const peers of this.clientServerServerPeers.values()) peers.clear();
|
|
241
235
|
this.clientServerServerPeers.clear();
|
|
242
236
|
this.clientServerMonitorHandlers.clear();
|
|
243
237
|
this.fanoutMonitorHandlers.clear();
|
|
@@ -294,7 +288,6 @@ export class ZLinkChannelSocketRegistry {
|
|
|
294
288
|
|
|
295
289
|
const dealer = this.adapter.createDealerSocket(this.context);
|
|
296
290
|
this.clientDealers.set(channelName, dealer);
|
|
297
|
-
this.registerReceiveFlowSocket(dealer);
|
|
298
291
|
dealer.setChannelName(channelName);
|
|
299
292
|
if (channel?.routingId !== undefined && channel.routingId.length > 0) {
|
|
300
293
|
dealer.setRoutingId(deriveRoutingId(channel.routingId, 'dealer'));
|
|
@@ -350,8 +343,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
350
343
|
)
|
|
351
344
|
return;
|
|
352
345
|
const routingId = String(event.routingId);
|
|
353
|
-
this.clientServerServerPeers.delete(
|
|
354
|
-
this.clientServerAdmittedClients.get(channelName)?.delete(routingId);
|
|
346
|
+
this.clientServerServerPeers.get(channelName)?.delete(routingId);
|
|
355
347
|
});
|
|
356
348
|
}
|
|
357
349
|
const endpoint = advertisedEndpoint(
|
|
@@ -450,7 +442,6 @@ export class ZLinkChannelSocketRegistry {
|
|
|
450
442
|
)[] = [dealer];
|
|
451
443
|
try {
|
|
452
444
|
this.clientServerConnections.set(connectionId, connection);
|
|
453
|
-
this.registerReceiveFlowSocket(dealer);
|
|
454
445
|
dealer.setChannelName(channelName);
|
|
455
446
|
dealer.setRoutingId(`cs-client-${randomUUID()}`);
|
|
456
447
|
applySocketConfig(dealer, {
|
|
@@ -501,7 +492,6 @@ export class ZLinkChannelSocketRegistry {
|
|
|
501
492
|
return dealer;
|
|
502
493
|
} catch (error) {
|
|
503
494
|
this.clientServerConnections.delete(connectionId);
|
|
504
|
-
this.unregisterReceiveFlowSocket(dealer);
|
|
505
495
|
void Promise.allSettled(
|
|
506
496
|
created.map(async (resource) => {
|
|
507
497
|
await resource.dispose();
|
|
@@ -561,7 +551,6 @@ export class ZLinkChannelSocketRegistry {
|
|
|
561
551
|
} catch {
|
|
562
552
|
// The socket close below releases an endpoint that is already disconnected.
|
|
563
553
|
}
|
|
564
|
-
this.unregisterReceiveFlowSocket(current.dealer);
|
|
565
554
|
if (current.readablePoller !== undefined) {
|
|
566
555
|
current.readablePoller.dispose();
|
|
567
556
|
this.ownedResources.delete(current.readablePoller);
|
|
@@ -623,9 +612,8 @@ export class ZLinkChannelSocketRegistry {
|
|
|
623
612
|
const admitted = this.clientServerDiscovery.admitClientServer(descriptor, connectionId);
|
|
624
613
|
if (admitted) {
|
|
625
614
|
const now = performance.now();
|
|
626
|
-
connection.
|
|
627
|
-
connection.
|
|
628
|
-
connection.outstandingProbeId = undefined;
|
|
615
|
+
connection.liveness = new ServiceLivenessConnection(connectionId, now);
|
|
616
|
+
connection.dealer.receiveAdmission = connection.liveness;
|
|
629
617
|
this.clientServerReadyIdentities.set(connectionId, {
|
|
630
618
|
channelName: descriptor.channelName,
|
|
631
619
|
serverRoutingId: descriptor.serverRoutingId,
|
|
@@ -653,9 +641,8 @@ export class ZLinkChannelSocketRegistry {
|
|
|
653
641
|
const connection = this.clientServerConnections.get(connectionId);
|
|
654
642
|
if (connection?.readyConnectionId === connectionId) {
|
|
655
643
|
connection.readyConnectionId = undefined;
|
|
656
|
-
connection.
|
|
657
|
-
connection.
|
|
658
|
-
connection.outstandingProbeId = undefined;
|
|
644
|
+
connection.liveness = undefined;
|
|
645
|
+
connection.dealer.receiveAdmission = undefined;
|
|
659
646
|
}
|
|
660
647
|
}
|
|
661
648
|
this.notifyClientServerTopology(channelName);
|
|
@@ -898,6 +885,15 @@ export class ZLinkChannelSocketRegistry {
|
|
|
898
885
|
for (const handler of this.clientServerMonitorHandlers.get(channelName) ?? []) handler();
|
|
899
886
|
}
|
|
900
887
|
|
|
888
|
+
clientServerServerPeersForChannel(channelName: string): Map<RoutingId, ClientServerServerPeer> {
|
|
889
|
+
let peers = this.clientServerServerPeers.get(channelName);
|
|
890
|
+
if (peers === undefined) {
|
|
891
|
+
peers = new Map();
|
|
892
|
+
this.clientServerServerPeers.set(channelName, peers);
|
|
893
|
+
}
|
|
894
|
+
return peers;
|
|
895
|
+
}
|
|
896
|
+
|
|
901
897
|
tryHandleClientServerControl(
|
|
902
898
|
channelName: string,
|
|
903
899
|
received: {
|
|
@@ -905,8 +901,12 @@ export class ZLinkChannelSocketRegistry {
|
|
|
905
901
|
readonly replyToken: unknown | null;
|
|
906
902
|
readonly routingId: unknown;
|
|
907
903
|
},
|
|
908
|
-
router: ZLinkBackendRouterSocket
|
|
904
|
+
router: ZLinkBackendRouterSocket,
|
|
905
|
+
peers = this.clientServerServerPeersForChannel(channelName)
|
|
909
906
|
): boolean {
|
|
907
|
+
const routingId = String(received.routingId) as RoutingId;
|
|
908
|
+
const peer = peers.get(routingId);
|
|
909
|
+
peer?.liveness.recordReceived();
|
|
910
910
|
if (received.parts.length === 0) return false;
|
|
911
911
|
const first = received.parts[0];
|
|
912
912
|
if (!isClientServerControlFrame(first.data())) return false;
|
|
@@ -924,18 +924,8 @@ export class ZLinkChannelSocketRegistry {
|
|
|
924
924
|
received.parts.length === 1 &&
|
|
925
925
|
received.replyToken === null
|
|
926
926
|
) {
|
|
927
|
-
if (
|
|
928
|
-
|
|
929
|
-
channelName,
|
|
930
|
-
String(received.routingId),
|
|
931
|
-
record.probeId
|
|
932
|
-
)
|
|
933
|
-
) {
|
|
934
|
-
this.reportStaleClientServerLivenessAck(
|
|
935
|
-
channelName,
|
|
936
|
-
String(received.routingId),
|
|
937
|
-
record.probeId
|
|
938
|
-
);
|
|
927
|
+
if (!this.acceptClientServerServerLivenessAck(peer, record.probeId)) {
|
|
928
|
+
this.reportStaleClientServerLivenessAck(channelName, routingId, record.probeId);
|
|
939
929
|
}
|
|
940
930
|
return true;
|
|
941
931
|
} else if (
|
|
@@ -960,7 +950,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
960
950
|
reply = encodeClientServerAdmit(descriptor, normalizedEffectiveMaxMessageBytes);
|
|
961
951
|
this.admitClientServerServerPeer(
|
|
962
952
|
channelName,
|
|
963
|
-
|
|
953
|
+
routingId,
|
|
964
954
|
normalizedEffectiveMaxMessageBytes
|
|
965
955
|
);
|
|
966
956
|
}
|
|
@@ -971,7 +961,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
971
961
|
if (received.replyToken !== null) {
|
|
972
962
|
const message = RuntimeMessage.from(reply);
|
|
973
963
|
try {
|
|
974
|
-
router.reply(
|
|
964
|
+
router.reply(routingId, received.replyToken, message);
|
|
975
965
|
} finally {
|
|
976
966
|
message.close();
|
|
977
967
|
}
|
|
@@ -987,34 +977,32 @@ export class ZLinkChannelSocketRegistry {
|
|
|
987
977
|
(connection.aliases.values().next().value as string | undefined);
|
|
988
978
|
if (connectionId === undefined) continue;
|
|
989
979
|
this.drainClientServerControl(connectionId, connection);
|
|
990
|
-
if (connection.
|
|
991
|
-
if (
|
|
980
|
+
if (connection.liveness === undefined) continue;
|
|
981
|
+
if (connection.liveness.isExpired(nowMs)) {
|
|
992
982
|
this.restartClientServerAdmission(connectionId, connection);
|
|
993
983
|
continue;
|
|
994
984
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
985
|
+
const probeId = connection.liveness.tryGetProbe(nowMs, () =>
|
|
986
|
+
this.allocateClientServerProbeId()
|
|
987
|
+
);
|
|
988
|
+
if (probeId === undefined) continue;
|
|
999
989
|
this.requestClientServerLiveness(connectionId, connection, probeId);
|
|
1000
990
|
}
|
|
1001
991
|
|
|
1002
|
-
for (const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
992
|
+
for (const peers of this.clientServerServerPeers.values()) {
|
|
993
|
+
for (const [routingId, peer] of peers) {
|
|
994
|
+
if (peer.liveness.isExpired(nowMs)) {
|
|
995
|
+
peers.delete(routingId);
|
|
996
|
+
try {
|
|
997
|
+
this.channelRouters.get(peer.channelName)?.disconnectPeer(peer.routingId);
|
|
998
|
+
} catch (error) {
|
|
999
|
+
this.oneWayFailureSink?.(error);
|
|
1000
|
+
}
|
|
1001
|
+
continue;
|
|
1010
1002
|
}
|
|
1011
|
-
|
|
1003
|
+
const probeId = peer.liveness.tryGetProbe(nowMs, () => this.allocateClientServerProbeId());
|
|
1004
|
+
if (probeId !== undefined) this.requestClientServerServerLiveness(peer, probeId);
|
|
1012
1005
|
}
|
|
1013
|
-
if (nowMs < peer.nextProbeAt) continue;
|
|
1014
|
-
peer.nextProbeAt = nowMs + CLIENT_SERVER_PROBE_INTERVAL_MS;
|
|
1015
|
-
const probeId = peer.outstandingProbeId ?? this.allocateClientServerProbeId();
|
|
1016
|
-
peer.outstandingProbeId = probeId;
|
|
1017
|
-
this.requestClientServerServerLiveness(peer, probeId);
|
|
1018
1006
|
}
|
|
1019
1007
|
this.tickFanoutLiveness(nowMs);
|
|
1020
1008
|
}
|
|
@@ -1376,6 +1364,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1376
1364
|
connectionId: string,
|
|
1377
1365
|
connection: ClientServerPhysicalConnection
|
|
1378
1366
|
): void {
|
|
1367
|
+
const admission = connection.liveness;
|
|
1379
1368
|
for (;;) {
|
|
1380
1369
|
if (connection.readablePoller === undefined || !connection.readablePoller.wait(0)) return;
|
|
1381
1370
|
const received = connection.dealer.recv(1);
|
|
@@ -1383,6 +1372,7 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1383
1372
|
connection.readablePoller.markDrained();
|
|
1384
1373
|
return;
|
|
1385
1374
|
}
|
|
1375
|
+
admission?.recordReceived();
|
|
1386
1376
|
try {
|
|
1387
1377
|
if (received.parts.length !== 1 || !isClientServerControlFrame(received.parts[0]!.data())) {
|
|
1388
1378
|
throw new ZLinkConfigurationException(
|
|
@@ -1534,24 +1524,18 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1534
1524
|
if (connection.readyConnectionId === connectionId) {
|
|
1535
1525
|
connection.readyConnectionId = undefined;
|
|
1536
1526
|
}
|
|
1537
|
-
connection.
|
|
1538
|
-
connection.
|
|
1539
|
-
connection.outstandingProbeId = undefined;
|
|
1527
|
+
connection.liveness = undefined;
|
|
1528
|
+
connection.dealer.receiveAdmission = undefined;
|
|
1540
1529
|
}
|
|
1541
1530
|
this.notifyClientServerTopology(identity.channelName);
|
|
1542
1531
|
}
|
|
1543
1532
|
|
|
1544
1533
|
private requestClientServerLiveness(
|
|
1545
1534
|
connectionId: string,
|
|
1546
|
-
connection:
|
|
1547
|
-
readonly channelName: string;
|
|
1548
|
-
readonly dealer: ZLinkBackendDealerSocket;
|
|
1549
|
-
readonly physicalConnectionId: symbol;
|
|
1550
|
-
outstandingProbeId?: bigint;
|
|
1551
|
-
deadlineAt?: number;
|
|
1552
|
-
},
|
|
1535
|
+
connection: ClientServerPhysicalConnection,
|
|
1553
1536
|
probeId: bigint
|
|
1554
1537
|
): void {
|
|
1538
|
+
const admission = connection.liveness;
|
|
1555
1539
|
const message = RuntimeMessage.from(encodeClientServerLivenessProbe(probeId));
|
|
1556
1540
|
void connection.dealer
|
|
1557
1541
|
.request(message, CLIENT_SERVER_PEER_DEADLINE_MS)
|
|
@@ -1561,12 +1545,16 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1561
1545
|
if (
|
|
1562
1546
|
current === undefined ||
|
|
1563
1547
|
current.physicalConnectionId !== connection.physicalConnectionId ||
|
|
1548
|
+
current.liveness !== admission ||
|
|
1564
1549
|
parts.length !== 1
|
|
1565
1550
|
)
|
|
1566
1551
|
return;
|
|
1567
1552
|
const record = decodeClientServerControl(parts[0]!.data());
|
|
1568
1553
|
if (record.kind !== 'livenessAck') return;
|
|
1569
|
-
if (
|
|
1554
|
+
if (
|
|
1555
|
+
admission === undefined ||
|
|
1556
|
+
!admission.acknowledge(record.probeId, performance.now())
|
|
1557
|
+
) {
|
|
1570
1558
|
this.reportStaleClientServerLivenessAck(
|
|
1571
1559
|
connection.channelName,
|
|
1572
1560
|
connectionId,
|
|
@@ -1574,8 +1562,6 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1574
1562
|
);
|
|
1575
1563
|
return;
|
|
1576
1564
|
}
|
|
1577
|
-
current.outstandingProbeId = undefined;
|
|
1578
|
-
current.deadlineAt = performance.now() + CLIENT_SERVER_PEER_DEADLINE_MS;
|
|
1579
1565
|
} finally {
|
|
1580
1566
|
closeMessages(parts);
|
|
1581
1567
|
}
|
|
@@ -1589,36 +1575,20 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1589
1575
|
routingId: RoutingId,
|
|
1590
1576
|
normalizedEffectiveMaxMessageBytes: number
|
|
1591
1577
|
): void {
|
|
1592
|
-
const
|
|
1593
|
-
const now = performance.now();
|
|
1594
|
-
const peer = {
|
|
1578
|
+
const peer: ClientServerServerPeer = {
|
|
1595
1579
|
channelName,
|
|
1596
1580
|
routingId,
|
|
1597
|
-
physicalConnectionId: Symbol(key),
|
|
1598
1581
|
normalizedEffectiveMaxMessageBytes,
|
|
1599
|
-
|
|
1600
|
-
|
|
1582
|
+
liveness: new ServiceLivenessConnection(
|
|
1583
|
+
clientServerServerPeerKey(channelName, routingId),
|
|
1584
|
+
performance.now()
|
|
1585
|
+
)
|
|
1601
1586
|
};
|
|
1602
|
-
this.
|
|
1603
|
-
let clients = this.clientServerAdmittedClients.get(channelName);
|
|
1604
|
-
if (clients === undefined) {
|
|
1605
|
-
clients = new Set();
|
|
1606
|
-
this.clientServerAdmittedClients.set(channelName, clients);
|
|
1607
|
-
}
|
|
1608
|
-
clients.add(routingId);
|
|
1587
|
+
this.clientServerServerPeersForChannel(channelName).set(routingId, peer);
|
|
1609
1588
|
this.ensureClientServerLivenessTimer();
|
|
1610
1589
|
}
|
|
1611
1590
|
|
|
1612
|
-
private requestClientServerServerLiveness(
|
|
1613
|
-
peer: {
|
|
1614
|
-
readonly channelName: string;
|
|
1615
|
-
readonly routingId: RoutingId;
|
|
1616
|
-
readonly physicalConnectionId: symbol;
|
|
1617
|
-
outstandingProbeId?: bigint;
|
|
1618
|
-
deadlineAt: number;
|
|
1619
|
-
},
|
|
1620
|
-
probeId: bigint
|
|
1621
|
-
): void {
|
|
1591
|
+
private requestClientServerServerLiveness(peer: ClientServerServerPeer, probeId: bigint): void {
|
|
1622
1592
|
const router = this.channelRouters.get(peer.channelName);
|
|
1623
1593
|
if (router === undefined) return;
|
|
1624
1594
|
const message = RuntimeMessage.from(encodeClientServerLivenessProbe(probeId));
|
|
@@ -1629,17 +1599,10 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1629
1599
|
}
|
|
1630
1600
|
|
|
1631
1601
|
private acceptClientServerServerLivenessAck(
|
|
1632
|
-
|
|
1633
|
-
routingId: RoutingId,
|
|
1602
|
+
peer: ClientServerServerPeer | undefined,
|
|
1634
1603
|
probeId: bigint
|
|
1635
1604
|
): boolean {
|
|
1636
|
-
|
|
1637
|
-
clientServerServerPeerKey(channelName, routingId)
|
|
1638
|
-
);
|
|
1639
|
-
if (peer === undefined || peer.outstandingProbeId !== probeId) return false;
|
|
1640
|
-
peer.outstandingProbeId = undefined;
|
|
1641
|
-
peer.deadlineAt = performance.now() + CLIENT_SERVER_PEER_DEADLINE_MS;
|
|
1642
|
-
return true;
|
|
1605
|
+
return peer?.liveness.acknowledge(probeId, performance.now()) ?? false;
|
|
1643
1606
|
}
|
|
1644
1607
|
|
|
1645
1608
|
private reportStaleClientServerLivenessAck(
|
|
@@ -1661,23 +1624,15 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1661
1624
|
descriptor: ZLinkClientServerServerDescriptor
|
|
1662
1625
|
): void {
|
|
1663
1626
|
const router = this.channelRouters.get(channelName);
|
|
1664
|
-
const
|
|
1665
|
-
if (router === undefined ||
|
|
1666
|
-
for (const routingId of
|
|
1667
|
-
const peer = this.clientServerServerPeers.get(
|
|
1668
|
-
clientServerServerPeerKey(channelName, routingId)
|
|
1669
|
-
);
|
|
1670
|
-
if (peer === undefined) {
|
|
1671
|
-
clients.delete(routingId);
|
|
1672
|
-
continue;
|
|
1673
|
-
}
|
|
1627
|
+
const peers = this.clientServerServerPeers.get(channelName);
|
|
1628
|
+
if (router === undefined || peers === undefined) return;
|
|
1629
|
+
for (const [routingId, peer] of peers) {
|
|
1674
1630
|
const message = RuntimeMessage.from(
|
|
1675
1631
|
encodeClientServerUpdate(descriptor, peer.normalizedEffectiveMaxMessageBytes)
|
|
1676
1632
|
);
|
|
1677
1633
|
void router
|
|
1678
1634
|
.send(routingId, message)
|
|
1679
1635
|
.catch((error) => {
|
|
1680
|
-
clients.delete(routingId);
|
|
1681
1636
|
this.oneWayFailureSink?.(error);
|
|
1682
1637
|
})
|
|
1683
1638
|
.finally(() => message.close());
|
|
@@ -1786,15 +1741,18 @@ export class ZLinkChannelSocketRegistry {
|
|
|
1786
1741
|
router.peerWeight = rawAvailabilityWeight(weight);
|
|
1787
1742
|
}
|
|
1788
1743
|
|
|
1789
|
-
private registerReceiveFlowSocket(socket:
|
|
1744
|
+
private registerReceiveFlowSocket(socket: ZLinkBackendRouterSocket): void {
|
|
1790
1745
|
this.applicationJobQueue?.registerReceiveFlowTarget(
|
|
1791
1746
|
socket,
|
|
1792
|
-
(state) =>
|
|
1747
|
+
(state) =>
|
|
1748
|
+
socket.setReceiveFlowState(
|
|
1749
|
+
state === 'paused' ? ReceiveFlowState.PAUSED : ReceiveFlowState.RUNNING
|
|
1750
|
+
),
|
|
1793
1751
|
this.oneWayFailureSink
|
|
1794
1752
|
);
|
|
1795
1753
|
}
|
|
1796
1754
|
|
|
1797
|
-
private unregisterReceiveFlowSocket(socket:
|
|
1755
|
+
private unregisterReceiveFlowSocket(socket: ZLinkBackendRouterSocket): void {
|
|
1798
1756
|
this.applicationJobQueue?.unregisterReceiveFlowTarget(socket);
|
|
1799
1757
|
}
|
|
1800
1758
|
|
|
@@ -1962,7 +1920,7 @@ function applyFanoutPublisherSocketOptions(
|
|
|
1962
1920
|
channel: ZLinkChannelOptions
|
|
1963
1921
|
): void {
|
|
1964
1922
|
publisher.noDrop = channel.noDrop ?? false;
|
|
1965
|
-
publisher.sendTimeoutMs =
|
|
1923
|
+
publisher.sendTimeoutMs = channel.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS;
|
|
1966
1924
|
}
|
|
1967
1925
|
|
|
1968
1926
|
function fanoutDiscoveryConnectionId(connectionId: string): string {
|
|
@@ -2022,7 +1980,3 @@ function applySocketConfig(
|
|
|
2022
1980
|
socket.maxMessageSize = config.maxMessageSize;
|
|
2023
1981
|
}
|
|
2024
1982
|
}
|
|
2025
|
-
|
|
2026
|
-
function configuredSendTimeoutMs(value: number | undefined): number {
|
|
2027
|
-
return value ?? DEFAULT_SEND_TIMEOUT_MS;
|
|
2028
|
-
}
|
|
@@ -35,7 +35,7 @@ export const DEFAULT_ZLINK_DIAGNOSTICS: ZLinkDiagnosticsOptions = {
|
|
|
35
35
|
includeMessageSizes: false
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
const telemetryLogger = openTelemetryLogs.getLogger('@zlink-systems/framework');
|
|
38
|
+
export const telemetryLogger = openTelemetryLogs.getLogger('@zlink-systems/framework');
|
|
39
39
|
const telemetryTracer = openTelemetryTrace.getTracer('@zlink-systems/framework');
|
|
40
40
|
|
|
41
41
|
let diagnosticsGeneration = 0n;
|