@zlink-systems/framework 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
- package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +1 -0
- package/dist/runtime/activation-admission.d.ts +29 -0
- package/dist/runtime/activation-admission.js +61 -0
- package/dist/runtime/actors/actor-context.js +6 -6
- package/dist/runtime/actors/actor-handoff.d.ts +9 -3
- package/dist/runtime/actors/actor-handoff.js +28 -17
- package/dist/runtime/actors/actor-local-native-join.js +2 -18
- package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
- package/dist/runtime/actors/actor-remote-joiner.js +6 -8
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
- package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
- package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
- package/dist/runtime/actors/deferred-join-completion.js +20 -0
- package/dist/runtime/actors/index.d.ts +1 -1
- package/dist/runtime/actors/index.js +15 -5
- package/dist/runtime/admission.d.ts +5 -1
- package/dist/runtime/admission.js +4 -0
- package/dist/runtime/backend/contracts/index.d.ts +2 -10
- package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
- package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
- package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
- package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
- package/dist/runtime/channels/channel-clients.d.ts +0 -1
- package/dist/runtime/channels/channel-clients.js +0 -8
- package/dist/runtime/channels/channel-outbound-operations.js +2 -10
- package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
- package/dist/runtime/channels/channel-runtime-manager.js +1 -12
- package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
- package/dist/runtime/channels/channel-socket-registry.js +49 -62
- package/dist/runtime/channels/channel-transports.d.ts +0 -3
- package/dist/runtime/channels/fanout-location-runtime.js +3 -9
- package/dist/runtime/execution/index.d.ts +18 -8
- package/dist/runtime/execution/index.js +55 -29
- package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
- package/dist/runtime/execution/serial-execution-queue.js +49 -15
- package/dist/runtime/foundation/listener-records.d.ts +11 -0
- package/dist/runtime/foundation/listener-records.js +20 -0
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
- package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
- package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
- package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
- package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
- package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
- package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
- package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
- package/dist/runtime/foundation/service-topology-registry.js +6 -30
- package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
- package/dist/runtime/host/actor-transfer-runtime.js +73 -86
- package/dist/runtime/host/index.d.ts +6 -2
- package/dist/runtime/host/index.js +63 -37
- package/dist/runtime/host/remote-bound-session-relay.js +4 -3
- package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
- package/dist/runtime/host/route-mesh-runtime.js +7 -5
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
- package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
- package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
- package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
- package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
- package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
- package/dist/runtime/locations/lifecycle.d.ts +1 -1
- package/dist/runtime/locations/lifecycle.js +2 -2
- package/dist/runtime/locations/resolvers.js +7 -2
- package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
- package/dist/runtime/locations/spot-location-claims.js +3 -27
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
- package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
- package/dist/runtime/spots/index.d.ts +25 -19
- package/dist/runtime/spots/index.js +207 -205
- package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
- package/dist/runtime/spots/spot-activation-registry.js +34 -31
- package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
- package/dist/runtime/spots/spot-activation-state.js +4 -17
- package/dist/runtime/spots/spot-activation.d.ts +8 -6
- package/dist/runtime/spots/spot-activation.js +54 -49
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
- package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
- package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
- package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
- package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
- package/dist/runtime/spots/spot-actor-membership.js +26 -12
- package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
- package/dist/runtime/spots/spot-entry-activation.js +0 -1
- package/dist/runtime/spots/spot-manager-public.js +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
- package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
- package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
- package/dist/runtime/spots/spot-outbound.js +1 -29
- package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
- package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
- package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
- package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
- package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
- package/dist/runtime/spots/spot-serial-executor.js +8 -1
- package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
- package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
- package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
- package/dist/runtime/streams/bound-session-service.js +1 -18
- package/dist/runtime/streams/index.d.ts +2 -0
- package/dist/runtime/streams/index.js +19 -19
- package/dist/runtime/streams/session-serial-executor.js +2 -2
- package/package.json +3 -3
- package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
- package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
- package/src/internal.ts +1 -0
- package/src/runtime/activation-admission.ts +78 -0
- package/src/runtime/actors/actor-context.ts +6 -6
- package/src/runtime/actors/actor-handoff.ts +31 -23
- package/src/runtime/actors/actor-local-native-join.ts +3 -42
- package/src/runtime/actors/actor-remote-joiner.ts +6 -25
- package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
- package/src/runtime/actors/actor-source-transfer.ts +5 -18
- package/src/runtime/actors/deferred-join-completion.ts +40 -0
- package/src/runtime/actors/index.ts +22 -9
- package/src/runtime/admission.ts +5 -1
- package/src/runtime/backend/contracts/index.ts +2 -13
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
- package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
- package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
- package/src/runtime/backend/raw-binding-port.ts +13 -0
- package/src/runtime/channels/channel-clients.ts +0 -11
- package/src/runtime/channels/channel-outbound-operations.ts +3 -11
- package/src/runtime/channels/channel-runtime-manager.ts +4 -15
- package/src/runtime/channels/channel-socket-registry.ts +69 -71
- package/src/runtime/channels/channel-transports.ts +0 -3
- package/src/runtime/channels/fanout-location-runtime.ts +4 -16
- package/src/runtime/execution/index.ts +68 -30
- package/src/runtime/execution/serial-execution-queue.ts +52 -20
- package/src/runtime/foundation/listener-records.ts +21 -0
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
- package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
- package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
- package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
- package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
- package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
- package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
- package/src/runtime/foundation/service-topology-registry.ts +8 -48
- package/src/runtime/host/actor-transfer-runtime.ts +94 -166
- package/src/runtime/host/index.ts +119 -54
- package/src/runtime/host/remote-bound-session-relay.ts +4 -3
- package/src/runtime/host/route-mesh-runtime.ts +9 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
- package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
- package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
- package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
- package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
- package/src/runtime/locations/lifecycle.ts +3 -2
- package/src/runtime/locations/resolvers.ts +19 -13
- package/src/runtime/locations/spot-location-claims.ts +5 -34
- package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
- package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
- package/src/runtime/spots/index.ts +341 -295
- package/src/runtime/spots/spot-activation-registry.ts +41 -31
- package/src/runtime/spots/spot-activation-state.ts +4 -16
- package/src/runtime/spots/spot-activation.ts +102 -80
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
- package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
- package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
- package/src/runtime/spots/spot-actor-membership.ts +81 -17
- package/src/runtime/spots/spot-entry-activation.ts +0 -3
- package/src/runtime/spots/spot-manager-public.ts +8 -4
- package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
- package/src/runtime/spots/spot-outbound.ts +4 -47
- package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
- package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
- package/src/runtime/spots/spot-runtime-ports.ts +6 -17
- package/src/runtime/spots/spot-serial-executor.ts +9 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
- package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
- package/src/runtime/streams/bound-session-service.ts +2 -36
- package/src/runtime/streams/index.ts +29 -27
- package/src/runtime/streams/session-serial-executor.ts +2 -2
- package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
- package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
- package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
|
@@ -110,13 +110,28 @@ class ServiceMaintenanceRuntime {
|
|
|
110
110
|
}
|
|
111
111
|
async runUnits(signal, stopStartingSignal) {
|
|
112
112
|
const pending = new Set();
|
|
113
|
+
// A unit failure is recorded before its promise leaves `pending`, so no
|
|
114
|
+
// failure is lost. Every started unit runs to its own terminal before the
|
|
115
|
+
// first failure is reported: the host result follows the settled
|
|
116
|
+
// authority of each unit (spec 30 §13).
|
|
117
|
+
const failures = [];
|
|
118
|
+
const reportFailure = async () => {
|
|
119
|
+
if (failures.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
await Promise.allSettled(pending);
|
|
122
|
+
throw failures[0];
|
|
123
|
+
};
|
|
113
124
|
for (;;) {
|
|
125
|
+
await reportFailure();
|
|
114
126
|
const queued = await this.lane.run(() => this.units.length > 0);
|
|
115
|
-
if (!queued && pending.size === 0)
|
|
127
|
+
if (!queued && pending.size === 0) {
|
|
128
|
+
await reportFailure();
|
|
116
129
|
return;
|
|
130
|
+
}
|
|
117
131
|
signal.throwIfAborted();
|
|
118
132
|
if (stopStartingSignal?.aborted === true) {
|
|
119
133
|
await Promise.allSettled(pending);
|
|
134
|
+
await reportFailure();
|
|
120
135
|
stopStartingSignal.throwIfAborted();
|
|
121
136
|
}
|
|
122
137
|
let admitted = false;
|
|
@@ -142,7 +157,12 @@ class ServiceMaintenanceRuntime {
|
|
|
142
157
|
continue;
|
|
143
158
|
admitted = true;
|
|
144
159
|
let running;
|
|
145
|
-
running = startOutsideStateLane(() => unit
|
|
160
|
+
running = startOutsideStateLane(() => unit
|
|
161
|
+
.relocate(signal)
|
|
162
|
+
.catch((error) => {
|
|
163
|
+
failures.push(error);
|
|
164
|
+
})
|
|
165
|
+
.finally(async () => {
|
|
146
166
|
const publication = await this.lane.run(() => {
|
|
147
167
|
this.activeOutbound--;
|
|
148
168
|
pending.delete(running);
|
|
@@ -154,6 +174,7 @@ class ServiceMaintenanceRuntime {
|
|
|
154
174
|
this.notify(claim.publication);
|
|
155
175
|
}
|
|
156
176
|
if (pending.size === 0) {
|
|
177
|
+
await reportFailure();
|
|
157
178
|
if (!admitted)
|
|
158
179
|
throw new Error('No relocation unit is ready to start.');
|
|
159
180
|
}
|
|
@@ -17,3 +17,12 @@ export declare class ServiceRelocationPostCommitError extends Error {
|
|
|
17
17
|
readonly cause: unknown;
|
|
18
18
|
constructor(authority: ZLinkAuthoritySnapshot, staging: ServiceRelocationStaging, cause: unknown);
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* A relocation whose settled authority leaves the host in `Error` with
|
|
22
|
+
* `Blocked/RelocationFailed` (spec 30 §13): the source owner lease ended
|
|
23
|
+
* before its Preserve fence succeeded, or units settled on both the source
|
|
24
|
+
* and the target.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ServiceRelocationAuthorityError extends Error {
|
|
27
|
+
constructor(message: string, options?: ErrorOptions);
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ServiceRelocationPostCommitError = void 0;
|
|
3
|
+
exports.ServiceRelocationAuthorityError = exports.ServiceRelocationPostCommitError = void 0;
|
|
4
4
|
class ServiceRelocationPostCommitError extends Error {
|
|
5
5
|
authority;
|
|
6
6
|
staging;
|
|
@@ -14,3 +14,16 @@ class ServiceRelocationPostCommitError extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
exports.ServiceRelocationPostCommitError = ServiceRelocationPostCommitError;
|
|
17
|
+
/**
|
|
18
|
+
* A relocation whose settled authority leaves the host in `Error` with
|
|
19
|
+
* `Blocked/RelocationFailed` (spec 30 §13): the source owner lease ended
|
|
20
|
+
* before its Preserve fence succeeded, or units settled on both the source
|
|
21
|
+
* and the target.
|
|
22
|
+
*/
|
|
23
|
+
class ServiceRelocationAuthorityError extends Error {
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super(message, options);
|
|
26
|
+
this.name = 'ServiceRelocationAuthorityError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.ServiceRelocationAuthorityError = ServiceRelocationAuthorityError;
|
|
@@ -16,6 +16,8 @@ export interface ServiceRelocationCaptureUnit {
|
|
|
16
16
|
captureApplicationState(signal?: AbortSignal): Promise<Uint8Array>;
|
|
17
17
|
commitSeal(): Promise<void> | void;
|
|
18
18
|
abortSeal(): Promise<void> | void;
|
|
19
|
+
/** Expired-owner terminal: pending requests fail once and dispatch stays closed. */
|
|
20
|
+
discardSeal?(reason: unknown): Promise<void> | void;
|
|
19
21
|
}
|
|
20
22
|
export declare class ServiceCapturedObjectRelocation {
|
|
21
23
|
readonly envelope: ServiceRelocationEnvelope;
|
|
@@ -24,6 +26,12 @@ export declare class ServiceCapturedObjectRelocation {
|
|
|
24
26
|
constructor(envelope: ServiceRelocationEnvelope, units: readonly ServiceRelocationCaptureUnit[]);
|
|
25
27
|
commitSource(): Promise<void>;
|
|
26
28
|
abortSource(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* The source owner lease ended before the authority settled (spec 28 §4.4):
|
|
31
|
+
* the source neither resumes nor commits. Retained work is dropped and
|
|
32
|
+
* every pending request without a terminal fails once with `reason`.
|
|
33
|
+
*/
|
|
34
|
+
discardSource(reason: unknown): Promise<void>;
|
|
27
35
|
}
|
|
28
36
|
/** Captures the two valid relocation units: User Spot aggregate or one Actor. */
|
|
29
37
|
export declare class ServiceRelocationObjectCaptureOwner {
|
|
@@ -12,8 +12,8 @@ class ServiceCapturedObjectRelocation {
|
|
|
12
12
|
async commitSource() {
|
|
13
13
|
if (this.terminal === 'committed')
|
|
14
14
|
return;
|
|
15
|
-
if (this.terminal
|
|
16
|
-
throw new Error(
|
|
15
|
+
if (this.terminal !== 'open') {
|
|
16
|
+
throw new Error(`Relocation source capture was already ${this.terminal}.`);
|
|
17
17
|
}
|
|
18
18
|
for (const unit of this.units)
|
|
19
19
|
await unit.commitSeal();
|
|
@@ -22,8 +22,8 @@ class ServiceCapturedObjectRelocation {
|
|
|
22
22
|
async abortSource() {
|
|
23
23
|
if (this.terminal === 'aborted')
|
|
24
24
|
return;
|
|
25
|
-
if (this.terminal
|
|
26
|
-
throw new Error(
|
|
25
|
+
if (this.terminal !== 'open') {
|
|
26
|
+
throw new Error(`A ${this.terminal} relocation source capture cannot be aborted.`);
|
|
27
27
|
}
|
|
28
28
|
const failures = [];
|
|
29
29
|
for (const unit of [...this.units].reverse()) {
|
|
@@ -39,6 +39,18 @@ class ServiceCapturedObjectRelocation {
|
|
|
39
39
|
throw new AggregateError(failures, 'Relocation source rollback was incomplete.');
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The source owner lease ended before the authority settled (spec 28 §4.4):
|
|
44
|
+
* the source neither resumes nor commits. Retained work is dropped and
|
|
45
|
+
* every pending request without a terminal fails once with `reason`.
|
|
46
|
+
*/
|
|
47
|
+
async discardSource(reason) {
|
|
48
|
+
if (this.terminal !== 'open')
|
|
49
|
+
return;
|
|
50
|
+
this.terminal = 'discarded';
|
|
51
|
+
for (const unit of this.units)
|
|
52
|
+
await unit.discardSeal?.(reason);
|
|
53
|
+
}
|
|
42
54
|
}
|
|
43
55
|
exports.ServiceCapturedObjectRelocation = ServiceCapturedObjectRelocation;
|
|
44
56
|
/** Captures the two valid relocation units: User Spot aggregate or one Actor. */
|
|
@@ -2,22 +2,15 @@ export interface ServiceSessionBindingRetainedDelivery {
|
|
|
2
2
|
deliver(): Promise<boolean>;
|
|
3
3
|
fail(error: unknown): void;
|
|
4
4
|
}
|
|
5
|
-
export interface ServiceSessionBindingAdmissionClaim {
|
|
6
|
-
readonly actorId: string;
|
|
7
|
-
readonly objectGeneration: bigint;
|
|
8
|
-
readonly actorNodeRid: string;
|
|
9
|
-
readonly actorNodeGeneration: bigint;
|
|
10
|
-
readonly authorityOwnerGeneration: bigint;
|
|
11
|
-
readonly ownerLeaseGeneration: bigint;
|
|
12
|
-
readonly producerNodeRid: string;
|
|
13
|
-
readonly producerNodeGeneration: bigint;
|
|
14
|
-
readonly sessionIdentity: string;
|
|
15
|
-
readonly bindingGeneration: bigint;
|
|
16
|
-
}
|
|
17
5
|
export type ServiceSessionBindingAdmissionResult = 'passThrough' | 'retained' | 'rejected';
|
|
18
6
|
export interface ServiceSessionBindingIngressPort {
|
|
19
7
|
actorSlot(actorId: string, sessionRid: string): Promise<number | undefined>;
|
|
20
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Holds a current-binding push while its relocation seal is open
|
|
10
|
+
* (Session–Actor binding §8.1). The caller has already decided that the push
|
|
11
|
+
* names the current binding.
|
|
12
|
+
*/
|
|
13
|
+
retainOutbound(actorId: string, delivery: ServiceSessionBindingRetainedDelivery): Promise<ServiceSessionBindingAdmissionResult>;
|
|
21
14
|
clearOutbound(actorId: string, error: unknown): Promise<void>;
|
|
22
15
|
}
|
|
23
16
|
export declare function registerServiceSessionBindingIngressPort(service: object, port: ServiceSessionBindingIngressPort): void;
|
|
@@ -7,15 +7,11 @@ import { type ServiceActorRouteFence, type ServiceRetiredBoundSessionRouteFence,
|
|
|
7
7
|
import { type ServiceApplicationPayload } from './service-wire-m6a-codec';
|
|
8
8
|
import type { ServiceInstanceActivationRecoveryEnvelope } from './service-instance-activation-recovery-codec';
|
|
9
9
|
import type { ServiceSessionBindingIngressPort } from './service-session-binding-ingress-port';
|
|
10
|
+
import { ZLinkFrameworkRuntimeState } from '../../contracts/Locations';
|
|
10
11
|
export interface ServiceSpotMessageFollowSeal {
|
|
11
12
|
readonly key: string;
|
|
12
13
|
readonly serial: bigint;
|
|
13
14
|
}
|
|
14
|
-
export interface ServiceBoundSessionSendFence {
|
|
15
|
-
readonly targetNodeGeneration: bigint;
|
|
16
|
-
readonly authorityOwnerGeneration: bigint;
|
|
17
|
-
readonly ownerLeaseGeneration: bigint;
|
|
18
|
-
}
|
|
19
15
|
export interface ServiceStatefulResult {
|
|
20
16
|
readonly terminalResult: number;
|
|
21
17
|
readonly failureCode: number;
|
|
@@ -223,11 +219,17 @@ export declare class ServiceStatefulRuntime {
|
|
|
223
219
|
private messageFollowHandler?;
|
|
224
220
|
private mailboxDropHandler?;
|
|
225
221
|
private dispatchErrors?;
|
|
222
|
+
private spotAdmissionProvider?;
|
|
226
223
|
private dispatchErrorMeshName?;
|
|
227
224
|
private readonly admittedUserSpotOperations;
|
|
228
225
|
private readonly pendingInstanceActivations;
|
|
229
226
|
private closed;
|
|
230
227
|
constructor(raw: RawServiceMeshRuntime, nodeRid: string, nodeGeneration: bigint);
|
|
228
|
+
setSpotAdmissionProvider(provider: {
|
|
229
|
+
readonly isClosing: (spotId: string) => boolean;
|
|
230
|
+
readonly runtimeState: () => ZLinkFrameworkRuntimeState;
|
|
231
|
+
readonly awaitCloseDecision?: (spotId: string) => Promise<void> | undefined;
|
|
232
|
+
}): void;
|
|
231
233
|
setMailboxDropHandler(handler: (record: {
|
|
232
234
|
readonly kind: 'spot_multicast' | 'actor_control' | 'actor_binding';
|
|
233
235
|
readonly owner: string;
|
|
@@ -305,7 +307,7 @@ export declare class ServiceStatefulRuntime {
|
|
|
305
307
|
sessionBindings(sessionRid: string): readonly ServiceSessionBinding[];
|
|
306
308
|
allSessionBindings(): readonly ServiceSessionBinding[];
|
|
307
309
|
sendSessionToActor(sessionRid: string, actor: ServiceActorRef, payload: ServiceApplicationPayload): Promise<number>;
|
|
308
|
-
sendBoundSession(actor: ServiceActorRef, expectedBindingGeneration: bigint, payload: ServiceApplicationPayload
|
|
310
|
+
sendBoundSession(actor: ServiceActorRef, expectedBindingGeneration: bigint, payload: ServiceApplicationPayload): Promise<number>;
|
|
309
311
|
close(): void;
|
|
310
312
|
private ingress;
|
|
311
313
|
private handleIngress;
|
|
@@ -349,6 +351,7 @@ export declare class ServiceStatefulRuntime {
|
|
|
349
351
|
private enqueueSessionBindingTombstone;
|
|
350
352
|
private enqueueSessionBindingRetirement;
|
|
351
353
|
private deliverBoundSession;
|
|
354
|
+
private traceRejectedBoundSessionSend;
|
|
352
355
|
private enqueueApplicationFrame;
|
|
353
356
|
private enqueueLifecycleFrame;
|
|
354
357
|
private enqueueFrame;
|
|
@@ -374,6 +377,7 @@ export declare class ServiceStatefulRuntime {
|
|
|
374
377
|
private validateActorMessageFence;
|
|
375
378
|
private validateSpotFence;
|
|
376
379
|
private validateDirectSpotFence;
|
|
380
|
+
private requireDirectSpotAdmission;
|
|
377
381
|
private holdOrRelaySpotMessage;
|
|
378
382
|
private restoreSpotMessageFollowRecord;
|
|
379
383
|
private drainSpotMessageFollow;
|
|
@@ -384,7 +388,6 @@ export declare class ServiceStatefulRuntime {
|
|
|
384
388
|
private peekSpotMessageFollow;
|
|
385
389
|
private takeSpotMessageFollow;
|
|
386
390
|
private actorFence;
|
|
387
|
-
private tryBoundSessionSendFence;
|
|
388
391
|
private tryActorFence;
|
|
389
392
|
private acceptCanonicalActorFence;
|
|
390
393
|
private trySpotFence;
|
|
@@ -8,16 +8,17 @@ 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
10
|
const ZLinkDispatchOptions_1 = require("../../contracts/Dispatch/ZLinkDispatchOptions");
|
|
11
|
+
const message_flow_1 = require("../diagnostics/message-flow");
|
|
11
12
|
const service_runtime_contracts_1 = require("./service-runtime-contracts");
|
|
12
13
|
const message_follow_suppression_registry_1 = require("./message-follow-suppression-registry");
|
|
13
14
|
const service_stateful_registry_1 = require("./service-stateful-registry");
|
|
14
15
|
const service_stateful_wire_codec_1 = require("./service-stateful-wire-codec");
|
|
15
|
-
const routing_id_1 = require("../routing-id");
|
|
16
16
|
const service_wire_pilot_codec_generated_1 = require("../protocol/service_wire_pilot_codec.generated");
|
|
17
17
|
const actor_join_recovery_codec_1 = require("./actor-join-recovery-codec");
|
|
18
18
|
const service_wire_m6a_codec_1 = require("./service-wire-m6a-codec");
|
|
19
19
|
const service_metadata_codec_1 = require("./service-metadata-codec");
|
|
20
20
|
const contracts_1 = require("../../contracts");
|
|
21
|
+
const Locations_1 = require("../../contracts/Locations");
|
|
21
22
|
const ACTOR_ROUTE_STALE = 21;
|
|
22
23
|
const SPOT_MOVING = 34;
|
|
23
24
|
const USER_SPOT_OPERATION_CAPACITY = 65_536;
|
|
@@ -83,6 +84,7 @@ class ServiceStatefulRuntime {
|
|
|
83
84
|
messageFollowHandler;
|
|
84
85
|
mailboxDropHandler;
|
|
85
86
|
dispatchErrors;
|
|
87
|
+
spotAdmissionProvider;
|
|
86
88
|
dispatchErrorMeshName;
|
|
87
89
|
admittedUserSpotOperations = new Map();
|
|
88
90
|
pendingInstanceActivations = new Map();
|
|
@@ -95,6 +97,9 @@ class ServiceStatefulRuntime {
|
|
|
95
97
|
this.registry.createEntrySpot(nodeRid);
|
|
96
98
|
raw.setServiceIngress((record) => this.ingress(record));
|
|
97
99
|
}
|
|
100
|
+
setSpotAdmissionProvider(provider) {
|
|
101
|
+
this.spotAdmissionProvider = provider;
|
|
102
|
+
}
|
|
98
103
|
setMailboxDropHandler(handler) {
|
|
99
104
|
this.mailboxDropHandler = handler;
|
|
100
105
|
}
|
|
@@ -669,7 +674,10 @@ class ServiceStatefulRuntime {
|
|
|
669
674
|
if (target === undefined) {
|
|
670
675
|
return runtime_values_1.SubmitResult.NotFound;
|
|
671
676
|
}
|
|
672
|
-
const header = (0, service_stateful_wire_codec_1.encodeSpotHeader)('spotSend', sourceSpotId, target
|
|
677
|
+
const header = (0, service_stateful_wire_codec_1.encodeSpotHeader)('spotSend', sourceSpotId, target, undefined, {
|
|
678
|
+
high: this.nodeGeneration,
|
|
679
|
+
low: this.nextMessageFollowOperation++
|
|
680
|
+
});
|
|
673
681
|
return this.submitOneWay(target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
|
|
674
682
|
}
|
|
675
683
|
requestToSpot(sourceSpotId, requested, payload, timeoutMs) {
|
|
@@ -682,7 +690,10 @@ class ServiceStatefulRuntime {
|
|
|
682
690
|
});
|
|
683
691
|
return pending;
|
|
684
692
|
}
|
|
685
|
-
const header = (0, service_stateful_wire_codec_1.encodeSpotHeader)('spotRequest', sourceSpotId, target, pending.id
|
|
693
|
+
const header = (0, service_stateful_wire_codec_1.encodeSpotHeader)('spotRequest', sourceSpotId, target, pending.id, {
|
|
694
|
+
high: this.nodeGeneration,
|
|
695
|
+
low: this.nextMessageFollowOperation++
|
|
696
|
+
});
|
|
686
697
|
this.submitRequest(pending, target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'spotRequest');
|
|
687
698
|
return pending;
|
|
688
699
|
}
|
|
@@ -695,7 +706,7 @@ class ServiceStatefulRuntime {
|
|
|
695
706
|
: {
|
|
696
707
|
...boundSession,
|
|
697
708
|
sequence: this.nextSessionSequence++
|
|
698
|
-
});
|
|
709
|
+
}, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
|
|
699
710
|
return this.submitOneWay(target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
|
|
700
711
|
}
|
|
701
712
|
requestToActor(target, _targetNodeGeneration, _authorityOwnerGeneration, payload, timeoutMs, sourceActor, boundSession) {
|
|
@@ -713,7 +724,7 @@ class ServiceStatefulRuntime {
|
|
|
713
724
|
: {
|
|
714
725
|
...boundSession,
|
|
715
726
|
sequence: this.nextSessionSequence++
|
|
716
|
-
});
|
|
727
|
+
}, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
|
|
717
728
|
this.submitRequest(pending, target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'actorRequest');
|
|
718
729
|
return pending;
|
|
719
730
|
}
|
|
@@ -1008,7 +1019,11 @@ class ServiceStatefulRuntime {
|
|
|
1008
1019
|
bindingGeneration: delivery.binding.bindingGeneration
|
|
1009
1020
|
});
|
|
1010
1021
|
}
|
|
1011
|
-
async sendBoundSession(actor, expectedBindingGeneration, payload
|
|
1022
|
+
async sendBoundSession(actor, expectedBindingGeneration, payload) {
|
|
1023
|
+
// Session–Actor binding §3 item 3: the source sends by binding identity to
|
|
1024
|
+
// the registered route. The header's owner lifecycle fields are this node's
|
|
1025
|
+
// current route values, not send conditions; the Session owner alone
|
|
1026
|
+
// decides whether the binding is current.
|
|
1012
1027
|
let binding;
|
|
1013
1028
|
try {
|
|
1014
1029
|
binding = this.registry.validateBoundSession(actor, expectedBindingGeneration);
|
|
@@ -1016,7 +1031,7 @@ class ServiceStatefulRuntime {
|
|
|
1016
1031
|
catch {
|
|
1017
1032
|
return runtime_values_1.SubmitResult.InvalidState;
|
|
1018
1033
|
}
|
|
1019
|
-
const actorFence = this.
|
|
1034
|
+
const actorFence = this.tryActorFence(actor);
|
|
1020
1035
|
if (actorFence === undefined)
|
|
1021
1036
|
return runtime_values_1.SubmitResult.InvalidState;
|
|
1022
1037
|
const header = (0, service_stateful_wire_codec_1.encodeBoundSessionSendHeader)(actorFence, expectedBindingGeneration);
|
|
@@ -1094,7 +1109,8 @@ class ServiceStatefulRuntime {
|
|
|
1094
1109
|
decoded = statefulActorJoinFromCanonical(canonicalActorJoin);
|
|
1095
1110
|
}
|
|
1096
1111
|
else {
|
|
1097
|
-
|
|
1112
|
+
const metadata = (record.flags & service_stateful_wire_codec_1.M6bServiceWireFlag.metadata) !== 0;
|
|
1113
|
+
decoded = (0, service_stateful_wire_codec_1.decodeStatefulHeader)(record.parts[0], record.parts[metadata ? 2 : 1], metadata ? record.parts[1] : undefined);
|
|
1098
1114
|
}
|
|
1099
1115
|
const hasPayload = [
|
|
1100
1116
|
'spotSend',
|
|
@@ -1106,19 +1122,26 @@ class ServiceStatefulRuntime {
|
|
|
1106
1122
|
'boundSessionSend'
|
|
1107
1123
|
].includes(decoded.kind);
|
|
1108
1124
|
const instanceMetadata = decoded.kind === 'instanceSpot' && (record.flags & service_stateful_wire_codec_1.M6bServiceWireFlag.metadata) !== 0;
|
|
1125
|
+
const statefulMetadata = (decoded.kind === 'spotSend' ||
|
|
1126
|
+
decoded.kind === 'spotRequest' ||
|
|
1127
|
+
decoded.kind === 'actorSend' ||
|
|
1128
|
+
decoded.kind === 'actorRequest') &&
|
|
1129
|
+
(record.flags & service_stateful_wire_codec_1.M6bServiceWireFlag.metadata) !== 0;
|
|
1109
1130
|
const userSpotInfrastructure = decoded.kind === 'userSpotCreate' ||
|
|
1110
1131
|
decoded.kind === 'userSpotClose' ||
|
|
1111
1132
|
decoded.kind === 'actorCreate' ||
|
|
1112
1133
|
decoded.kind === 'messageFollow' ||
|
|
1113
1134
|
decoded.kind === 'boundSessionReplaced';
|
|
1114
1135
|
if (record.parts.length < 1 ||
|
|
1115
|
-
record.parts.length > (instanceMetadata ? 3 : 2) ||
|
|
1116
|
-
(hasPayload &&
|
|
1136
|
+
record.parts.length > (instanceMetadata || statefulMetadata ? 3 : 2) ||
|
|
1137
|
+
(hasPayload &&
|
|
1138
|
+
decoded.kind !== 'actorJoin' &&
|
|
1139
|
+
record.parts.length !== ((record.flags & service_stateful_wire_codec_1.M6bServiceWireFlag.metadata) !== 0 ? 3 : 2)) ||
|
|
1117
1140
|
(decoded.kind === 'instanceSpot' && record.parts.length !== (instanceMetadata ? 3 : 2)) ||
|
|
1118
1141
|
(userSpotInfrastructure && record.parts.length !== 1)) {
|
|
1119
1142
|
return 'protocolError';
|
|
1120
1143
|
}
|
|
1121
|
-
const metadataFrame = instanceMetadata
|
|
1144
|
+
const metadataFrame = instanceMetadata || statefulMetadata
|
|
1122
1145
|
? (0, service_metadata_codec_1.validateServiceMetadataFrame)(record.parts[1])
|
|
1123
1146
|
: undefined;
|
|
1124
1147
|
const canonicalPayload = canonicalActorJoin?.payload === undefined
|
|
@@ -1201,6 +1224,8 @@ class ServiceStatefulRuntime {
|
|
|
1201
1224
|
}
|
|
1202
1225
|
case 'spotSend':
|
|
1203
1226
|
case 'spotRequest': {
|
|
1227
|
+
await this.spotAdmissionProvider?.awaitCloseDecision?.(record.target.spot.spotId);
|
|
1228
|
+
this.requireDirectSpotAdmission(record.target.spot.spotId);
|
|
1204
1229
|
const followed = this.holdOrRelaySpotMessage(ingress, record);
|
|
1205
1230
|
if (followed !== undefined)
|
|
1206
1231
|
return followed;
|
|
@@ -2232,13 +2257,17 @@ class ServiceStatefulRuntime {
|
|
|
2232
2257
|
return accepted;
|
|
2233
2258
|
}
|
|
2234
2259
|
async deliverBoundSession(ingress, record, payloadFrame) {
|
|
2260
|
+
// Session–Actor binding §3 item 3, §8.1: this Session owner's binding
|
|
2261
|
+
// record alone decides whether command 36 names the current binding
|
|
2262
|
+
// (ActorId, ObjectGeneration, binding generation; SessionRid is the
|
|
2263
|
+
// record's own). The transport boundary has already authenticated the
|
|
2264
|
+
// source peer, and the header's route fields are not compared here.
|
|
2265
|
+
if (payloadFrame === undefined)
|
|
2266
|
+
return 'protocolError';
|
|
2235
2267
|
const delivery = this.sessionDeliveries.get(actorKey(record.actor.actor));
|
|
2236
2268
|
if (delivery === undefined ||
|
|
2237
|
-
delivery.binding.bindingGeneration !== record.expectedBindingGeneration
|
|
2238
|
-
|
|
2239
|
-
ingress.sourceNodeGeneration === undefined ||
|
|
2240
|
-
!(0, routing_id_1.routingIdsEqual)(ingress.sourceRoutingId, record.actor.actor.nodeRid) ||
|
|
2241
|
-
ingress.sourceNodeGeneration !== record.actor.targetNodeGeneration) {
|
|
2269
|
+
delivery.binding.bindingGeneration !== record.expectedBindingGeneration) {
|
|
2270
|
+
this.traceRejectedBoundSessionSend(ingress, record, payloadFrame);
|
|
2242
2271
|
return 'protocolError';
|
|
2243
2272
|
}
|
|
2244
2273
|
const sessionRid = delivery.binding.sessionRid;
|
|
@@ -2264,18 +2293,7 @@ class ServiceStatefulRuntime {
|
|
|
2264
2293
|
settle();
|
|
2265
2294
|
}
|
|
2266
2295
|
};
|
|
2267
|
-
const decision = await delivery.bindingIngress?.retainOutbound(
|
|
2268
|
-
actorId: record.actor.actor.actorId,
|
|
2269
|
-
objectGeneration: record.actor.actor.generation,
|
|
2270
|
-
actorNodeRid: record.actor.actor.nodeRid,
|
|
2271
|
-
actorNodeGeneration: record.actor.targetNodeGeneration,
|
|
2272
|
-
authorityOwnerGeneration: record.actor.authorityOwnerGeneration,
|
|
2273
|
-
ownerLeaseGeneration: record.actor.ownerLeaseGeneration,
|
|
2274
|
-
producerNodeRid: ingress.sourceRoutingId,
|
|
2275
|
-
producerNodeGeneration: ingress.sourceNodeGeneration,
|
|
2276
|
-
sessionIdentity: sessionRid,
|
|
2277
|
-
bindingGeneration: record.expectedBindingGeneration
|
|
2278
|
-
}, operation);
|
|
2296
|
+
const decision = await delivery.bindingIngress?.retainOutbound(record.actor.actor.actorId, operation);
|
|
2279
2297
|
if (decision === 'retained')
|
|
2280
2298
|
return 'application';
|
|
2281
2299
|
if (decision === 'rejected') {
|
|
@@ -2301,6 +2319,35 @@ class ServiceStatefulRuntime {
|
|
|
2301
2319
|
}
|
|
2302
2320
|
return 'application';
|
|
2303
2321
|
}
|
|
2322
|
+
// Session–Actor binding §3 item 4: a push refused as not current is
|
|
2323
|
+
// recorded with the closed flow vocabulary (dropped, stream_session, send,
|
|
2324
|
+
// stale_target) instead of disappearing. Nothing is built while tracing is
|
|
2325
|
+
// off.
|
|
2326
|
+
traceRejectedBoundSessionSend(ingress, record, payloadFrame) {
|
|
2327
|
+
const tracePoint = (0, message_flow_1.flowIfEnabled)(this.dispatchErrors?.flow, ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped);
|
|
2328
|
+
if (tracePoint === undefined)
|
|
2329
|
+
return;
|
|
2330
|
+
let packetName;
|
|
2331
|
+
try {
|
|
2332
|
+
packetName = (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payloadFrame).packetName;
|
|
2333
|
+
}
|
|
2334
|
+
catch (error) {
|
|
2335
|
+
// A malformed payload is still a refused push; it is traced without a
|
|
2336
|
+
// packet name.
|
|
2337
|
+
if (!(error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError))
|
|
2338
|
+
throw error;
|
|
2339
|
+
}
|
|
2340
|
+
tracePoint.trace({
|
|
2341
|
+
outcome: ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped,
|
|
2342
|
+
surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.StreamSession,
|
|
2343
|
+
messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
|
|
2344
|
+
...(packetName === undefined ? {} : { packetName }),
|
|
2345
|
+
...(this.dispatchErrorMeshName === undefined ? {} : { meshName: this.dispatchErrorMeshName }),
|
|
2346
|
+
sourceRid: ingress.sourceRoutingId,
|
|
2347
|
+
actorId: record.actor.actor.actorId,
|
|
2348
|
+
errorReason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2304
2351
|
enqueueApplicationFrame(ingress, owner, payloadFrame, stateful) {
|
|
2305
2352
|
return this.enqueueFrame('application', ingress, owner, payloadFrame, stateful);
|
|
2306
2353
|
}
|
|
@@ -2783,7 +2830,7 @@ class ServiceStatefulRuntime {
|
|
|
2783
2830
|
applicationJobOwner
|
|
2784
2831
|
};
|
|
2785
2832
|
try {
|
|
2786
|
-
this.submitLocalRequest(localIngress, pending, operationKind, actor, deadlineUnixMs);
|
|
2833
|
+
await this.submitLocalRequest(localIngress, pending, operationKind, actor, deadlineUnixMs);
|
|
2787
2834
|
}
|
|
2788
2835
|
catch (error) {
|
|
2789
2836
|
this.operations.reply(pending.id, failure(error));
|
|
@@ -2854,7 +2901,7 @@ class ServiceStatefulRuntime {
|
|
|
2854
2901
|
this.operations.fail(pending.id, error);
|
|
2855
2902
|
});
|
|
2856
2903
|
}
|
|
2857
|
-
submitLocalRequest(ingress, pending, operationKind, actor, deadlineUnixMs) {
|
|
2904
|
+
async submitLocalRequest(ingress, pending, operationKind, actor, deadlineUnixMs) {
|
|
2858
2905
|
const canonicalActorJoin = operationKind === 'actorJoin' ? (0, service_wire_pilot_codec_generated_1.decodeActorJoin28)(ingress.parts) : undefined;
|
|
2859
2906
|
const decoded = canonicalActorJoin === undefined
|
|
2860
2907
|
? (0, service_stateful_wire_codec_1.decodeStatefulHeader)(ingress.parts[0])
|
|
@@ -2891,6 +2938,7 @@ class ServiceStatefulRuntime {
|
|
|
2891
2938
|
}
|
|
2892
2939
|
const localReply = (terminalResult, failureCode, replyPayload, tail) => this.operations.reply(pending.id, this.resultFromReply(terminalResult, failureCode, replyPayload, tail, this.nodeRid, actor));
|
|
2893
2940
|
if (decoded.kind === 'spotRequest') {
|
|
2941
|
+
await this.spotAdmissionProvider?.awaitCloseDecision?.(decoded.target.spot.spotId);
|
|
2894
2942
|
this.validateDirectSpotFence(decoded.target);
|
|
2895
2943
|
this.enqueueApplicationFrame(ingress, `spot:${decoded.target.spot.spotId}`, payloadFrame, {
|
|
2896
2944
|
receiveKind: service_runtime_contracts_1.ReceiveKind.SpotRequest,
|
|
@@ -2911,7 +2959,9 @@ class ServiceStatefulRuntime {
|
|
|
2911
2959
|
operationKind: service_runtime_contracts_1.OperationKind.ActorRequest,
|
|
2912
2960
|
correlation: decoded.correlation,
|
|
2913
2961
|
targetActor: current.ref,
|
|
2914
|
-
...(decoded.sourceActor === undefined
|
|
2962
|
+
...(decoded.sourceActor === undefined
|
|
2963
|
+
? {}
|
|
2964
|
+
: { sourceActor: { ...decoded.sourceActor, nodeRid: ingress.sourceRoutingId } }),
|
|
2915
2965
|
...(decoded.boundSession === undefined
|
|
2916
2966
|
? {}
|
|
2917
2967
|
: { sourceBindingGeneration: decoded.boundSession.bindingGeneration }),
|
|
@@ -3147,6 +3197,11 @@ class ServiceStatefulRuntime {
|
|
|
3147
3197
|
return spot;
|
|
3148
3198
|
}
|
|
3149
3199
|
validateDirectSpotFence(fence) {
|
|
3200
|
+
if (fence.targetNodeRid !== this.nodeRid ||
|
|
3201
|
+
fence.targetNodeGeneration !== this.nodeGeneration) {
|
|
3202
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Spot '${fence.spot.spotId}' targets an unavailable owner route.`);
|
|
3203
|
+
}
|
|
3204
|
+
this.requireDirectSpotAdmission(fence.spot.spotId);
|
|
3150
3205
|
const spot = this.registry.spot(fence.spot.spotId);
|
|
3151
3206
|
if (spot === undefined) {
|
|
3152
3207
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestTargetNotFound, `Spot '${fence.spot.spotId}' has no current Ready authority.`);
|
|
@@ -3154,10 +3209,6 @@ class ServiceStatefulRuntime {
|
|
|
3154
3209
|
if (spot.state !== 'ready') {
|
|
3155
3210
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Spot '${fence.spot.spotId}' is not Ready.`);
|
|
3156
3211
|
}
|
|
3157
|
-
if (fence.targetNodeRid !== this.nodeRid ||
|
|
3158
|
-
fence.targetNodeGeneration !== this.nodeGeneration) {
|
|
3159
|
-
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Spot '${fence.spot.spotId}' targets an unavailable owner route.`);
|
|
3160
|
-
}
|
|
3161
3212
|
if (spot.kind === 'entry') {
|
|
3162
3213
|
if (!isEntrySpotFence(fence)) {
|
|
3163
3214
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Entry Spot '${fence.spot.spotId}' has an invalid owner fence.`);
|
|
@@ -3177,9 +3228,17 @@ class ServiceStatefulRuntime {
|
|
|
3177
3228
|
}
|
|
3178
3229
|
return spot;
|
|
3179
3230
|
}
|
|
3231
|
+
requireDirectSpotAdmission(spotId) {
|
|
3232
|
+
if (this.spotAdmissionProvider?.runtimeState() === Locations_1.ZLinkFrameworkRuntimeState.Draining) {
|
|
3233
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RuntimeShutdown, `Spot '${spotId}' owner is Draining.`);
|
|
3234
|
+
}
|
|
3235
|
+
if (this.spotAdmissionProvider?.isClosing(spotId) === true) {
|
|
3236
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestRejected, `Spot '${spotId}' authority is Closing.`);
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3180
3239
|
holdOrRelaySpotMessage(ingress, wire) {
|
|
3181
3240
|
const state = this.spotMessageFollow.get(spotKey(wire.target.spot));
|
|
3182
|
-
if (state === undefined || !
|
|
3241
|
+
if (state === undefined || !sameDirectSpotRouteIdentity(state.source, wire.target)) {
|
|
3183
3242
|
return undefined;
|
|
3184
3243
|
}
|
|
3185
3244
|
if (state.expiresAtMs !== undefined && state.expiresAtMs <= performance.now()) {
|
|
@@ -3224,9 +3283,11 @@ class ServiceStatefulRuntime {
|
|
|
3224
3283
|
}
|
|
3225
3284
|
const current = this.peekSpotMessageFollow(state);
|
|
3226
3285
|
try {
|
|
3286
|
+
const metadata = (current.ingress.parts[0][4] & service_stateful_wire_codec_1.M6bServiceWireFlag.metadata) !== 0;
|
|
3227
3287
|
const parts = [
|
|
3228
|
-
(0, service_stateful_wire_codec_1.encodeSpotHeader)(current.wire.kind, current.wire.sourceSpotId, state.target, current.wire.correlation),
|
|
3229
|
-
current.ingress.parts[1]
|
|
3288
|
+
(0, service_stateful_wire_codec_1.encodeSpotHeader)(current.wire.kind, current.wire.sourceSpotId, state.target, current.wire.correlation, current.wire.operation, current.wire.messageFollowHopCount + 1, metadata ? current.ingress.parts[1] : undefined),
|
|
3289
|
+
...(metadata ? [current.ingress.parts[1]] : []),
|
|
3290
|
+
current.ingress.parts[metadata ? 2 : 1]
|
|
3230
3291
|
];
|
|
3231
3292
|
if (current.wire.kind === 'spotSend') {
|
|
3232
3293
|
if (!(await this.raw.sendService(state.target.targetNodeRid, parts)))
|
|
@@ -3341,26 +3402,6 @@ class ServiceStatefulRuntime {
|
|
|
3341
3402
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('actor', actor.actorId);
|
|
3342
3403
|
return route;
|
|
3343
3404
|
}
|
|
3344
|
-
tryBoundSessionSendFence(actor, senderFence) {
|
|
3345
|
-
if (senderFence === undefined ||
|
|
3346
|
-
senderFence.targetNodeGeneration !== this.nodeGeneration ||
|
|
3347
|
-
senderFence.authorityOwnerGeneration <= 0n ||
|
|
3348
|
-
senderFence.ownerLeaseGeneration <= 0n) {
|
|
3349
|
-
return undefined;
|
|
3350
|
-
}
|
|
3351
|
-
const local = actor.nodeRid === this.nodeRid ? this.registry.actor(actor.actorId) : undefined;
|
|
3352
|
-
if (local === undefined ||
|
|
3353
|
-
!sameActorRef(local.ref, actor) ||
|
|
3354
|
-
local.authorityOwnerGeneration !== senderFence.authorityOwnerGeneration) {
|
|
3355
|
-
return undefined;
|
|
3356
|
-
}
|
|
3357
|
-
return {
|
|
3358
|
-
actor,
|
|
3359
|
-
targetNodeGeneration: senderFence.targetNodeGeneration,
|
|
3360
|
-
authorityOwnerGeneration: senderFence.authorityOwnerGeneration,
|
|
3361
|
-
ownerLeaseGeneration: senderFence.ownerLeaseGeneration
|
|
3362
|
-
};
|
|
3363
|
-
}
|
|
3364
3405
|
tryActorFence(actor) {
|
|
3365
3406
|
const local = actor.nodeRid === this.nodeRid ? this.registry.actor(actor.actorId) : undefined;
|
|
3366
3407
|
if (local !== undefined && sameActorRef(local.ref, actor)) {
|
|
@@ -3558,8 +3599,7 @@ function isEntrySpotFence(fence) {
|
|
|
3558
3599
|
return (fence.spot.spotId === fence.targetNodeRid &&
|
|
3559
3600
|
fence.spot.generation === fence.targetNodeGeneration &&
|
|
3560
3601
|
fence.authorityOwnerGeneration === fence.targetNodeGeneration &&
|
|
3561
|
-
fence.ownerLeaseGeneration === fence.targetNodeGeneration
|
|
3562
|
-
fence.storeVersion === `entry:${fence.targetNodeGeneration}`);
|
|
3602
|
+
fence.ownerLeaseGeneration === fence.targetNodeGeneration);
|
|
3563
3603
|
}
|
|
3564
3604
|
function userSpotDeadline(deadlineUnixMs) {
|
|
3565
3605
|
const controller = new AbortController();
|
|
@@ -278,6 +278,7 @@ export type ServiceSessionRelocationRoute = {
|
|
|
278
278
|
readonly targetAuthorityOwnerGeneration: bigint;
|
|
279
279
|
readonly targetNodeRid: string;
|
|
280
280
|
readonly targetNodeGeneration: bigint;
|
|
281
|
+
readonly targetOwnerLeaseGeneration: bigint;
|
|
281
282
|
};
|
|
282
283
|
} | {
|
|
283
284
|
readonly relocation: ServiceWireOperationId;
|
|
@@ -414,8 +415,10 @@ export type ServiceBoundSessionTransition = {
|
|
|
414
415
|
export type ServiceStatefulWireRecord = {
|
|
415
416
|
readonly kind: 'spotSend' | 'spotRequest';
|
|
416
417
|
readonly correlation?: bigint;
|
|
418
|
+
readonly operation: ServiceWireOperationId;
|
|
419
|
+
readonly messageFollowHopCount: number;
|
|
417
420
|
readonly sourceSpotId: string;
|
|
418
|
-
readonly target:
|
|
421
|
+
readonly target: ServiceSpotRouteFence;
|
|
419
422
|
} | {
|
|
420
423
|
readonly kind: 'logicalMulticast';
|
|
421
424
|
readonly channelName: string;
|
|
@@ -424,6 +427,8 @@ export type ServiceStatefulWireRecord = {
|
|
|
424
427
|
} | {
|
|
425
428
|
readonly kind: 'actorSend' | 'actorRequest';
|
|
426
429
|
readonly correlation?: bigint;
|
|
430
|
+
readonly operation: ServiceWireOperationId;
|
|
431
|
+
readonly messageFollowHopCount: number;
|
|
427
432
|
readonly sourceActor?: ServiceActorRef;
|
|
428
433
|
readonly target: ServiceActorRouteFence;
|
|
429
434
|
readonly boundSession?: ServiceBoundSessionSource;
|
|
@@ -521,8 +526,8 @@ export interface ServiceStatefulReply {
|
|
|
521
526
|
readonly failureCode: number;
|
|
522
527
|
readonly tail?: ServiceStatefulReplyTail;
|
|
523
528
|
}
|
|
524
|
-
export declare function encodeSpotHeader(kind: 'spotSend' | 'spotRequest', sourceSpotId: string, target: ServiceDirectSpotRouteFence, correlation?: bigint): Buffer;
|
|
525
|
-
export declare function encodeActorHeader(kind: 'actorSend' | 'actorRequest', target: ServiceActorRouteFence, correlation?: bigint, sourceActor?: ServiceActorRef, boundSession?: ServiceBoundSessionSource): Buffer;
|
|
529
|
+
export declare function encodeSpotHeader(kind: 'spotSend' | 'spotRequest', sourceSpotId: string, target: ServiceDirectSpotRouteFence, correlation?: bigint, operation?: ServiceWireOperationId, messageFollowHopCount?: number, metadataFrame?: Uint8Array): Buffer;
|
|
530
|
+
export declare function encodeActorHeader(kind: 'actorSend' | 'actorRequest', target: ServiceActorRouteFence, correlation?: bigint, sourceActor?: ServiceActorRef, boundSession?: ServiceBoundSessionSource, operation?: ServiceWireOperationId, messageFollowHopCount?: number): Buffer;
|
|
526
531
|
export declare function encodeLogicalMulticastHeader(channelName: string, topic: string, sourceSpotId: string): Buffer;
|
|
527
532
|
export declare function encodeActorLookupHeader(correlation: bigint, actorId: string): Buffer;
|
|
528
533
|
export declare function encodeActorDestroyHeader(correlation: bigint, actor: ServiceActorRouteFence): Buffer;
|
|
@@ -553,7 +558,7 @@ export declare function encodeUserSpotCreateHeader(record: Omit<ServiceUserSpotC
|
|
|
553
558
|
export declare function encodeActorCreateHeader(record: Omit<ServiceActorCreateRecord, 'kind'>): Buffer;
|
|
554
559
|
export declare function encodeUserSpotCloseHeader(record: Omit<ServiceUserSpotCloseRecord, 'kind'>): Buffer;
|
|
555
560
|
export declare function encodeMessageFollowHeader(record: Omit<ServiceMessageFollowRecord, 'kind'>): Buffer;
|
|
556
|
-
export declare function decodeStatefulHeader(frame: Uint8Array): ServiceStatefulWireRecord;
|
|
561
|
+
export declare function decodeStatefulHeader(frame: Uint8Array, payloadFrame?: Uint8Array, metadataFrame?: Uint8Array): ServiceStatefulWireRecord;
|
|
557
562
|
export declare function encodeStatefulReply(correlation: bigint, terminalResult: number, failureCode: number, tail?: ServiceStatefulReplyTail): Buffer;
|
|
558
563
|
/** Encodes canonical maintenance relocation commands 30, 31, 34, 40, 52, and 53. */
|
|
559
564
|
export declare function encodeMaintenanceRelocationControl(value: ServiceMaintenanceRelocationControl): Buffer;
|