@zlink-systems/framework 0.27.0 → 0.29.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/Actors/ZLinkActorClient.d.ts +1 -1
- package/dist/contracts/Channels/Calls.d.ts +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +2 -1
- package/dist/contracts/Configuration/Configs.d.ts +0 -1
- package/dist/contracts/Configuration/InternalDefaults.d.ts +3 -0
- package/dist/contracts/Configuration/InternalDefaults.js +4 -1
- package/dist/contracts/Configuration/RegistrationBuilders.js +9 -0
- package/dist/contracts/Configuration/RegistrationNormalizers.d.ts +1 -0
- package/dist/contracts/Configuration/RegistrationNormalizers.js +16 -0
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +3 -5
- package/dist/contracts/Configuration/RegistrationValidators.js +0 -2
- package/dist/contracts/Spots/Contracts.d.ts +1 -1
- package/dist/contracts/Streams/BoundSessionContracts.d.ts +1 -1
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -3
- package/dist/contracts/Streams/IZLinkSessionActor.d.ts +2 -2
- package/dist/runtime/actors/actor-client.js +7 -10
- package/dist/runtime/actors/actor-mailbox.d.ts +2 -2
- package/dist/runtime/actors/actor-mailbox.js +2 -2
- package/dist/runtime/actors/actor-request-deadline.d.ts +1 -3
- package/dist/runtime/actors/actor-request-deadline.js +4 -29
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +2 -3
- package/dist/runtime/backend/contracts/index.d.ts +1 -4
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -0
- package/dist/runtime/backend/node/node-backend-adapter-support.js +35 -4
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +1 -2
- package/dist/runtime/backend/node/node-raw-binding-port.js +10 -27
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +1 -3
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
- package/dist/runtime/channels/channel-clients.js +8 -10
- package/dist/runtime/channels/channel-envelope.d.ts +1 -1
- package/dist/runtime/channels/channel-envelope.js +4 -10
- package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
- package/dist/runtime/channels/channel-outbound-operations.js +20 -36
- package/dist/runtime/channels/channel-runtime-manager.d.ts +4 -4
- package/dist/runtime/channels/channel-runtime-manager.js +8 -8
- package/dist/runtime/channels/channel-socket-options.js +0 -10
- package/dist/runtime/channels/channel-socket-registry.d.ts +1 -1
- package/dist/runtime/channels/channel-socket-registry.js +3 -14
- package/dist/runtime/channels/channel-transports.d.ts +10 -14
- package/dist/runtime/channels/channel-transports.js +11 -14
- package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.js +1 -3
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/router-socket-spot-route-transport.js +2 -2
- package/dist/runtime/channels/source-spot-router.d.ts +1 -1
- package/dist/runtime/channels/source-spot-router.js +2 -4
- package/dist/runtime/channels/spot-node-route-transport.d.ts +1 -1
- package/dist/runtime/channels/spot-node-route-transport.js +2 -3
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +1 -1
- package/dist/runtime/channels/spot-route-bridge-transport.js +2 -2
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +2 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +11 -12
- package/dist/runtime/execution/serial-execution-queue.d.ts +12 -3
- package/dist/runtime/execution/serial-execution-queue.js +116 -28
- package/dist/runtime/foundation/operation-registry.d.ts +3 -2
- package/dist/runtime/foundation/operation-registry.js +5 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +17 -11
- package/dist/runtime/foundation/service-authority-payload-codec.d.ts +0 -2
- package/dist/runtime/foundation/service-authority-payload-codec.js +0 -43
- package/dist/runtime/foundation/service-stateful-registry.d.ts +4 -3
- package/dist/runtime/foundation/service-stateful-registry.js +5 -2
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -8
- package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -11
- package/dist/runtime/foundation/service-stateful-wire-codec.js +1 -23
- package/dist/runtime/foundation/service-topology-registry.d.ts +5 -0
- package/dist/runtime/foundation/service-topology-registry.js +16 -17
- package/dist/runtime/host/actor-packet-relay.d.ts +2 -2
- package/dist/runtime/host/actor-packet-relay.js +8 -10
- package/dist/runtime/host/index.js +1 -15
- package/dist/runtime/host/instance-activation-authority.d.ts +0 -1
- package/dist/runtime/host/instance-activation-authority.js +46 -97
- package/dist/runtime/host/remote-bound-session-relay.js +8 -8
- package/dist/runtime/host/spot-address-transport.d.ts +1 -9
- package/dist/runtime/host/spot-address-transport.js +47 -87
- package/dist/runtime/host/stateful-authority-route-runtime.d.ts +1 -0
- package/dist/runtime/host/stateful-authority-route-runtime.js +17 -9
- package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
- package/dist/runtime/locations/in-memory-authority-store.d.ts +2 -0
- package/dist/runtime/locations/in-memory-authority-store.js +22 -8
- package/dist/runtime/locations/in-memory-location-store.d.ts +1 -0
- package/dist/runtime/locations/in-memory-location-store.js +3 -0
- package/dist/runtime/locations/internal-store-contracts.d.ts +1 -1
- package/dist/runtime/locations/location-store-repository.d.ts +1 -0
- package/dist/runtime/locations/location-store-repository.js +98 -53
- package/dist/runtime/messaging/request-deadline.d.ts +3 -0
- package/dist/runtime/messaging/request-deadline.js +39 -0
- package/dist/runtime/messaging/submission-result.d.ts +2 -1
- package/dist/runtime/messaging/submission-result.js +11 -4
- package/dist/runtime/spots/spot-outbound.d.ts +3 -5
- package/dist/runtime/spots/spot-outbound.js +12 -15
- package/dist/runtime/spots/spot-serial-executor.js +4 -1
- package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
- package/dist/runtime/spots/spot-serial-turn-executor.js +5 -0
- package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -2
- package/dist/runtime/streams/bound-actor-relay-sender.js +14 -14
- package/dist/runtime/streams/bound-session-service.js +1 -1
- package/dist/runtime/streams/index.d.ts +2 -3
- package/dist/runtime/streams/index.js +6 -5
- package/dist/runtime/streams/managed-stream.d.ts +2 -2
- package/dist/runtime/streams/managed-stream.js +3 -5
- package/dist/runtime/streams/native-fallback-bound-session.js +13 -16
- package/dist/runtime/streams/protocol.js +0 -9
- package/dist/runtime/streams/session-calls.d.ts +5 -7
- package/dist/runtime/streams/session-calls.js +6 -23
- package/dist/runtime/streams/session-context.d.ts +4 -8
- package/dist/runtime/streams/session-context.js +3 -32
- package/dist/runtime/streams/session-serial-executor.d.ts +0 -1
- package/dist/runtime/streams/session-serial-executor.js +0 -3
- package/dist/runtime/streams/stream-message-utils.d.ts +0 -1
- package/dist/runtime/streams/stream-message-utils.js +0 -20
- package/dist/runtime/streams/stream-session-runtime.d.ts +6 -3
- package/dist/runtime/streams/stream-session-runtime.js +40 -85
- package/package.json +3 -3
- package/src/contracts/Actors/ZLinkActorClient.ts +1 -1
- package/src/contracts/Channels/Calls.ts +1 -1
- package/src/contracts/Configuration/Builders.ts +2 -1
- package/src/contracts/Configuration/Configs.ts +0 -1
- package/src/contracts/Configuration/InternalDefaults.ts +4 -0
- package/src/contracts/Configuration/RegistrationBuilders.ts +13 -3
- package/src/contracts/Configuration/RegistrationNormalizers.ts +25 -0
- package/src/contracts/Configuration/RegistrationTypes.ts +3 -5
- package/src/contracts/Configuration/RegistrationValidators.ts +0 -4
- package/src/contracts/Spots/Contracts.ts +1 -1
- package/src/contracts/Streams/BoundSessionContracts.ts +1 -1
- package/src/contracts/Streams/IZLinkSession.ts +2 -3
- package/src/contracts/Streams/IZLinkSessionActor.ts +2 -6
- package/src/runtime/actors/actor-client.ts +9 -15
- package/src/runtime/actors/actor-mailbox.ts +7 -2
- package/src/runtime/actors/actor-request-deadline.ts +4 -49
- package/src/runtime/actors/actor-routed-join-transport.ts +3 -5
- package/src/runtime/backend/contracts/index.ts +1 -8
- package/src/runtime/backend/node/node-backend-adapter-support.ts +45 -5
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +0 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +15 -41
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +1 -7
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +1 -1
- package/src/runtime/channels/channel-clients.ts +9 -19
- package/src/runtime/channels/channel-envelope.ts +16 -28
- package/src/runtime/channels/channel-outbound-operations.ts +36 -38
- package/src/runtime/channels/channel-runtime-manager.ts +6 -28
- package/src/runtime/channels/channel-socket-options.ts +0 -13
- package/src/runtime/channels/channel-socket-registry.ts +3 -17
- package/src/runtime/channels/channel-transports.ts +7 -33
- package/src/runtime/channels/local-spot-route-transport.ts +1 -5
- package/src/runtime/channels/router-socket-spot-route-transport.ts +2 -6
- package/src/runtime/channels/source-spot-router.ts +2 -9
- package/src/runtime/channels/spot-node-route-transport.ts +2 -7
- package/src/runtime/channels/spot-route-bridge-transport.ts +5 -12
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +11 -30
- package/src/runtime/execution/serial-execution-queue.ts +117 -29
- package/src/runtime/foundation/operation-registry.ts +16 -9
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +17 -14
- package/src/runtime/foundation/service-authority-payload-codec.ts +0 -46
- package/src/runtime/foundation/service-stateful-registry.ts +10 -5
- package/src/runtime/foundation/service-stateful-runtime.ts +103 -181
- package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -25
- package/src/runtime/foundation/service-topology-registry.ts +30 -20
- package/src/runtime/host/actor-packet-relay.ts +8 -15
- package/src/runtime/host/index.ts +2 -26
- package/src/runtime/host/instance-activation-authority.ts +58 -125
- package/src/runtime/host/remote-bound-session-relay.ts +8 -16
- package/src/runtime/host/spot-address-transport.ts +107 -166
- package/src/runtime/host/stateful-authority-route-runtime.ts +22 -9
- package/src/runtime/locations/domain-store-contract.ts +5 -0
- package/src/runtime/locations/in-memory-authority-store.ts +42 -8
- package/src/runtime/locations/in-memory-location-store.ts +8 -0
- package/src/runtime/locations/internal-store-contracts.ts +1 -0
- package/src/runtime/locations/location-store-repository.ts +130 -68
- package/src/runtime/messaging/request-deadline.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +18 -4
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
- package/src/runtime/spots/spot-outbound.ts +14 -24
- package/src/runtime/spots/spot-serial-executor.ts +4 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +10 -0
- package/src/runtime/streams/bound-actor-relay-sender.ts +12 -26
- package/src/runtime/streams/bound-session-service.ts +1 -1
- package/src/runtime/streams/index.ts +5 -5
- package/src/runtime/streams/managed-stream.ts +3 -13
- package/src/runtime/streams/native-fallback-bound-session.ts +13 -25
- package/src/runtime/streams/protocol.ts +0 -13
- package/src/runtime/streams/session-calls.ts +8 -34
- package/src/runtime/streams/session-context.ts +6 -47
- package/src/runtime/streams/session-serial-executor.ts +0 -8
- package/src/runtime/streams/stream-message-utils.ts +1 -27
- package/src/runtime/streams/stream-session-runtime.ts +54 -97
- package/dist/runtime/streams/session-requests.d.ts +0 -25
- package/dist/runtime/streams/session-requests.js +0 -101
- package/src/runtime/streams/session-requests.ts +0 -110
|
@@ -61,12 +61,10 @@ import {
|
|
|
61
61
|
import { createSessionDispatchContext, DefaultZLinkSessionContext } from './session-context';
|
|
62
62
|
import { ZLinkSessionSerialExecutor } from './session-serial-executor';
|
|
63
63
|
import { ownedMessage } from './stream-message-utils';
|
|
64
|
+
import { normalizeStreamLiveness } from '../../contracts/Configuration/RegistrationNormalizers';
|
|
64
65
|
|
|
65
66
|
const ZLINK_SEND_DONT_WAIT = 1;
|
|
66
67
|
const ZLINK_RECV_DONT_WAIT = 1;
|
|
67
|
-
const ZLINK_STREAM_HEARTBEAT_INTERVAL_MS = 1_000;
|
|
68
|
-
const ZLINK_STREAM_HEARTBEAT_TIMEOUT_MS = 5_000;
|
|
69
|
-
const ZLINK_STREAM_APPLICATION_IDLE_TIMEOUT_MS = 30_000;
|
|
70
68
|
const ZLINK_STREAM_RECEIVE_FRAME_BATCH_LIMIT = 64;
|
|
71
69
|
const ZLINK_STREAM_ACTOR_BINDING_REPLACEMENT_CLOSE_DELAY_MS = 100;
|
|
72
70
|
const ZLINK_STREAM_MONITOR_IDLE_MIN_DELAY_MS = 1;
|
|
@@ -89,9 +87,11 @@ interface ZLinkStreamLivenessOptions {
|
|
|
89
87
|
readonly claimApplicationWork?: () => ZLinkApplicationWorkClaim;
|
|
90
88
|
}
|
|
91
89
|
|
|
90
|
+
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
91
|
+
|
|
92
92
|
const systemLivenessClock: ZLinkStreamLivenessClock = {
|
|
93
93
|
now: () => performance.now(),
|
|
94
|
-
setTimer: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
94
|
+
setTimer: (callback, delayMs) => setTimeout(callback, Math.min(delayMs, MAX_TIMER_DELAY_MS)),
|
|
95
95
|
clearTimer: (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>)
|
|
96
96
|
};
|
|
97
97
|
|
|
@@ -127,6 +127,9 @@ export interface ZLinkStreamSessionContextFactory {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
export interface ZLinkStreamSessionRuntimeOptions {
|
|
130
|
+
readonly heartbeatIntervalMs?: number;
|
|
131
|
+
readonly heartbeatTimeoutMs?: number;
|
|
132
|
+
readonly idleTimeoutMs?: number;
|
|
130
133
|
readonly socket: ZLinkBackendStreamSocket;
|
|
131
134
|
readonly nativeSessionService?: StreamSessionService;
|
|
132
135
|
readonly meshCompletions?: ZLinkMeshCompletionTable;
|
|
@@ -165,8 +168,10 @@ export class ZLinkStreamSessionRuntime {
|
|
|
165
168
|
private closeReason = 'client_close';
|
|
166
169
|
private metricsClosed = false;
|
|
167
170
|
private readonly livenessClock: ZLinkStreamLivenessClock;
|
|
171
|
+
private readonly liveness: ReturnType<typeof normalizeStreamLiveness>;
|
|
168
172
|
private lastApplicationActivityAt = 0;
|
|
169
173
|
private lastInboundFrameAt = 0;
|
|
174
|
+
private lastHeartbeatPingAt = 0;
|
|
170
175
|
private livenessTimer: unknown;
|
|
171
176
|
|
|
172
177
|
constructor(
|
|
@@ -177,6 +182,7 @@ export class ZLinkStreamSessionRuntime {
|
|
|
177
182
|
session: ZLinkStreamSessionRuntime
|
|
178
183
|
) => void = () => {}
|
|
179
184
|
) {
|
|
185
|
+
this.liveness = normalizeStreamLiveness(options);
|
|
180
186
|
this.livenessClock = options.livenessClock ?? systemLivenessClock;
|
|
181
187
|
this.stream = new ZLinkManagedStream(
|
|
182
188
|
options.socket,
|
|
@@ -238,7 +244,7 @@ export class ZLinkStreamSessionRuntime {
|
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
enqueueConnected(localAddr?: string, remoteAddr?: string): void {
|
|
241
|
-
this.serial.
|
|
247
|
+
this.serial.executeControl(async () => this.markConnected(localAddr, remoteAddr));
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
enqueuePacket(
|
|
@@ -255,46 +261,22 @@ export class ZLinkStreamSessionRuntime {
|
|
|
255
261
|
terminalOwner?.close();
|
|
256
262
|
};
|
|
257
263
|
if (decodedHeader.kind === ZLinkStreamMessageKind.Control) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
void this.handleControl(decodedHeader, payload)
|
|
264
|
-
.catch((error) => {
|
|
265
|
-
this.options.onError?.(error);
|
|
266
|
-
})
|
|
267
|
-
.finally(() => {
|
|
268
|
-
applicationJobPermit?.releaseAfterInternalProcessing();
|
|
269
|
-
payload.close();
|
|
270
|
-
releaseTerminal();
|
|
271
|
-
});
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
this.enqueueControl(
|
|
275
|
-
async () => {
|
|
276
|
-
try {
|
|
277
|
-
const dispatch = () => this.dispatchPacket(payload, decodedHeader);
|
|
278
|
-
if (applicationJobPermit === undefined) await dispatch();
|
|
279
|
-
else await runWithApplicationJobPermit(applicationJobPermit, dispatch);
|
|
280
|
-
} finally {
|
|
281
|
-
releaseTerminal();
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
() => {
|
|
264
|
+
void this.handleControl(decodedHeader, payload)
|
|
265
|
+
.catch((error) => {
|
|
266
|
+
this.options.onError?.(error);
|
|
267
|
+
})
|
|
268
|
+
.finally(() => {
|
|
285
269
|
applicationJobPermit?.releaseAfterInternalProcessing();
|
|
286
270
|
payload.close();
|
|
287
271
|
releaseTerminal();
|
|
288
|
-
}
|
|
289
|
-
() => this.traceShutdownDrop(decodedHeader)
|
|
290
|
-
);
|
|
272
|
+
});
|
|
291
273
|
return;
|
|
292
274
|
}
|
|
293
275
|
if (
|
|
294
276
|
decodedHeader.kind === ZLinkStreamMessageKind.Response ||
|
|
295
277
|
decodedHeader.kind === ZLinkStreamMessageKind.Error
|
|
296
278
|
) {
|
|
297
|
-
this.
|
|
279
|
+
this.enqueueControl(
|
|
298
280
|
async () => {
|
|
299
281
|
try {
|
|
300
282
|
await this.dispatchPacket(payload, decodedHeader);
|
|
@@ -340,8 +322,7 @@ export class ZLinkStreamSessionRuntime {
|
|
|
340
322
|
}
|
|
341
323
|
|
|
342
324
|
/**
|
|
343
|
-
*
|
|
344
|
-
* without retaining that lane while application code awaits unrelated work.
|
|
325
|
+
* Retains the session turn through the callback's terminal result.
|
|
345
326
|
*/
|
|
346
327
|
enqueueActorBindingReplaced(
|
|
347
328
|
actor: ServiceActorRef,
|
|
@@ -352,7 +333,6 @@ export class ZLinkStreamSessionRuntime {
|
|
|
352
333
|
if (!this.context.beginActorBindingReplacement(actor, retiredSession)) return;
|
|
353
334
|
const session = await this.requireSession();
|
|
354
335
|
let callbackDeadlineTimer: unknown;
|
|
355
|
-
let callbackTerminal = false;
|
|
356
336
|
let forcedClose = false;
|
|
357
337
|
const scheduleClose = (): void => {
|
|
358
338
|
if (forcedClose) return;
|
|
@@ -367,23 +347,6 @@ export class ZLinkStreamSessionRuntime {
|
|
|
367
347
|
void this.close().catch((error) => this.options.onError?.(error));
|
|
368
348
|
}, ZLINK_STREAM_ACTOR_BINDING_REPLACEMENT_CLOSE_DELAY_MS);
|
|
369
349
|
};
|
|
370
|
-
const completeCallback = (): void => {
|
|
371
|
-
if (callbackTerminal) return;
|
|
372
|
-
callbackTerminal = true;
|
|
373
|
-
if (callbackDeadlineTimer !== undefined) {
|
|
374
|
-
this.livenessClock.clearTimer(callbackDeadlineTimer);
|
|
375
|
-
callbackDeadlineTimer = undefined;
|
|
376
|
-
}
|
|
377
|
-
scheduleClose();
|
|
378
|
-
};
|
|
379
|
-
const reportCallbackFailure = (error: unknown): void => {
|
|
380
|
-
try {
|
|
381
|
-
this.options.onError?.(error);
|
|
382
|
-
} catch {
|
|
383
|
-
// Diagnostics must not prevent the lifecycle terminal transition.
|
|
384
|
-
}
|
|
385
|
-
completeCallback();
|
|
386
|
-
};
|
|
387
350
|
callbackDeadlineTimer = this.livenessClock.setTimer(() => {
|
|
388
351
|
if (
|
|
389
352
|
this.disposed ||
|
|
@@ -396,18 +359,15 @@ export class ZLinkStreamSessionRuntime {
|
|
|
396
359
|
void this.close().catch((error) => this.options.onError?.(error));
|
|
397
360
|
}, this.options.replacementCallbackTimeoutMs ?? DEFAULT_SESSION_REPLACEMENT_CALLBACK_TIMEOUT_MS);
|
|
398
361
|
|
|
399
|
-
const callback = session.onActorBindingReplaced;
|
|
400
|
-
if (callback === undefined) {
|
|
401
|
-
completeCallback();
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
362
|
try {
|
|
405
|
-
|
|
406
|
-
// serial lane while application code awaits an unrelated operation.
|
|
407
|
-
const result = callback.call(session, this.context, actor.actorId);
|
|
408
|
-
void Promise.resolve(result).then(() => completeCallback(), reportCallbackFailure);
|
|
363
|
+
await session.onActorBindingReplaced?.(this.context, actor.actorId);
|
|
409
364
|
} catch (error) {
|
|
410
|
-
|
|
365
|
+
this.options.onError?.(error);
|
|
366
|
+
} finally {
|
|
367
|
+
if (callbackDeadlineTimer !== undefined) {
|
|
368
|
+
this.livenessClock.clearTimer(callbackDeadlineTimer);
|
|
369
|
+
}
|
|
370
|
+
scheduleClose();
|
|
411
371
|
}
|
|
412
372
|
});
|
|
413
373
|
}
|
|
@@ -460,6 +420,7 @@ export class ZLinkStreamSessionRuntime {
|
|
|
460
420
|
this.connected = true;
|
|
461
421
|
const connectedAt = this.livenessClock.now();
|
|
462
422
|
this.lastApplicationActivityAt = connectedAt;
|
|
423
|
+
this.lastHeartbeatPingAt = connectedAt;
|
|
463
424
|
this.lastInboundFrameAt = Math.max(this.lastInboundFrameAt, connectedAt);
|
|
464
425
|
this.scheduleLivenessCheck();
|
|
465
426
|
this.options.metrics?.change(METRIC_NAMES.StreamConnectionsActive, 1, { transport: 'tcp' });
|
|
@@ -475,15 +436,8 @@ export class ZLinkStreamSessionRuntime {
|
|
|
475
436
|
let dispatchPayload = payload;
|
|
476
437
|
let enteredDispatch = false;
|
|
477
438
|
try {
|
|
478
|
-
if (decodedHeader.kind === ZLinkStreamMessageKind.Control) {
|
|
479
|
-
await this.handleControl(decodedHeader, payload);
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
439
|
this.lastApplicationActivityAt = this.livenessClock.now();
|
|
483
440
|
dispatchPayload = this.context.payloadForHeader(decodedHeader, payload);
|
|
484
|
-
if (this.context.tryCompleteResponse(decodedHeader, dispatchPayload)) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
441
|
const dispatchActor = this.context.actorForSlot(decodedHeader.actorSlot);
|
|
488
442
|
if (decodedHeader.actorSlot !== undefined && dispatchActor === undefined) {
|
|
489
443
|
const staleFlowEnabled = this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true;
|
|
@@ -674,14 +628,21 @@ export class ZLinkStreamSessionRuntime {
|
|
|
674
628
|
if (this.disposed || this.disconnected || this.livenessTimer !== undefined) {
|
|
675
629
|
return;
|
|
676
630
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
this.
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
631
|
+
const now = this.livenessClock.now();
|
|
632
|
+
const due = Math.min(
|
|
633
|
+
this.lastHeartbeatPingAt + this.liveness.heartbeatIntervalMs,
|
|
634
|
+
this.lastInboundFrameAt + this.liveness.heartbeatTimeoutMs,
|
|
635
|
+
this.liveness.idleTimeoutMs > 0
|
|
636
|
+
? this.lastApplicationActivityAt + this.liveness.idleTimeoutMs
|
|
637
|
+
: Infinity
|
|
638
|
+
);
|
|
639
|
+
this.livenessTimer = this.livenessClock.setTimer(
|
|
640
|
+
() => {
|
|
641
|
+
this.livenessTimer = undefined;
|
|
642
|
+
void this.runLivenessCheck().catch((error) => this.options.onError?.(error));
|
|
643
|
+
},
|
|
644
|
+
Math.max(0, due - now)
|
|
645
|
+
);
|
|
685
646
|
}
|
|
686
647
|
|
|
687
648
|
private async runLivenessCheck(): Promise<void> {
|
|
@@ -689,7 +650,10 @@ export class ZLinkStreamSessionRuntime {
|
|
|
689
650
|
return;
|
|
690
651
|
}
|
|
691
652
|
const now = this.livenessClock.now();
|
|
692
|
-
if (
|
|
653
|
+
if (
|
|
654
|
+
this.liveness.idleTimeoutMs > 0 &&
|
|
655
|
+
now - this.lastApplicationActivityAt >= this.liveness.idleTimeoutMs
|
|
656
|
+
) {
|
|
693
657
|
await this.closeForLiveness(
|
|
694
658
|
ZLinkStreamCloseReasonCode.IdleTimeout,
|
|
695
659
|
'idle_timeout',
|
|
@@ -697,7 +661,7 @@ export class ZLinkStreamSessionRuntime {
|
|
|
697
661
|
);
|
|
698
662
|
return;
|
|
699
663
|
}
|
|
700
|
-
if (now - this.lastInboundFrameAt >=
|
|
664
|
+
if (now - this.lastInboundFrameAt >= this.liveness.heartbeatTimeoutMs) {
|
|
701
665
|
await this.closeForLiveness(
|
|
702
666
|
ZLinkStreamCloseReasonCode.HeartbeatTimeout,
|
|
703
667
|
'heartbeat_timeout',
|
|
@@ -705,7 +669,10 @@ export class ZLinkStreamSessionRuntime {
|
|
|
705
669
|
);
|
|
706
670
|
return;
|
|
707
671
|
}
|
|
708
|
-
|
|
672
|
+
if (now - this.lastHeartbeatPingAt >= this.liveness.heartbeatIntervalMs) {
|
|
673
|
+
this.lastHeartbeatPingAt = now;
|
|
674
|
+
await this.stream.writeControl(ZLINK_STREAM_HEARTBEAT_PING);
|
|
675
|
+
}
|
|
709
676
|
this.scheduleLivenessCheck();
|
|
710
677
|
}
|
|
711
678
|
|
|
@@ -722,7 +689,9 @@ export class ZLinkStreamSessionRuntime {
|
|
|
722
689
|
this.closeReason = closeReason;
|
|
723
690
|
this.stopLivenessChecks();
|
|
724
691
|
await this.stream.closeForReason(reason, diagnostic);
|
|
725
|
-
|
|
692
|
+
void this.serial
|
|
693
|
+
.executeFinal(async () => this.complete(undefined, true))
|
|
694
|
+
.catch((error) => this.options.onError?.(error));
|
|
726
695
|
}
|
|
727
696
|
|
|
728
697
|
private stopLivenessChecks(): void {
|
|
@@ -853,18 +822,6 @@ export class ZLinkStreamSessionRuntime {
|
|
|
853
822
|
}
|
|
854
823
|
}
|
|
855
824
|
|
|
856
|
-
private enqueueInfrastructure(
|
|
857
|
-
work: () => Promise<void>,
|
|
858
|
-
onRejected?: () => void,
|
|
859
|
-
onShutdownRejected?: () => void
|
|
860
|
-
): void {
|
|
861
|
-
if (!this.serial.executeInfrastructure(work, {}, onRejected)) {
|
|
862
|
-
// The serial lane only refuses new work after dispose() closed it.
|
|
863
|
-
onShutdownRejected?.();
|
|
864
|
-
onRejected?.();
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
825
|
private enqueueApplication(
|
|
869
826
|
work: () => Promise<void>,
|
|
870
827
|
onRejected?: (error?: unknown) => void,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Message } from '../../contracts/Common/Message';
|
|
2
|
-
export declare class ZLinkPendingSessionRequest {
|
|
3
|
-
private readonly tracker;
|
|
4
|
-
readonly requestSeq: bigint;
|
|
5
|
-
private completed;
|
|
6
|
-
private readonly timeout;
|
|
7
|
-
private resolvePromise;
|
|
8
|
-
private rejectPromise;
|
|
9
|
-
readonly promise: Promise<Message>;
|
|
10
|
-
constructor(tracker: ZLinkSessionRequestTracker, requestSeq: bigint, timeoutMs: number | undefined);
|
|
11
|
-
complete(payload: Message): void;
|
|
12
|
-
fail(error: unknown): void;
|
|
13
|
-
cancel(): void;
|
|
14
|
-
dispose(): void;
|
|
15
|
-
private clearTimeout;
|
|
16
|
-
}
|
|
17
|
-
export declare class ZLinkSessionRequestTracker {
|
|
18
|
-
private readonly pending;
|
|
19
|
-
private nextRequestSeq;
|
|
20
|
-
start(timeoutMs?: number): ZLinkPendingSessionRequest;
|
|
21
|
-
complete(requestSeq: bigint, payload: Message): boolean;
|
|
22
|
-
fail(requestSeq: bigint, error: unknown): boolean;
|
|
23
|
-
remove(requestSeq: bigint): void;
|
|
24
|
-
private next;
|
|
25
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ZLinkSessionRequestTracker = exports.ZLinkPendingSessionRequest = void 0;
|
|
4
|
-
const stream_wire_1 = require("@zlink-systems/stream-wire");
|
|
5
|
-
const stream_message_utils_1 = require("./stream-message-utils");
|
|
6
|
-
class ZLinkPendingSessionRequest {
|
|
7
|
-
tracker;
|
|
8
|
-
requestSeq;
|
|
9
|
-
completed = false;
|
|
10
|
-
timeout;
|
|
11
|
-
resolvePromise;
|
|
12
|
-
rejectPromise;
|
|
13
|
-
promise;
|
|
14
|
-
constructor(tracker, requestSeq, timeoutMs) {
|
|
15
|
-
this.tracker = tracker;
|
|
16
|
-
this.requestSeq = requestSeq;
|
|
17
|
-
this.promise = new Promise((resolve, reject) => {
|
|
18
|
-
this.resolvePromise = resolve;
|
|
19
|
-
this.rejectPromise = reject;
|
|
20
|
-
});
|
|
21
|
-
if (timeoutMs !== undefined) {
|
|
22
|
-
this.timeout = setTimeout(() => this.cancel(), timeoutMs);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
complete(payload) {
|
|
26
|
-
if (this.completed) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
this.completed = true;
|
|
30
|
-
this.clearTimeout();
|
|
31
|
-
this.resolvePromise((0, stream_message_utils_1.copyMessage)(payload));
|
|
32
|
-
}
|
|
33
|
-
fail(error) {
|
|
34
|
-
if (this.completed) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
this.completed = true;
|
|
38
|
-
this.clearTimeout();
|
|
39
|
-
this.rejectPromise(error);
|
|
40
|
-
}
|
|
41
|
-
cancel() {
|
|
42
|
-
if (this.completed) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
this.completed = true;
|
|
46
|
-
this.clearTimeout();
|
|
47
|
-
this.tracker.remove(this.requestSeq);
|
|
48
|
-
this.rejectPromise(new Error('Client stream request timed out.'));
|
|
49
|
-
}
|
|
50
|
-
dispose() {
|
|
51
|
-
this.clearTimeout();
|
|
52
|
-
this.tracker.remove(this.requestSeq);
|
|
53
|
-
}
|
|
54
|
-
clearTimeout() {
|
|
55
|
-
if (this.timeout !== undefined) {
|
|
56
|
-
clearTimeout(this.timeout);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
exports.ZLinkPendingSessionRequest = ZLinkPendingSessionRequest;
|
|
61
|
-
class ZLinkSessionRequestTracker {
|
|
62
|
-
pending = new Map();
|
|
63
|
-
nextRequestSeq = 0n;
|
|
64
|
-
start(timeoutMs) {
|
|
65
|
-
const requestSeq = this.next();
|
|
66
|
-
const pending = new ZLinkPendingSessionRequest(this, requestSeq, timeoutMs);
|
|
67
|
-
if (this.pending.has(requestSeq)) {
|
|
68
|
-
throw new Error('Duplicate stream request sequence.');
|
|
69
|
-
}
|
|
70
|
-
this.pending.set(requestSeq, pending);
|
|
71
|
-
return pending;
|
|
72
|
-
}
|
|
73
|
-
complete(requestSeq, payload) {
|
|
74
|
-
const pending = this.pending.get(requestSeq);
|
|
75
|
-
if (pending === undefined) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
this.pending.delete(requestSeq);
|
|
79
|
-
pending.complete(payload);
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
fail(requestSeq, error) {
|
|
83
|
-
const pending = this.pending.get(requestSeq);
|
|
84
|
-
if (pending === undefined) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
this.pending.delete(requestSeq);
|
|
88
|
-
pending.fail(error);
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
remove(requestSeq) {
|
|
92
|
-
this.pending.delete(requestSeq);
|
|
93
|
-
}
|
|
94
|
-
next() {
|
|
95
|
-
do {
|
|
96
|
-
this.nextRequestSeq = (this.nextRequestSeq + 1n) & stream_wire_1.UINT64_MAX;
|
|
97
|
-
} while (this.nextRequestSeq === 0n);
|
|
98
|
-
return this.nextRequestSeq;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
exports.ZLinkSessionRequestTracker = ZLinkSessionRequestTracker;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { UINT64_MAX } from '@zlink-systems/stream-wire';
|
|
2
|
-
import type { Message } from '../../contracts/Common/Message';
|
|
3
|
-
import { copyMessage } from './stream-message-utils';
|
|
4
|
-
|
|
5
|
-
export class ZLinkPendingSessionRequest {
|
|
6
|
-
private completed = false;
|
|
7
|
-
private readonly timeout: ReturnType<typeof setTimeout> | undefined;
|
|
8
|
-
private resolvePromise!: (message: Message) => void;
|
|
9
|
-
private rejectPromise!: (error: unknown) => void;
|
|
10
|
-
readonly promise: Promise<Message>;
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
private readonly tracker: ZLinkSessionRequestTracker,
|
|
14
|
-
readonly requestSeq: bigint,
|
|
15
|
-
timeoutMs: number | undefined
|
|
16
|
-
) {
|
|
17
|
-
this.promise = new Promise<Message>((resolve, reject) => {
|
|
18
|
-
this.resolvePromise = resolve;
|
|
19
|
-
this.rejectPromise = reject;
|
|
20
|
-
});
|
|
21
|
-
if (timeoutMs !== undefined) {
|
|
22
|
-
this.timeout = setTimeout(() => this.cancel(), timeoutMs);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
complete(payload: Message): void {
|
|
27
|
-
if (this.completed) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
this.completed = true;
|
|
31
|
-
this.clearTimeout();
|
|
32
|
-
this.resolvePromise(copyMessage(payload));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
fail(error: unknown): void {
|
|
36
|
-
if (this.completed) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
this.completed = true;
|
|
40
|
-
this.clearTimeout();
|
|
41
|
-
this.rejectPromise(error);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
cancel(): void {
|
|
45
|
-
if (this.completed) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
this.completed = true;
|
|
49
|
-
this.clearTimeout();
|
|
50
|
-
this.tracker.remove(this.requestSeq);
|
|
51
|
-
this.rejectPromise(new Error('Client stream request timed out.'));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
dispose(): void {
|
|
55
|
-
this.clearTimeout();
|
|
56
|
-
this.tracker.remove(this.requestSeq);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private clearTimeout(): void {
|
|
60
|
-
if (this.timeout !== undefined) {
|
|
61
|
-
clearTimeout(this.timeout);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class ZLinkSessionRequestTracker {
|
|
67
|
-
private readonly pending = new Map<bigint, ZLinkPendingSessionRequest>();
|
|
68
|
-
private nextRequestSeq = 0n;
|
|
69
|
-
|
|
70
|
-
start(timeoutMs?: number): ZLinkPendingSessionRequest {
|
|
71
|
-
const requestSeq = this.next();
|
|
72
|
-
const pending = new ZLinkPendingSessionRequest(this, requestSeq, timeoutMs);
|
|
73
|
-
if (this.pending.has(requestSeq)) {
|
|
74
|
-
throw new Error('Duplicate stream request sequence.');
|
|
75
|
-
}
|
|
76
|
-
this.pending.set(requestSeq, pending);
|
|
77
|
-
return pending;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
complete(requestSeq: bigint, payload: Message): boolean {
|
|
81
|
-
const pending = this.pending.get(requestSeq);
|
|
82
|
-
if (pending === undefined) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
this.pending.delete(requestSeq);
|
|
86
|
-
pending.complete(payload);
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
fail(requestSeq: bigint, error: unknown): boolean {
|
|
91
|
-
const pending = this.pending.get(requestSeq);
|
|
92
|
-
if (pending === undefined) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
this.pending.delete(requestSeq);
|
|
96
|
-
pending.fail(error);
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
remove(requestSeq: bigint): void {
|
|
101
|
-
this.pending.delete(requestSeq);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private next(): bigint {
|
|
105
|
-
do {
|
|
106
|
-
this.nextRequestSeq = (this.nextRequestSeq + 1n) & UINT64_MAX;
|
|
107
|
-
} while (this.nextRequestSeq === 0n);
|
|
108
|
-
return this.nextRequestSeq;
|
|
109
|
-
}
|
|
110
|
-
}
|