@zlink-systems/framework 0.22.0 → 0.23.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/Dispatch/ZLinkDispatchOptions.d.ts +1 -0
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -1
- package/dist/runtime/actors/actor-context.js +4 -4
- package/dist/runtime/actors/actor-join-deferred-scope.d.ts +0 -1
- package/dist/runtime/actors/actor-join-deferred-scope.js +0 -18
- package/dist/runtime/actors/deferred-join-accepted-journal.js +2 -6
- package/dist/runtime/backend/contracts/index.d.ts +1 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +3 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +21 -8
- package/dist/runtime/channels/channel-dispatch-pipeline.js +2 -2
- package/dist/runtime/channels/channel-transports.js +3 -9
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +1 -0
- package/dist/runtime/channels/dispatch-error-reporter.js +6 -38
- package/dist/runtime/diagnostics/dispatch-error-details.d.ts +6 -0
- package/dist/runtime/diagnostics/dispatch-error-details.js +55 -0
- package/dist/runtime/diagnostics/flow-context.d.ts +2 -1
- package/dist/runtime/diagnostics/flow-context.js +2 -2
- package/dist/runtime/diagnostics/message-flow.js +11 -3
- package/dist/runtime/foundation/actor-join-recovery-codec.js +0 -4
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +4 -2
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +34 -9
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +1 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -0
- package/dist/runtime/foundation/service-stateful-runtime.js +46 -2
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -0
- package/dist/runtime/foundation/service-topology-registry.js +12 -4
- package/dist/runtime/host/index.js +1 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +20 -18
- package/dist/runtime/spots/index.js +1 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +6 -1
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-node-runtime-manager.js +5 -1
- package/dist/runtime/spots/spot-route-packet-dispatch.js +1 -1
- package/dist/runtime/spots/spot-routed-bound-session-dispatch.js +1 -1
- package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
- package/dist/runtime/spots/spot-timer.js +1 -1
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +21 -8
- package/dist/runtime/streams/actor-session-binding-registry.js +71 -42
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +1 -0
- package/dist/runtime/streams/bound-actor-relay-sender.js +2 -1
- package/dist/runtime/streams/bound-session-response-target.js +8 -1
- package/dist/runtime/streams/bound-session-service.d.ts +1 -0
- package/dist/runtime/streams/bound-session-service.js +6 -3
- package/dist/runtime/streams/index.js +8 -1
- package/dist/runtime/streams/managed-stream.d.ts +3 -0
- package/dist/runtime/streams/managed-stream.js +20 -1
- package/dist/runtime/streams/protocol.d.ts +5 -1
- package/dist/runtime/streams/protocol.js +41 -4
- package/dist/runtime/streams/session-actor-coordinator.js +3 -4
- package/dist/runtime/streams/session-context.d.ts +9 -2
- package/dist/runtime/streams/session-context.js +20 -4
- package/dist/runtime/streams/session-local-actors.d.ts +3 -1
- package/dist/runtime/streams/session-local-actors.js +17 -2
- package/dist/runtime/streams/stream-frame-factory.d.ts +1 -1
- package/dist/runtime/streams/stream-frame-factory.js +3 -2
- package/dist/runtime/streams/stream-session-runtime.js +42 -12
- package/package.json +3 -3
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +1 -0
- package/src/contracts/Streams/IZLinkSession.ts +2 -1
- package/src/runtime/actors/actor-context.ts +4 -4
- package/src/runtime/actors/actor-join-deferred-scope.ts +0 -32
- package/src/runtime/actors/deferred-join-accepted-journal.ts +2 -6
- package/src/runtime/backend/contracts/index.ts +4 -0
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +39 -11
- package/src/runtime/channels/channel-dispatch-pipeline.ts +4 -2
- package/src/runtime/channels/channel-transports.ts +3 -9
- package/src/runtime/channels/dispatch-error-reporter.ts +7 -45
- package/src/runtime/diagnostics/dispatch-error-details.ts +62 -0
- package/src/runtime/diagnostics/flow-context.ts +6 -4
- package/src/runtime/diagnostics/message-flow.ts +12 -3
- package/src/runtime/foundation/actor-join-recovery-codec.ts +0 -4
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +54 -13
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +1 -0
- package/src/runtime/foundation/service-stateful-runtime.ts +64 -5
- package/src/runtime/foundation/service-topology-registry.ts +18 -5
- package/src/runtime/host/index.ts +1 -1
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +18 -17
- package/src/runtime/spots/index.ts +2 -1
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +20 -3
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +5 -1
- package/src/runtime/spots/spot-route-packet-dispatch.ts +2 -1
- package/src/runtime/spots/spot-routed-bound-session-dispatch.ts +2 -1
- package/src/runtime/spots/spot-subscription-dispatch.ts +2 -1
- package/src/runtime/spots/spot-timer.ts +6 -1
- package/src/runtime/streams/actor-session-binding-registry.ts +150 -63
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +1 -0
- package/src/runtime/streams/bound-actor-relay-sender.ts +10 -2
- package/src/runtime/streams/bound-session-response-target.ts +10 -1
- package/src/runtime/streams/bound-session-service.ts +13 -3
- package/src/runtime/streams/index.ts +8 -1
- package/src/runtime/streams/managed-stream.ts +34 -12
- package/src/runtime/streams/protocol.ts +44 -5
- package/src/runtime/streams/session-actor-coordinator.ts +12 -4
- package/src/runtime/streams/session-context.ts +31 -4
- package/src/runtime/streams/session-local-actors.ts +19 -3
- package/src/runtime/streams/stream-frame-factory.ts +4 -2
- package/src/runtime/streams/stream-session-runtime.ts +58 -13
|
@@ -303,9 +303,10 @@ class RawServiceMeshRuntime {
|
|
|
303
303
|
return this.send(targetNodeRoutingId, [(0, service_wire_m6a_codec_1.encodeNodeSendHeader)(), this.applicationFrame(payload)]);
|
|
304
304
|
}
|
|
305
305
|
async sendToChannel(channelName, payload) {
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
return
|
|
306
|
+
const selection = this.selectChannelTarget(channelName);
|
|
307
|
+
if (selection.kind !== 'selected')
|
|
308
|
+
return selection.submitResult;
|
|
309
|
+
const selected = selection.peer;
|
|
309
310
|
const applicationFrame = this.applicationFrame(payload);
|
|
310
311
|
if (selected.descriptor.nodeRoutingId === this.descriptor.nodeRoutingId) {
|
|
311
312
|
const applicationJobOwner = await this.reserveLocalIngress();
|
|
@@ -320,25 +321,49 @@ class RawServiceMeshRuntime {
|
|
|
320
321
|
});
|
|
321
322
|
if (!accepted)
|
|
322
323
|
applicationJob.close();
|
|
323
|
-
return accepted;
|
|
324
|
+
return accepted ? runtime_values_1.SubmitResult.Ok : runtime_values_1.SubmitResult.NotAdmitted;
|
|
324
325
|
}
|
|
325
326
|
finally {
|
|
326
327
|
applicationJobOwner.close();
|
|
327
328
|
}
|
|
328
329
|
}
|
|
329
|
-
return this.send(selected.descriptor.nodeRoutingId, [
|
|
330
|
+
return (await this.send(selected.descriptor.nodeRoutingId, [
|
|
330
331
|
(0, service_wire_m6a_codec_1.encodeChannelSendHeader)(channelName),
|
|
331
332
|
applicationFrame
|
|
332
|
-
])
|
|
333
|
+
]))
|
|
334
|
+
? runtime_values_1.SubmitResult.Ok
|
|
335
|
+
: runtime_values_1.SubmitResult.NotConnected;
|
|
333
336
|
}
|
|
334
337
|
requestToNode(targetNodeRoutingId, payload, timeoutMs) {
|
|
335
338
|
return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs);
|
|
336
339
|
}
|
|
337
340
|
requestToChannel(channelName, payload, timeoutMs) {
|
|
341
|
+
const selection = this.selectChannelTarget(channelName);
|
|
342
|
+
if (selection.kind !== 'selected') {
|
|
343
|
+
const pending = this.operations.register(timeoutMs);
|
|
344
|
+
this.operations.complete(pending.id, selection.requestResult);
|
|
345
|
+
return pending;
|
|
346
|
+
}
|
|
347
|
+
return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName);
|
|
348
|
+
}
|
|
349
|
+
selectChannelTarget(channelName) {
|
|
338
350
|
const selected = this.topology.selectChannel(channelName, (peer) => this.isLocalOrReadyPeer(peer.descriptor.nodeRoutingId));
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
351
|
+
if (selected !== undefined)
|
|
352
|
+
return { kind: 'selected', peer: selected };
|
|
353
|
+
return this.topology.hasKnownChannelTarget(channelName)
|
|
354
|
+
? {
|
|
355
|
+
kind: 'knownButNotReady',
|
|
356
|
+
submitResult: runtime_values_1.SubmitResult.NotConnected,
|
|
357
|
+
requestResult: { terminalResult: runtime_values_1.RequestResult.NotConnected, failureCode: 0 }
|
|
358
|
+
}
|
|
359
|
+
: {
|
|
360
|
+
kind: 'noMember',
|
|
361
|
+
submitResult: runtime_values_1.SubmitResult.NotFound,
|
|
362
|
+
requestResult: {
|
|
363
|
+
terminalResult: runtime_values_1.RequestResult.NotFound,
|
|
364
|
+
failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
|
|
365
|
+
}
|
|
366
|
+
};
|
|
342
367
|
}
|
|
343
368
|
isLocalOrReadyPeer(nodeRoutingId) {
|
|
344
369
|
return nodeRoutingId === this.descriptor.nodeRoutingId || this.isPeerRouteReady(nodeRoutingId);
|
|
@@ -16,6 +16,7 @@ export interface ServiceSessionBindingAdmissionClaim {
|
|
|
16
16
|
}
|
|
17
17
|
export type ServiceSessionBindingAdmissionResult = 'passThrough' | 'retained' | 'rejected';
|
|
18
18
|
export interface ServiceSessionBindingIngressPort {
|
|
19
|
+
actorSlot(actorId: string, sessionRid: string): Promise<number | undefined>;
|
|
19
20
|
retainOutbound(claim: ServiceSessionBindingAdmissionClaim, delivery: ServiceSessionBindingRetainedDelivery): Promise<ServiceSessionBindingAdmissionResult>;
|
|
20
21
|
clearOutbound(actorId: string, error: unknown): Promise<void>;
|
|
21
22
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ZLinkDispatchErrorReporter } from '../channels/dispatch-error-reporter';
|
|
1
2
|
import type { RawServiceMeshRuntime } from './raw-service-mesh-runtime';
|
|
2
3
|
import { type ReceiveKindData, type StreamSessionActorAuthorityFence } from './service-runtime-contracts';
|
|
3
4
|
import type { ServiceMailboxRecord } from './service-mailbox';
|
|
@@ -221,6 +222,8 @@ export declare class ServiceStatefulRuntime {
|
|
|
221
222
|
private userSpotOperationHandler?;
|
|
222
223
|
private messageFollowHandler?;
|
|
223
224
|
private mailboxDropHandler?;
|
|
225
|
+
private dispatchErrors?;
|
|
226
|
+
private dispatchErrorMeshName?;
|
|
224
227
|
private readonly admittedUserSpotOperations;
|
|
225
228
|
private readonly pendingInstanceActivations;
|
|
226
229
|
private closed;
|
|
@@ -229,6 +232,7 @@ export declare class ServiceStatefulRuntime {
|
|
|
229
232
|
readonly kind: 'spot_multicast' | 'actor_control' | 'actor_binding';
|
|
230
233
|
readonly owner: string;
|
|
231
234
|
}) => void): void;
|
|
235
|
+
setDispatchErrorReporter(reporter: ZLinkDispatchErrorReporter, meshName: string): void;
|
|
232
236
|
createSpot(routingId?: string, kind?: 'user' | 'instance', stableType?: "user" | "instance"): ServiceSpotState;
|
|
233
237
|
restoreUserSpotAuthority(spotId: string, stableType: string, generation: bigint, authorityOwnerGeneration: bigint): ServiceSpotState;
|
|
234
238
|
restoreSpotAuthority(spotId: string, objectKind: 'user_spot' | 'instance_spot', stableType: string, generation: bigint, authorityOwnerGeneration: bigint): ServiceSpotState;
|
|
@@ -7,6 +7,7 @@ const abort_1 = require("../abort");
|
|
|
7
7
|
const execution_1 = require("../execution");
|
|
8
8
|
const framework_errors_internal_1 = require("../framework-errors-internal");
|
|
9
9
|
const runtime_values_1 = require("../backend/runtime-values");
|
|
10
|
+
const ZLinkDispatchOptions_1 = require("../../contracts/Dispatch/ZLinkDispatchOptions");
|
|
10
11
|
const service_runtime_contracts_1 = require("./service-runtime-contracts");
|
|
11
12
|
const message_follow_suppression_registry_1 = require("./message-follow-suppression-registry");
|
|
12
13
|
const service_stateful_registry_1 = require("./service-stateful-registry");
|
|
@@ -81,6 +82,8 @@ class ServiceStatefulRuntime {
|
|
|
81
82
|
userSpotOperationHandler;
|
|
82
83
|
messageFollowHandler;
|
|
83
84
|
mailboxDropHandler;
|
|
85
|
+
dispatchErrors;
|
|
86
|
+
dispatchErrorMeshName;
|
|
84
87
|
admittedUserSpotOperations = new Map();
|
|
85
88
|
pendingInstanceActivations = new Map();
|
|
86
89
|
closed = false;
|
|
@@ -95,6 +98,10 @@ class ServiceStatefulRuntime {
|
|
|
95
98
|
setMailboxDropHandler(handler) {
|
|
96
99
|
this.mailboxDropHandler = handler;
|
|
97
100
|
}
|
|
101
|
+
setDispatchErrorReporter(reporter, meshName) {
|
|
102
|
+
this.dispatchErrors = reporter;
|
|
103
|
+
this.dispatchErrorMeshName = meshName;
|
|
104
|
+
}
|
|
98
105
|
createSpot(routingId, kind = 'user', stableType = kind) {
|
|
99
106
|
this.requireOpen();
|
|
100
107
|
return this.registry.createSpot(routingId ?? `spot-${this.nodeRid}-${this.nextSpotId++}`, kind, stableType);
|
|
@@ -623,13 +630,32 @@ class ServiceStatefulRuntime {
|
|
|
623
630
|
await this.enqueueLogicalMulticast(channelName, topic, sourceSpotId, payload);
|
|
624
631
|
const targets = this.raw.topology
|
|
625
632
|
.peers()
|
|
626
|
-
.filter((peer) => peer.descriptor.channels.some((channel) => channel.name === channelName && channel.weight > 0));
|
|
633
|
+
.filter((peer) => peer.descriptor.channels.some((channel) => channel.name === channelName && channel.weight > 0) && this.raw.isPeerRouteReady(peer.descriptor.nodeRoutingId));
|
|
627
634
|
const header = (0, service_stateful_wire_codec_1.encodeLogicalMulticastHeader)(channelName, topic, sourceSpotId);
|
|
628
635
|
const payloadFrame = (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload);
|
|
636
|
+
const reporter = this.dispatchErrors;
|
|
637
|
+
const captureFailures = reporter?.captureEnabled() === true;
|
|
629
638
|
for (const target of targets) {
|
|
630
639
|
// Remote admission ends at the source outbound transport queue. The
|
|
631
640
|
// receiver's Spot queue and handler completion are not publish results.
|
|
632
|
-
await this.raw.sendService(target.descriptor.nodeRoutingId, [
|
|
641
|
+
const accepted = await this.raw.sendService(target.descriptor.nodeRoutingId, [
|
|
642
|
+
header,
|
|
643
|
+
payloadFrame
|
|
644
|
+
]);
|
|
645
|
+
if (!accepted) {
|
|
646
|
+
if (captureFailures) {
|
|
647
|
+
reporter.report({
|
|
648
|
+
surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.SpotRoute,
|
|
649
|
+
messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
|
|
650
|
+
reason: serviceSpotPublishFailureReason(undefined, this.raw.isPeerRouteReady(target.descriptor.nodeRoutingId), this.closed),
|
|
651
|
+
action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.Drop,
|
|
652
|
+
meshName: this.dispatchErrorMeshName,
|
|
653
|
+
channelName,
|
|
654
|
+
topic,
|
|
655
|
+
targetRid: target.descriptor.nodeRoutingId
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
633
659
|
}
|
|
634
660
|
}
|
|
635
661
|
async sendToSpot(sourceSpotId, requested, payload) {
|
|
@@ -3504,6 +3530,24 @@ class ServiceStatefulRuntime {
|
|
|
3504
3530
|
}
|
|
3505
3531
|
}
|
|
3506
3532
|
exports.ServiceStatefulRuntime = ServiceStatefulRuntime;
|
|
3533
|
+
function serviceSpotPublishFailureReason(result, routeReady, closed) {
|
|
3534
|
+
if (closed || result === runtime_values_1.SubmitResult.Terminated)
|
|
3535
|
+
return 'shutdown';
|
|
3536
|
+
switch (result) {
|
|
3537
|
+
case runtime_values_1.SubmitResult.Backpressured:
|
|
3538
|
+
return 'backpressure';
|
|
3539
|
+
case runtime_values_1.SubmitResult.NotAdmitted:
|
|
3540
|
+
case runtime_values_1.SubmitResult.NotConnected:
|
|
3541
|
+
case runtime_values_1.SubmitResult.NotFound:
|
|
3542
|
+
case runtime_values_1.SubmitResult.InvalidHandle:
|
|
3543
|
+
return 'stale_target';
|
|
3544
|
+
default:
|
|
3545
|
+
// RawServiceMeshRuntime exposes failed Core submissions as false. A
|
|
3546
|
+
// ready route therefore identifies queue admission failure; a route
|
|
3547
|
+
// that became unready after selection is a stale target.
|
|
3548
|
+
return routeReady ? 'backpressure' : 'stale_target';
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3507
3551
|
function isEntrySpotFence(fence) {
|
|
3508
3552
|
return (fence.spot.spotId === fence.targetNodeRid &&
|
|
3509
3553
|
fence.spot.generation === fence.targetNodeGeneration &&
|
|
@@ -55,6 +55,7 @@ export declare class ServiceTopologyRegistry {
|
|
|
55
55
|
markNotRequired(descriptor: ServiceNodeDescriptor): void;
|
|
56
56
|
forgetNotRequired(nodeRoutingId: string): void;
|
|
57
57
|
knownDescriptor(nodeRoutingId: string): ServiceNodeDescriptor | undefined;
|
|
58
|
+
hasKnownChannelTarget(channelName: string): boolean;
|
|
58
59
|
private remember;
|
|
59
60
|
selectChannel(channelName: string, isReady?: (peer: AdmittedServicePeer) => boolean): AdmittedServicePeer | undefined;
|
|
60
61
|
selectPlacement(isReady?: (peer: AdmittedServicePeer) => boolean): AdmittedServicePeer | undefined;
|
|
@@ -170,6 +170,10 @@ class ServiceTopologyRegistry {
|
|
|
170
170
|
const descriptor = admitted ?? this.notRequiredByRid.get(nodeRoutingId) ?? this.knownByRid.get(nodeRoutingId);
|
|
171
171
|
return descriptor === undefined ? undefined : cloneDescriptor(descriptor);
|
|
172
172
|
}
|
|
173
|
+
hasKnownChannelTarget(channelName) {
|
|
174
|
+
requireText(channelName, 'channelName');
|
|
175
|
+
return [this.local, ...this.knownByRid.values()].some((descriptor) => selectableChannel(descriptor, channelName) !== undefined);
|
|
176
|
+
}
|
|
173
177
|
remember(descriptor) {
|
|
174
178
|
const current = this.knownByRid.get(descriptor.nodeRoutingId);
|
|
175
179
|
if (current === undefined ||
|
|
@@ -190,11 +194,9 @@ class ServiceTopologyRegistry {
|
|
|
190
194
|
return [local, ...this.peersByRid.values()]
|
|
191
195
|
.map((peer) => ({
|
|
192
196
|
peer: clonePeer(peer),
|
|
193
|
-
channel:
|
|
197
|
+
channel: selectableChannel(peer.descriptor, channelName)
|
|
194
198
|
}))
|
|
195
|
-
.filter((value) => value.channel !== undefined
|
|
196
|
-
value.peer.descriptor.state === 'serving' &&
|
|
197
|
-
value.channel.weight > 0);
|
|
199
|
+
.filter((value) => value.channel !== undefined);
|
|
198
200
|
}, (value) => value.channel.weight, (value) => value.peer.descriptor.nodeRoutingId, (left, right) => compareOrdinal(left.peer.descriptor.nodeRoutingId, right.peer.descriptor.nodeRoutingId), (value) => isReady(value.peer))?.peer;
|
|
199
201
|
}
|
|
200
202
|
selectPlacement(isReady = () => true) {
|
|
@@ -338,6 +340,12 @@ function validateSortedUnique(values, key, field) {
|
|
|
338
340
|
function findChannel(descriptor, channelName) {
|
|
339
341
|
return descriptor.channels.find((channel) => channel.name === channelName);
|
|
340
342
|
}
|
|
343
|
+
function selectableChannel(descriptor, channelName) {
|
|
344
|
+
if (descriptor.state !== 'serving')
|
|
345
|
+
return undefined;
|
|
346
|
+
const channel = findChannel(descriptor, channelName);
|
|
347
|
+
return channel !== undefined && channel.weight > 0 ? channel : undefined;
|
|
348
|
+
}
|
|
341
349
|
function requireText(value, field) {
|
|
342
350
|
if (value.length === 0 || value.includes('\0')) {
|
|
343
351
|
throw new TypeError(`${field} must be non-empty text without NUL.`);
|
|
@@ -2178,7 +2178,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
2178
2178
|
const current = (0, diagnostics_1.currentOrCreateFlow)('Lifecycle', false);
|
|
2179
2179
|
const flow = current?.flowOrigin === 'Lifecycle'
|
|
2180
2180
|
? current
|
|
2181
|
-
: (0, diagnostics_1.createInboundFlow)(undefined, 'Lifecycle', this.flowCreationEnabled());
|
|
2181
|
+
: (0, diagnostics_1.createInboundFlow)(undefined, 'Lifecycle', this.flowCreationEnabled(), undefined);
|
|
2182
2182
|
return (0, diagnostics_1.runWithFlow)(flow, operation);
|
|
2183
2183
|
}
|
|
2184
2184
|
requirePrimaryMeshNode() {
|
|
@@ -66,22 +66,24 @@ function read64(bytes, at) { if (at.value + 8 > bytes.length)
|
|
|
66
66
|
r = (r << 8n) | BigInt(bytes[at.value++]); return r; }
|
|
67
67
|
function u32(out, value) { if (!Number.isInteger(value) || value < 0 || value > 0xffffffff)
|
|
68
68
|
throw new RangeError("u32"); out.push(value >>> 24, (value >>> 16) & 255, (value >>> 8) & 255, value & 255); }
|
|
69
|
+
function appendBytes(out, bytes) { for (const byte of bytes)
|
|
70
|
+
out.push(byte); }
|
|
69
71
|
function read32(bytes, at) { if (at.value + 4 > bytes.length)
|
|
70
72
|
throw new RangeError("truncated u32"); return ((bytes[at.value++] << 24) | (bytes[at.value++] << 16) | (bytes[at.value++] << 8) | bytes[at.value++]) >>> 0; }
|
|
71
73
|
function text8(out, value) { const b = text.encode(value); if (b.length === 0 || b.length > 255 || b.includes(0))
|
|
72
|
-
throw new RangeError("text8"); out.push(b.length,
|
|
74
|
+
throw new RangeError("text8"); out.push(b.length); appendBytes(out, b); }
|
|
73
75
|
function readText8(bytes, at) { const n = bytes[at.value++]; if (n === 0 || at.value + n > bytes.length)
|
|
74
76
|
throw new RangeError("truncated text8"); const b = bytes.slice(at.value, at.value + n); at.value += n; if (b.includes(0))
|
|
75
77
|
throw new RangeError("text8 NUL"); return decodeText.decode(b); }
|
|
76
78
|
function rid(out, value) { if (value.length === 0 || value.length > 255)
|
|
77
|
-
throw new RangeError("rid"); out.push(value.length,
|
|
79
|
+
throw new RangeError("rid"); out.push(value.length); appendBytes(out, value); }
|
|
78
80
|
function readRid(bytes, at) { const n = bytes[at.value++]; if (n === 0 || at.value + n > bytes.length)
|
|
79
81
|
throw new RangeError("truncated rid"); const r = bytes.slice(at.value, at.value + n); at.value += n; return r; }
|
|
80
82
|
function fence(out, value) { if (value.generation === 0n || value.targetNodeGeneration === 0n || value.expectedAuthorityOwnerGeneration === 0n || value.expectedOwnerLeaseGeneration === 0n)
|
|
81
83
|
throw new RangeError("invalid fence"); text8(out, value.id); u64(out, value.generation); rid(out, value.targetNodeRid); u64(out, value.targetNodeGeneration); u64(out, value.expectedAuthorityOwnerGeneration); u64(out, value.expectedOwnerLeaseGeneration); }
|
|
82
84
|
function readFence(bytes, at) { const value = { id: readText8(bytes, at), generation: read64(bytes, at), targetNodeRid: readRid(bytes, at), targetNodeGeneration: read64(bytes, at), expectedAuthorityOwnerGeneration: read64(bytes, at), expectedOwnerLeaseGeneration: read64(bytes, at) }; if (value.generation === 0n || value.targetNodeGeneration === 0n || value.expectedAuthorityOwnerGeneration === 0n || value.expectedOwnerLeaseGeneration === 0n)
|
|
83
85
|
throw new RangeError("invalid fence"); return value; }
|
|
84
|
-
function encodePayload(value) { const body = []; text8(body, value.packetName); text8(body, value.contentType); u32(body, value.payload.length); body
|
|
86
|
+
function encodePayload(value) { const body = []; text8(body, value.packetName); text8(body, value.contentType); u32(body, value.payload.length); appendBytes(body, value.payload); const out = [1]; u32(out, body.length); appendBytes(out, body); return Uint8Array.from(out); }
|
|
85
87
|
function decodePayload(bytes) { const at = { value: 0 }; if (bytes[at.value++] !== 1)
|
|
86
88
|
throw new RangeError("payload version"); const length = read32(bytes, at); if (length !== bytes.length - at.value)
|
|
87
89
|
throw new RangeError("payload length"); const end = bytes.length; const packetName = readText8(bytes, at); const contentType = readText8(bytes, at); const length2 = read32(bytes, at); if (length2 !== end - at.value)
|
|
@@ -93,10 +95,10 @@ function decodeActorJoin28(frames) { if (frames.length < 1 || frames.length > 2)
|
|
|
93
95
|
throw new RangeError("actorJoin frames"); const bytes = frames[0]; const at = { value: 0 }; if (bytes.length < 5 || bytes[at.value++] !== 90 || bytes[at.value++] !== 77 || bytes[at.value++] !== 1 || bytes[at.value++] !== 28 || bytes[at.value++] !== 0)
|
|
94
96
|
throw new RangeError("actorJoin header"); const correlation = read64(bytes, at); const actor = readFence(bytes, at); const entry = bytes[at.value++]; const targetSpot = readFence(bytes, at); if (correlation === 0n || entry > 1 || at.value !== bytes.length)
|
|
95
97
|
throw new RangeError("actorJoin body"); const payload = frames.length === 2 ? decodePayload(frames[1]) : undefined; return payload === undefined ? { correlation, actor, entry: entry === 1, targetSpot } : { correlation, actor, entry: entry === 1, targetSpot, payload }; }
|
|
96
|
-
function bytes64(out, v) { u64(out, BigInt(v.length)); out
|
|
98
|
+
function bytes64(out, v) { u64(out, BigInt(v.length)); appendBytes(out, v); }
|
|
97
99
|
function body16(out, write) { const b = []; write(b); if (b.length > 65535)
|
|
98
|
-
throw new RangeError("body16"); out.push(b.length >>> 8, b.length & 255,
|
|
99
|
-
function body64(out, write) { const b = []; write(b); u64(out, BigInt(b.length)); out
|
|
100
|
+
throw new RangeError("body16"); out.push(b.length >>> 8, b.length & 255); appendBytes(out, b); }
|
|
101
|
+
function body64(out, write) { const b = []; write(b); u64(out, BigInt(b.length)); appendBytes(out, b); }
|
|
100
102
|
function sorted(v, compare, name) { for (let i = 1; i < v.length; i++)
|
|
101
103
|
if (compare(v[i - 1], v[i]) >= 0)
|
|
102
104
|
throw new RangeError(name); }
|
|
@@ -112,7 +114,7 @@ function readText16(bytes, at, minimum, maximum, name) { const n = read16(bytes,
|
|
|
112
114
|
throw new RangeError(name); const b = take(bytes, at, n, name); if (b.includes(0))
|
|
113
115
|
throw new RangeError(name + " NUL"); return decodeText.decode(b); }
|
|
114
116
|
function writeText16(out, value, minimum, maximum, name) { const b = text.encode(value); if (b.length < minimum || b.length > maximum || b.includes(0))
|
|
115
|
-
throw new RangeError(name); out.push(b.length >>> 8, b.length & 255,
|
|
117
|
+
throw new RangeError(name); out.push(b.length >>> 8, b.length & 255); appendBytes(out, b); }
|
|
116
118
|
function boundedEnd(bytes, at, length, name) { if (at.value + length > bytes.length)
|
|
117
119
|
throw new RangeError("truncated " + name); return at.value + length; }
|
|
118
120
|
function exactEnd(at, end, name) { if (at.value !== end)
|
|
@@ -305,7 +307,7 @@ function encodeRelocationEnvelopeV1(value) { const out = []; if (value.relocatio
|
|
|
305
307
|
exactEnd(at, w.frozenRecord.length, "frozen record");
|
|
306
308
|
u64(out, w.participantId);
|
|
307
309
|
u64(out, w.order);
|
|
308
|
-
out
|
|
310
|
+
appendBytes(out, w.frozenRecord);
|
|
309
311
|
} sorted(value.timerRegistrations, (a, b) => a.participantId === b.participantId ? compareUtf8(a.name, b.name) : a.participantId < b.participantId ? -1 : 1, "timerRegistrations"); u32(out, value.timerRegistrations.length); for (const t of value.timerRegistrations) {
|
|
310
312
|
if (t.participantId === 0n || t.periodMilliseconds === 0n || t.maxCatchUpTicks === 0n || t.overrunPolicy < 1 || t.overrunPolicy > 3)
|
|
311
313
|
throw new RangeError("timer");
|
|
@@ -385,17 +387,17 @@ function crc32c(bytes) { let crc = 0xffffffff; for (const octet of bytes) {
|
|
|
385
387
|
for (let bit = 0; bit < 8; bit++)
|
|
386
388
|
crc = (crc >>> 1) ^ ((crc & 1) !== 0 ? 0x82f63b78 : 0);
|
|
387
389
|
} return (~crc) >>> 0; }
|
|
388
|
-
function encodeDurable(magic, body, maximum) { const out = [...magic, 1, 0, 0]; u32(out, body.length); out
|
|
390
|
+
function encodeDurable(magic, body, maximum) { const out = [...magic, 1, 0, 0]; u32(out, body.length); appendBytes(out, body); if (out.length + 4 > maximum)
|
|
389
391
|
throw new RangeError("durable format bytes"); u32(out, crc32c(Uint8Array.from(out))); return Uint8Array.from(out); }
|
|
390
392
|
function decodeDurable(bytes, magic, maximum) { if (bytes.length > maximum || bytes.length < 15 || magic.some((v, i) => bytes[i] !== v) || bytes[4] !== 1 || bytes[5] !== 0 || bytes[6] !== 0)
|
|
391
393
|
throw new RangeError("durable header"); const at = { value: 7 }, length = read32(bytes, at), end = boundedEnd(bytes, at, length, "durable body"); if (end + 4 !== bytes.length)
|
|
392
394
|
throw new RangeError("durable length"); const body = bytes.slice(at.value, end); at.value = end; const expected = read32(bytes, at); if (crc32c(bytes.slice(0, end)) !== expected)
|
|
393
395
|
throw new RangeError("durable checksum"); return body; }
|
|
394
396
|
function encodeRelocationDataChunkV1(value) { const body = []; u32(body, value.order); if (value.data.length > 67108864)
|
|
395
|
-
throw new RangeError("chunk data"); u32(body, value.data.length); body
|
|
397
|
+
throw new RangeError("chunk data"); u32(body, value.data.length); appendBytes(body, value.data); return encodeDurable([90, 76, 84, 67], body, 67108886); }
|
|
396
398
|
function decodeRelocationDataChunkV1(bytes) { const body = decodeDurable(bytes, [90, 76, 84, 67], 67108886), at = { value: 0 }, order = read32(body, at), data = take(body, at, read32(body, at), "chunk data"); exactEnd(at, body.length, "chunk"); return { order, data }; }
|
|
397
399
|
function encodeRelocationManifestV1(value) { if (Number(value.logicalFormatVersion) !== 1 || value.totalLength > 274877906944n || value.inventoryDigestSha256.length !== 32 || value.chunks.length > 4096)
|
|
398
|
-
throw new RangeError("manifest"); sorted(value.chunks, (a, b) => a.order - b.order, "manifest chunks"); const body = [1]; u64(body, value.totalLength); u32(body, value.totalChecksumCrc32c); body.push(32,
|
|
400
|
+
throw new RangeError("manifest"); sorted(value.chunks, (a, b) => a.order - b.order, "manifest chunks"); const body = [1]; u64(body, value.totalLength); u32(body, value.totalChecksumCrc32c); body.push(32); appendBytes(body, value.inventoryDigestSha256); u32(body, value.chunks.length); for (const chunk of value.chunks) {
|
|
399
401
|
if (chunk.length === 0n)
|
|
400
402
|
throw new RangeError("chunk length");
|
|
401
403
|
u32(body, chunk.order);
|
|
@@ -568,14 +570,14 @@ function b3WriteSourceBase(o, v) { b3WriteId(o, v.relocation, "relocation"); if
|
|
|
568
570
|
throw new RangeError("sender role"); writeRelocationObject(o, v.object); }
|
|
569
571
|
function b3ReadSourceBase(bytes, at) { const relocation = b3ReadId(bytes, at, "relocation"), targetAttemptGeneration = nonzero64(bytes, at, "target attempt"), coordinator = b3ReadCoordinator(bytes, at), senderRole = b3ReadRole(bytes, at); if (senderRole !== "source")
|
|
570
572
|
throw new RangeError("sender role"); return { relocation, targetAttemptGeneration, coordinator, senderRole, object: readRelocationObject(bytes, at) }; }
|
|
571
|
-
function encodeRelocationData31(v) { const o = b3Header(31); b3WriteSourceBase(o, v); const at = { value: 0 }; skipFrozenRecord(v.record, at); exactEnd(at, v.record.length, "frozen record"); o
|
|
573
|
+
function encodeRelocationData31(v) { const o = b3Header(31); b3WriteSourceBase(o, v); const at = { value: 0 }; skipFrozenRecord(v.record, at); exactEnd(at, v.record.length, "frozen record"); appendBytes(o, v.record); return Uint8Array.from(o); }
|
|
572
574
|
function decodeRelocationData31(bytes) { const at = b3ReadHeader(bytes, 31, "relocationData"), v = b3ReadSourceBase(bytes, at), start = at.value; skipFrozenRecord(bytes, at); const record = bytes.slice(start, at.value); b3Finish(at, bytes, "relocationData"); return { ...v, record }; }
|
|
573
575
|
function encodeRelocationCutover34(v) { const o = b3Header(34); b3WriteSourceBase(o, v); if (v.boundaryRecordCount < 0n || v.boundaryRecordCount > 9223372036854775807n)
|
|
574
576
|
throw new RangeError("boundary count"); u64(o, v.boundaryRecordCount); u32(o, v.boundaryChecksumCrc32c); return Uint8Array.from(o); }
|
|
575
577
|
function decodeRelocationCutover34(bytes) { const at = b3ReadHeader(bytes, 34, "relocationCutover"), v = b3ReadSourceBase(bytes, at), boundaryRecordCount = read64(bytes, at); if (boundaryRecordCount > 9223372036854775807n)
|
|
576
578
|
throw new RangeError("boundary count"); const boundaryChecksumCrc32c = read32(bytes, at); b3Finish(at, bytes, "relocationCutover"); return { ...v, boundaryRecordCount, boundaryChecksumCrc32c }; }
|
|
577
579
|
function encodeRelocationState52(v) { const o = b3Header(52); b3WriteSourceBase(o, v); if (v.chunkData.length > 67108864)
|
|
578
|
-
throw new RangeError("chunk data"); u32(o, v.chunkOrdinal); u32(o, v.chunkData.length); o
|
|
580
|
+
throw new RangeError("chunk data"); u32(o, v.chunkOrdinal); u32(o, v.chunkData.length); appendBytes(o, v.chunkData); return Uint8Array.from(o); }
|
|
579
581
|
function decodeRelocationState52(bytes) { const at = b3ReadHeader(bytes, 52, "relocationState"), v = b3ReadSourceBase(bytes, at), chunkOrdinal = read32(bytes, at), length = read32(bytes, at); if (length > 67108864)
|
|
580
582
|
throw new RangeError("chunk data"); const chunkData = take(bytes, at, length, "chunk data"); b3Finish(at, bytes, "relocationState"); return { ...v, chunkOrdinal, chunkData }; }
|
|
581
583
|
function encodeRelocationPrepare40(v) { const o = b3Header(40); b3WriteId(o, v.relocation, "relocation"); if (v.targetAttemptGeneration === 0n || v.sourceNodeGeneration === 0n)
|
|
@@ -615,7 +617,7 @@ function b4ReadReservation(bytes, at) { return { reservationId: readText8(bytes,
|
|
|
615
617
|
throw new RangeError("pending capacity"); return v; })() }; }
|
|
616
618
|
function b4Close(out, v) { const body = []; text8(body, v.spotId); if (v.objectGeneration === 0n || v.targetNodeGeneration === 0n || v.expectedAuthorityOwnerGeneration === 0n)
|
|
617
619
|
throw new RangeError("close fence"); u64(body, v.objectGeneration); rid(body, v.targetNodeRid); u64(body, v.targetNodeGeneration); u64(body, v.expectedAuthorityOwnerGeneration); writeText16(body, v.expectedStoreVersion, 1, 4096, "store version"); out.push(1); if (body.length > 65535)
|
|
618
|
-
throw new RangeError("close fence"); out.push(body.length >>> 8, body.length & 255,
|
|
620
|
+
throw new RangeError("close fence"); out.push(body.length >>> 8, body.length & 255); appendBytes(out, body); }
|
|
619
621
|
function b4ReadClose(bytes, at) { if (read8(bytes, at) !== 1)
|
|
620
622
|
throw new RangeError("close fence version"); const end = boundedEnd(bytes, at, read16(bytes, at), "close fence"); const value = { spotId: readText8(bytes, at), objectGeneration: nonzero64(bytes, at, "object generation"), targetNodeRid: readRid(bytes, at), targetNodeGeneration: nonzero64(bytes, at, "target node generation"), expectedAuthorityOwnerGeneration: nonzero64(bytes, at, "authority generation"), expectedStoreVersion: readText16(bytes, at, 1, 4096, "store version") }; exactEnd(at, end, "close fence"); return value; }
|
|
621
623
|
function b4CommandBase(out, v) { if (v.correlation === 0n || v.sourceNodeGeneration === 0n)
|
|
@@ -630,14 +632,14 @@ function decodeUserSpotClose48(bytes) { const at = b4ReadHeader(bytes, 48, "user
|
|
|
630
632
|
function encodeActorCreate49(v) { const out = b4Header(49); b4CommandBase(out, v); text8(out, v.actorId); text8(out, v.stableType); b4Reservation(out, v.reservation); if (v.deadlineUnixMs === 0n)
|
|
631
633
|
throw new RangeError("deadline"); u64(out, v.deadlineUnixMs); return Uint8Array.from(out); }
|
|
632
634
|
function decodeActorCreate49(bytes) { const at = b4ReadHeader(bytes, 49, "actorCreate"), base = b4ReadCommandBase(bytes, at), actorId = readText8(bytes, at), stableType = readText8(bytes, at), reservation = b4ReadReservation(bytes, at), deadlineUnixMs = nonzero64(bytes, at, "deadline"); b4Finish(at, bytes, "actorCreate"); return { ...base, actorId, stableType, reservation, deadlineUnixMs }; }
|
|
633
|
-
function b4ZljrPayload(v) { if (v.metadata.length > 262144
|
|
634
|
-
throw new RangeError("ZLJR length"); const out = [90, 76, 74, 82, 1]; u32(out, v.metadata.length); u32(out, v.request.length); u32(out, v.reply.length); out
|
|
635
|
+
function b4ZljrPayload(v) { if (v.metadata.length > 262144)
|
|
636
|
+
throw new RangeError("ZLJR length"); const out = [90, 76, 74, 82, 1]; u32(out, v.metadata.length); u32(out, v.request.length); u32(out, v.reply.length); appendBytes(out, v.metadata); appendBytes(out, v.request); appendBytes(out, v.reply); return Uint8Array.from(out); }
|
|
635
637
|
function b4ReadZljrPayload(bytes) { const at = { value: 0 }; if (read32(bytes, at) !== 0x5a4c4a52 || read8(bytes, at) !== 1)
|
|
636
|
-
throw new RangeError("ZLJR header"); const metadataLength = read32(bytes, at), requestLength = read32(bytes, at), replyLength = read32(bytes, at); if (metadataLength > 262144
|
|
638
|
+
throw new RangeError("ZLJR header"); const metadataLength = read32(bytes, at), requestLength = read32(bytes, at), replyLength = read32(bytes, at); if (metadataLength > 262144)
|
|
637
639
|
throw new RangeError("ZLJR length"); const metadata = take(bytes, at, metadataLength, "ZLJR metadata"), request = take(bytes, at, requestLength, "ZLJR request"), reply = take(bytes, at, replyLength, "ZLJR reply"); b4Finish(at, bytes, "ZLJR"); return { metadata, request, reply }; }
|
|
638
640
|
function encodeZljrRecordV1(v) { if (v.source.nodeGeneration === 0n || v.source.ownerLeaseGeneration === 0n)
|
|
639
641
|
throw new RangeError("ZLJR record"); const source = []; rid(source, v.source.nodeRid); u64(source, v.source.nodeGeneration); text8(source, v.source.ownerId); u64(source, v.source.ownerLeaseGeneration); if (source.length > 65535)
|
|
640
|
-
throw new RangeError("ZLJR source"); const payload = b4ZljrPayload(v), body = []; text8(body, "__zlink.actor.routed_join.recovery"); text8(body, "application/x-zlink-actor-routed-join-recovery-v1"); u32(body, payload.length); body
|
|
642
|
+
throw new RangeError("ZLJR source"); const payload = b4ZljrPayload(v), body = []; text8(body, "__zlink.actor.routed_join.recovery"); text8(body, "application/x-zlink-actor-routed-join-recovery-v1"); u32(body, payload.length); appendBytes(body, payload); const out = [1, 1, source.length >>> 8, source.length & 255, ...source, 0]; u64(out, v.operation.high); u64(out, v.operation.low); u32(out, 0); out.push(0, 0, 1); u32(out, body.length); appendBytes(out, body); return Uint8Array.from(out); }
|
|
641
643
|
function decodeZljrRecordV1(bytes) { const at = { value: 0 }; if (read8(bytes, at) !== 1 || read8(bytes, at) !== 1)
|
|
642
644
|
throw new RangeError("ZLJR frozen record"); const sourceEnd = boundedEnd(bytes, at, read16(bytes, at), "ZLJR source"), nodeRid = readRid(bytes, at), nodeGeneration = nonzero64(bytes, at, "source node generation"), ownerId = readText8(bytes, at), ownerLeaseGeneration = nonzero64(bytes, at, "source owner lease"); exactEnd(at, sourceEnd, "ZLJR source"); if (read8(bytes, at) !== 0)
|
|
643
645
|
throw new RangeError("ZLJR metadata flag"); const operation = { high: read64(bytes, at), low: read64(bytes, at) }; if (read32(bytes, at) !== 0 || read16(bytes, at) !== 0 || read8(bytes, at) !== 1)
|
|
@@ -907,7 +907,7 @@ class DefaultZLinkSpotManager {
|
|
|
907
907
|
throw new configuration_1.ZLinkConfigurationException('MeshNode Instance Spot record is missing the owner Spot RID.');
|
|
908
908
|
}
|
|
909
909
|
const envelope = (0, channel_envelope_1.decodeChannelEnvelope)(record.parts, undefined, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true);
|
|
910
|
-
const inboundFlow = (0, diagnostics_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true);
|
|
910
|
+
const inboundFlow = (0, diagnostics_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, undefined);
|
|
911
911
|
await (0, diagnostics_1.runWithFlow)(inboundFlow, async () => {
|
|
912
912
|
const request = record.operationKind === service_runtime_contracts_1.OperationKind.InstanceSpotRequest;
|
|
913
913
|
this.traceInstanceMessage(ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Received, meshName, spotId, record, envelope, 'activating');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActorRef, ZLinkActor, ZLinkMessageSerializer, ZLinkSpot } from '../../contracts';
|
|
1
|
+
import type { ActorRef, RoutingId, ZLinkActor, ZLinkMessageSerializer, ZLinkSpot } from '../../contracts';
|
|
2
2
|
import type { Message } from '../../contracts/Common/Message';
|
|
3
3
|
import type { ZLinkRemoteBoundSessionTarget } from '../actors';
|
|
4
4
|
import { ZLinkSpotActorHandlerRegistryRuntime } from '../actors';
|
|
@@ -24,6 +24,7 @@ export interface ZLinkActorPacketDelivery {
|
|
|
24
24
|
readonly fallbackActorRef?: ActorRef;
|
|
25
25
|
readonly requestTerminal?: ZLinkActorRequestTerminal;
|
|
26
26
|
readonly messageFollowOrigin?: ZLinkMessageFollowOrigin;
|
|
27
|
+
readonly sourceSessionRid?: RoutingId;
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
30
|
* Spec 15 §4.2 relocation temporary queue: consulted when {@code
|
|
@@ -6,6 +6,7 @@ const contracts_1 = require("../../contracts");
|
|
|
6
6
|
const ZLinkDispatchOptions_1 = require("../../contracts/Dispatch/ZLinkDispatchOptions");
|
|
7
7
|
const diagnostics_1 = require("../diagnostics");
|
|
8
8
|
const flow_context_1 = require("../diagnostics/flow-context");
|
|
9
|
+
const managed_stream_1 = require("../streams/managed-stream");
|
|
9
10
|
const actors_1 = require("../actors");
|
|
10
11
|
const protocol_1 = require("../streams/protocol");
|
|
11
12
|
const payload_codec_1 = require("../messaging/payload-codec");
|
|
@@ -48,7 +49,11 @@ class ZLinkSpotActorPacketDispatch {
|
|
|
48
49
|
this.reportInvalidFrame(actorId, ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.ActorSend, error);
|
|
49
50
|
throw error;
|
|
50
51
|
}
|
|
51
|
-
return (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(header.flowId, header.flowOrigin, flowEnabled
|
|
52
|
+
return (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(header.flowId, header.flowOrigin, flowEnabled, !flowEnabled
|
|
53
|
+
? undefined
|
|
54
|
+
: delivery.sourceSessionRid === undefined
|
|
55
|
+
? (0, flow_context_1.currentFlowContext)()?.streamSessionId
|
|
56
|
+
: (0, managed_stream_1.streamSessionIdFromRoutingId)(delivery.sourceSessionRid)), async () => {
|
|
52
57
|
const messageKind = header.kind === protocol_1.ZLinkStreamMessageKind.Request
|
|
53
58
|
? ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.ActorRequest
|
|
54
59
|
: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.ActorSend;
|
|
@@ -86,6 +86,7 @@ class ZLinkSpotActorPacketDrain {
|
|
|
86
86
|
actorId,
|
|
87
87
|
parts,
|
|
88
88
|
returnResponse: false,
|
|
89
|
+
sourceSessionRid,
|
|
89
90
|
fallbackActorRef: actorRef
|
|
90
91
|
});
|
|
91
92
|
}
|
|
@@ -133,6 +134,7 @@ class ZLinkSpotActorPacketDrain {
|
|
|
133
134
|
actorId,
|
|
134
135
|
parts,
|
|
135
136
|
returnResponse: true,
|
|
137
|
+
sourceSessionRid: info.sourceSessionRid,
|
|
136
138
|
fallbackActorRef: actorRef
|
|
137
139
|
});
|
|
138
140
|
this.options.replyActorNoBind?.(info, [this.encodeActorReplyFrame(parts[0], protocol_1.ZLinkStreamMessageKind.Response, response)], runtime_values_1.RequestResult.Ok);
|
|
@@ -143,6 +143,9 @@ class ZLinkSpotNodeRuntimeManager {
|
|
|
143
143
|
applicationJobReceiveFlowFailureSink: this.options.applicationJobReceiveFlowFailureSink,
|
|
144
144
|
peerAdmissionSealed: () => this.options.peerAdmissionSealed?.(spotNodeName) ?? false
|
|
145
145
|
});
|
|
146
|
+
if (this.options.dispatchErrors !== undefined) {
|
|
147
|
+
node.setDispatchErrorReporter?.(this.options.dispatchErrors, spotNodeName);
|
|
148
|
+
}
|
|
146
149
|
node.setMailboxRecordDroppedHandler?.((record) => this.options.dispatchErrors?.report({
|
|
147
150
|
surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.RouteMeshChannel,
|
|
148
151
|
messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
|
|
@@ -813,7 +816,8 @@ class ZLinkSpotNodeRuntimeManager {
|
|
|
813
816
|
}
|
|
814
817
|
const parts = (0, flow_context_1.runWithOutboundFlow)(this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, () => (0, channel_envelope_1.encodeChannelPublishEnvelopeParts)(channelName, topic, packetName, event, undefined, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, metadata));
|
|
815
818
|
try {
|
|
816
|
-
publisher.publish(channelName, topic, parts, { flags });
|
|
819
|
+
const processing = publisher.publish(channelName, topic, parts, { flags });
|
|
820
|
+
void Promise.resolve(processing).catch(() => undefined);
|
|
817
821
|
return { status: submission_result_1.ZLinkSubmitStatus.Submitted };
|
|
818
822
|
}
|
|
819
823
|
catch (error) {
|
|
@@ -83,7 +83,7 @@ class ZLinkSpotRoutePacketDispatch {
|
|
|
83
83
|
let response;
|
|
84
84
|
const applicationClaim = this.options.claimApplicationWork?.();
|
|
85
85
|
try {
|
|
86
|
-
await (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true), () => this.options.serial.execute(async () => {
|
|
86
|
+
await (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, undefined), () => this.options.serial.execute(async () => {
|
|
87
87
|
const spot = this.options.getTarget();
|
|
88
88
|
// Keep the wire payload raw until this Spot has acquired its
|
|
89
89
|
// execution authority. A rejected or superseded work item must not
|
|
@@ -12,7 +12,7 @@ class ZLinkSpotRoutedBoundSessionDispatch {
|
|
|
12
12
|
async dispatch(received) {
|
|
13
13
|
const boundSessionSend = (0, spot_remote_route_codec_1.decodeRemoteBoundSessionSend)(received.parts, this.options.channelCodecs(), this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true);
|
|
14
14
|
if (boundSessionSend !== undefined) {
|
|
15
|
-
await (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(boundSessionSend.flowId ?? boundSessionSend.envelope?.header.flowId, boundSessionSend.flowOrigin ?? boundSessionSend.envelope?.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true), () => this.options.routedBoundSessionReceiver?.(boundSessionSend.actorId, boundSessionSend.message, boundSessionSend.packetName, boundSessionSend.metadata, boundSessionSend.actorRef, boundSessionSend.actorPacketTarget));
|
|
15
|
+
await (0, flow_context_1.runWithFlow)((0, flow_context_1.createInboundFlow)(boundSessionSend.flowId ?? boundSessionSend.envelope?.header.flowId, boundSessionSend.flowOrigin ?? boundSessionSend.envelope?.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, undefined), () => this.options.routedBoundSessionReceiver?.(boundSessionSend.actorId, boundSessionSend.message, boundSessionSend.packetName, boundSessionSend.metadata, boundSessionSend.actorRef, boundSessionSend.actorPacketTarget));
|
|
16
16
|
if ((0, spot_route_replies_1.hasReplyToken)(received.replyToken)) {
|
|
17
17
|
(0, spot_route_replies_1.submitRoutePayloadReply)(received, boundSessionSend.envelope, { ok: true });
|
|
18
18
|
}
|
|
@@ -131,7 +131,7 @@ class ZLinkSpotSubscriptionDispatch {
|
|
|
131
131
|
}
|
|
132
132
|
const spot = this.options.getTarget();
|
|
133
133
|
const subSource = message.routingId === null ? undefined : String(message.routingId);
|
|
134
|
-
const inboundFlow = (0, flow_context_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true);
|
|
134
|
+
const inboundFlow = (0, flow_context_1.createInboundFlow)(envelope.header.flowId, envelope.header.flowOrigin, this.options.dispatchErrors?.flow.flowCreationEnabled() ?? true, undefined);
|
|
135
135
|
try {
|
|
136
136
|
await this.options.serial.execute(() => (0, flow_context_1.runWithFlow)(inboundFlow, async () => {
|
|
137
137
|
// Payload deserialization belongs to the Spot serial turn. Queue
|
|
@@ -62,7 +62,7 @@ class ZLinkSpotTimerRegistry {
|
|
|
62
62
|
let callbackStarted = false;
|
|
63
63
|
const timer = startOutsideStateLane(() => new ZLinkManagedTimer(name, periodMs, normalizeTimerOptions(options), async (tick) => {
|
|
64
64
|
callbackStarted = false;
|
|
65
|
-
const timerFlow = (0, flow_context_1.createInboundFlow)(undefined, 'Timer', this.flowCreationEnabled());
|
|
65
|
+
const timerFlow = (0, flow_context_1.createInboundFlow)(undefined, 'Timer', this.flowCreationEnabled(), undefined);
|
|
66
66
|
const operation = () => {
|
|
67
67
|
const current = this.timers.get(name);
|
|
68
68
|
if (current === undefined ||
|
|
@@ -4,13 +4,18 @@ export interface ZLinkActorSessionBindingActor {
|
|
|
4
4
|
}
|
|
5
5
|
export interface ZLinkActorSessionBindingContext<TActor extends ZLinkActorSessionBindingActor> {
|
|
6
6
|
readonly routingId?: unknown;
|
|
7
|
-
|
|
7
|
+
readonly actorSlotControls?: {
|
|
8
|
+
enqueueBound(actorSlot: number, actorId: string): Promise<void>;
|
|
9
|
+
enqueueUnbound(actorSlot: number): Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
bindLocal(actor: TActor, bindingToken: string, actorSlot?: number): void;
|
|
8
12
|
unbindLocal(actorId: string, bindingToken: string): void;
|
|
9
13
|
}
|
|
10
14
|
export interface ZLinkActorSessionRoute<TContext extends ZLinkActorSessionBindingContext<TActor>, TActor extends ZLinkActorSessionBindingActor> {
|
|
11
15
|
readonly context: TContext;
|
|
12
16
|
readonly actor: TActor;
|
|
13
17
|
readonly bindingToken: string;
|
|
18
|
+
readonly actorSlot?: number;
|
|
14
19
|
readonly sessionIdentity?: string;
|
|
15
20
|
readonly activeFrames: ZLinkActorSessionActiveFrames;
|
|
16
21
|
sealId?: string;
|
|
@@ -68,22 +73,30 @@ export interface ZLinkActorSessionAuthorityFence {
|
|
|
68
73
|
readonly authorityStoreVersion?: string;
|
|
69
74
|
readonly actorType?: string;
|
|
70
75
|
}
|
|
76
|
+
export declare enum ZLinkActorSessionBindingTermination {
|
|
77
|
+
BindingEnd = 0,
|
|
78
|
+
PhysicalDisconnect = 1
|
|
79
|
+
}
|
|
71
80
|
export declare class ZLinkActorSessionBindingRegistry<TContext extends ZLinkActorSessionBindingContext<TActor>, TActor extends ZLinkActorSessionBindingActor> {
|
|
72
81
|
private readonly terminalRelocationCapacity;
|
|
73
82
|
private readonly outboundCapacity;
|
|
74
83
|
private readonly sealWaitTimeoutMs;
|
|
84
|
+
private readonly errorSink?;
|
|
75
85
|
private readonly lane;
|
|
76
86
|
private readonly routes;
|
|
87
|
+
private readonly nextActorSlots;
|
|
77
88
|
private readonly sealWaiters;
|
|
78
89
|
private readonly activeFrameWaiters;
|
|
79
90
|
private readonly relocations;
|
|
80
91
|
private readonly terminalRelocations;
|
|
81
|
-
constructor(terminalRelocationCapacity?: number, outboundCapacity?: number, sealWaitTimeoutMs?: number)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
92
|
+
constructor(terminalRelocationCapacity?: number, outboundCapacity?: number, sealWaitTimeoutMs?: number, errorSink?: (() => {
|
|
93
|
+
reportRuntimeTaskException(taskName: string, error: unknown): void;
|
|
94
|
+
} | undefined) | undefined);
|
|
95
|
+
bind(context: TContext, actor: TActor, bindingToken: string, authorityFence?: ZLinkActorSessionAuthorityFence, sessionIdentity?: string, commitActor?: () => void): Promise<void>;
|
|
96
|
+
private commitCore;
|
|
97
|
+
private issueActorSlot;
|
|
98
|
+
replace(previous: ZLinkActorSessionRoute<TContext, TActor>, context: TContext, actor: TActor, bindingToken: string, authorityFence?: ZLinkActorSessionAuthorityFence, sessionIdentity?: string, commitActor?: () => void): Promise<void>;
|
|
99
|
+
replaceAndReleaseSeal(previous: ZLinkActorSessionRoute<TContext, TActor>, context: TContext, actor: TActor, bindingToken: string, sealId: string, authorityFence?: ZLinkActorSessionAuthorityFence, sessionIdentity?: string, commitActor?: () => void): Promise<void>;
|
|
87
100
|
private replaceAndReleaseSealCore;
|
|
88
101
|
find(actorId: string): Promise<TActor | undefined>;
|
|
89
102
|
private findCore;
|
|
@@ -93,7 +106,7 @@ export declare class ZLinkActorSessionBindingRegistry<TContext extends ZLinkActo
|
|
|
93
106
|
readonly context: TContext;
|
|
94
107
|
} | undefined>;
|
|
95
108
|
private capturePendingReplyClaimCore;
|
|
96
|
-
unbind(actorId: string, context: TContext, bindingToken: string): Promise<void>;
|
|
109
|
+
unbind(actorId: string, context: TContext, bindingToken: string, termination?: ZLinkActorSessionBindingTermination): Promise<void>;
|
|
97
110
|
private unbindCore;
|
|
98
111
|
unbindActor(actorId: string): Promise<void>;
|
|
99
112
|
private unbindActorCore;
|