@zlink-systems/framework 0.29.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +1 -2
- package/dist/contracts/Configuration/Configs.d.ts +0 -5
- package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
- package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
- package/dist/contracts/Configuration/index.d.ts +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/runtime/actors/actor-handoff.d.ts +3 -2
- package/dist/runtime/actors/actor-handoff.js +9 -4
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +3 -1
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +6 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +3 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.js +5 -0
- package/dist/runtime/application-jobs/contracts.d.ts +5 -1
- package/dist/runtime/backend/contracts/index.d.ts +10 -19
- package/dist/runtime/backend/mesh-completion-table.d.ts +6 -4
- package/dist/runtime/backend/mesh-completion-table.js +28 -18
- package/dist/runtime/backend/mesh-dispatch-pump.js +21 -25
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +24 -29
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +11 -6
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +10 -12
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +64 -98
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +10 -5
- package/dist/runtime/backend/raw-binding-port.d.ts +9 -2
- package/dist/runtime/channels/channel-receive-loops.js +3 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
- package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
- package/dist/runtime/channels/channel-socket-registry.js +59 -82
- package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow.js +3 -3
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +15 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +193 -64
- package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
- package/dist/runtime/foundation/service-liveness-registry.js +57 -44
- package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
- package/dist/runtime/foundation/service-mailbox.js +2 -1
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +7 -6
- package/dist/runtime/foundation/service-stateful-runtime.js +34 -23
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -2
- package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
- package/dist/runtime/foundation/service-topology-registry.d.ts +5 -3
- package/dist/runtime/foundation/service-topology-registry.js +9 -4
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-runtime-options-factory.js +1 -1
- package/dist/runtime/host/application-job-queue.d.ts +11 -4
- package/dist/runtime/host/application-job-queue.js +66 -10
- package/dist/runtime/host/entry-actor-runtime.js +1 -1
- package/dist/runtime/host/index.js +15 -11
- package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
- package/dist/runtime/host/instance-activation-authority.js +89 -25
- package/dist/runtime/host/service-relocation-host-runtime.js +2 -2
- package/dist/runtime/host/spot-address-transport.d.ts +1 -0
- package/dist/runtime/host/spot-address-transport.js +25 -12
- package/dist/runtime/host/spot-runtime-options-factory.js +2 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
- package/dist/runtime/locations/domain-store-contract.d.ts +2 -2
- package/dist/runtime/locations/in-memory-authority-store.d.ts +4 -2
- package/dist/runtime/locations/in-memory-authority-store.js +80 -8
- package/dist/runtime/locations/in-memory-location-store.d.ts +2 -2
- package/dist/runtime/locations/in-memory-location-store.js +19 -3
- package/dist/runtime/locations/internal-location-contracts.d.ts +3 -0
- package/dist/runtime/locations/location-store-repository.d.ts +3 -2
- package/dist/runtime/locations/location-store-repository.js +165 -22
- package/dist/runtime/locations/resolvers.d.ts +2 -1
- package/dist/runtime/locations/resolvers.js +10 -1
- package/dist/runtime/messaging/submission-result.d.ts +1 -1
- package/dist/runtime/messaging/submission-result.js +2 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +2 -0
- package/dist/runtime/spots/index.d.ts +4 -3
- package/dist/runtime/spots/index.js +14 -14
- package/dist/runtime/spots/spot-activation.d.ts +2 -1
- package/dist/runtime/spots/spot-activation.js +4 -4
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
- package/dist/runtime/spots/spot-entry-activation.js +3 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +2 -1
- package/dist/runtime/spots/spot-node-runtime-manager.js +4 -11
- package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
- package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -1
- package/dist/runtime/streams/stream-session-runtime.js +1 -1
- package/package.json +3 -3
- package/src/contracts/Configuration/Builders.ts +1 -2
- package/src/contracts/Configuration/Configs.ts +0 -6
- package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
- package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
- package/src/contracts/Configuration/index.ts +1 -6
- package/src/internal.ts +1 -0
- package/src/runtime/actors/actor-handoff.ts +13 -4
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +12 -2
- package/src/runtime/application-jobs/application-job-queue-scope.ts +6 -1
- package/src/runtime/application-jobs/contracts.ts +14 -1
- package/src/runtime/backend/contracts/index.ts +10 -18
- package/src/runtime/backend/mesh-completion-table.ts +36 -19
- package/src/runtime/backend/mesh-dispatch-pump.ts +19 -22
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
- package/src/runtime/backend/node/node-backend-adapter-support.ts +31 -29
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
- package/src/runtime/backend/node/node-raw-binding-port.ts +19 -10
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +81 -111
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +12 -8
- package/src/runtime/backend/raw-binding-port.ts +12 -2
- package/src/runtime/channels/channel-receive-loops.ts +3 -3
- package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
- package/src/runtime/channels/channel-socket-registry.ts +84 -130
- package/src/runtime/diagnostics/message-flow.ts +1 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +268 -70
- package/src/runtime/foundation/service-liveness-registry.ts +68 -59
- package/src/runtime/foundation/service-mailbox.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +61 -35
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
- package/src/runtime/foundation/service-topology-registry.ts +13 -7
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-runtime-options-factory.ts +1 -0
- package/src/runtime/host/application-job-queue.ts +77 -10
- package/src/runtime/host/entry-actor-runtime.ts +1 -0
- package/src/runtime/host/index.ts +24 -5
- package/src/runtime/host/instance-activation-authority.ts +132 -27
- package/src/runtime/host/service-relocation-host-runtime.ts +2 -0
- package/src/runtime/host/spot-address-transport.ts +45 -22
- package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
- package/src/runtime/locations/domain-store-contract.ts +6 -2
- package/src/runtime/locations/in-memory-authority-store.ts +113 -9
- package/src/runtime/locations/in-memory-location-store.ts +25 -3
- package/src/runtime/locations/internal-location-contracts.ts +4 -0
- package/src/runtime/locations/location-store-repository.ts +220 -15
- package/src/runtime/locations/resolvers.ts +25 -2
- package/src/runtime/messaging/submission-result.ts +2 -2
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +2 -0
- package/src/runtime/spots/index.ts +16 -0
- package/src/runtime/spots/spot-activation.ts +5 -0
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
- package/src/runtime/spots/spot-entry-activation.ts +3 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +2 -0
- package/src/runtime/streams/stream-session-runtime.ts +1 -1
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ApplicationJobQueue = exports.ApplicationJobQueuePermit = void 0;
|
|
4
4
|
exports.resolveApplicationJobQueueConfiguration = resolveApplicationJobQueueConfiguration;
|
|
5
5
|
exports.nodeEffectiveProcessorCount = nodeEffectiveProcessorCount;
|
|
6
|
+
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
7
|
+
const message_flow_1 = require("../diagnostics/message-flow");
|
|
6
8
|
const runtime_metrics_1 = require("../diagnostics/runtime-metrics");
|
|
7
9
|
const Dispatch_1 = require("../../contracts/Dispatch");
|
|
8
10
|
const Registration_1 = require("../../contracts/Configuration/Registration");
|
|
@@ -50,9 +52,11 @@ function resolveApplicationJobQueueConfiguration(options = {}, effectiveProcesso
|
|
|
50
52
|
}
|
|
51
53
|
class ApplicationJobQueuePermit {
|
|
52
54
|
owner;
|
|
55
|
+
origin;
|
|
53
56
|
state = 'reserved';
|
|
54
|
-
constructor(owner) {
|
|
57
|
+
constructor(owner, origin) {
|
|
55
58
|
this.owner = owner;
|
|
59
|
+
this.origin = origin;
|
|
56
60
|
}
|
|
57
61
|
markApplicationQueued() {
|
|
58
62
|
if (this.state !== 'reserved') {
|
|
@@ -86,6 +90,9 @@ class ApplicationJobQueue {
|
|
|
86
90
|
configuration;
|
|
87
91
|
nowMs;
|
|
88
92
|
handlerStartGate;
|
|
93
|
+
loggerFailureReporter;
|
|
94
|
+
localWaiters = 0;
|
|
95
|
+
localBacklogLogged = false;
|
|
89
96
|
reservedSupplyPermits = 0n;
|
|
90
97
|
queuedApplicationJobs = 0n;
|
|
91
98
|
peakPermitsInUse = 0n;
|
|
@@ -104,10 +111,11 @@ class ApplicationJobQueue {
|
|
|
104
111
|
waiters = [];
|
|
105
112
|
receiveFlowTargets = new Map();
|
|
106
113
|
receiveFlowController;
|
|
107
|
-
constructor(configuration, nowMs = () => performance.now(), handlerStartGate) {
|
|
114
|
+
constructor(configuration, nowMs = () => performance.now(), handlerStartGate, loggerFailureReporter) {
|
|
108
115
|
this.configuration = configuration;
|
|
109
116
|
this.nowMs = nowMs;
|
|
110
117
|
this.handlerStartGate = handlerStartGate;
|
|
118
|
+
this.loggerFailureReporter = loggerFailureReporter;
|
|
111
119
|
this.receiveFlowController = new receive_flow_controller_1.ApplicationJobReceiveFlowController(this, (state) => state);
|
|
112
120
|
}
|
|
113
121
|
shouldHoldPermitBeforeHandler() {
|
|
@@ -153,15 +161,24 @@ class ApplicationJobQueue {
|
|
|
153
161
|
this.receiveFlowTargets.delete(identity);
|
|
154
162
|
this.receiveFlowController.unregister(target);
|
|
155
163
|
}
|
|
156
|
-
acquire(signal) {
|
|
164
|
+
acquire(signal, origin) {
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
const permit = this.acquireOrResume(resolve, reject, signal, origin);
|
|
167
|
+
if (permit !== undefined)
|
|
168
|
+
resolve(permit);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
acquireOrResume(resume, reject, signal, origin) {
|
|
157
172
|
if (signal?.aborted === true) {
|
|
158
|
-
|
|
173
|
+
reject(abortReason(signal));
|
|
174
|
+
return undefined;
|
|
159
175
|
}
|
|
160
176
|
if (this.waiters.length === 0 && this.permitsInUse() < this.limit()) {
|
|
161
|
-
return
|
|
177
|
+
return this.reserve(origin);
|
|
162
178
|
}
|
|
163
|
-
|
|
179
|
+
new Promise((resolve, reject) => {
|
|
164
180
|
const waiter = {
|
|
181
|
+
origin,
|
|
165
182
|
resolve,
|
|
166
183
|
reject,
|
|
167
184
|
signal,
|
|
@@ -172,9 +189,15 @@ class ApplicationJobQueue {
|
|
|
172
189
|
};
|
|
173
190
|
this.waiters.push(waiter);
|
|
174
191
|
this.capacityWaitCount += 1n;
|
|
192
|
+
const warningCount = this.updateLocalWaiters(origin, 1);
|
|
175
193
|
signal?.addEventListener('abort', waiter.abort, { once: true });
|
|
176
194
|
this.drainWaiters();
|
|
177
|
-
|
|
195
|
+
if (warningCount !== undefined)
|
|
196
|
+
this.logLocalBacklog(warningCount);
|
|
197
|
+
})
|
|
198
|
+
.then(resume)
|
|
199
|
+
.catch(reject);
|
|
200
|
+
return undefined;
|
|
178
201
|
}
|
|
179
202
|
snapshot() {
|
|
180
203
|
const permitsInUse = this.permitsInUse();
|
|
@@ -253,14 +276,14 @@ class ApplicationJobQueue {
|
|
|
253
276
|
permitsInUse() {
|
|
254
277
|
return this.reservedSupplyPermits + this.queuedApplicationJobs;
|
|
255
278
|
}
|
|
256
|
-
reserve(evaluatePressure = true) {
|
|
279
|
+
reserve(origin, evaluatePressure = true) {
|
|
257
280
|
this.reservedSupplyPermits += 1n;
|
|
258
281
|
const current = this.permitsInUse();
|
|
259
282
|
if (current > this.peakPermitsInUse)
|
|
260
283
|
this.peakPermitsInUse = current;
|
|
261
284
|
if (evaluatePressure)
|
|
262
285
|
this.evaluatePressure();
|
|
263
|
-
return new ApplicationJobQueuePermit(this);
|
|
286
|
+
return new ApplicationJobQueuePermit(this, origin);
|
|
264
287
|
}
|
|
265
288
|
drainWaiters() {
|
|
266
289
|
while (this.waiters.length > 0 && this.permitsInUse() < this.limit()) {
|
|
@@ -270,7 +293,7 @@ class ApplicationJobQueue {
|
|
|
270
293
|
waiter.active = false;
|
|
271
294
|
waiter.signal?.removeEventListener('abort', waiter.abort);
|
|
272
295
|
this.recordCompletedWait(waiter);
|
|
273
|
-
waiter.resolve(this.reserve(false));
|
|
296
|
+
waiter.resolve(this.reserve(waiter.origin, false));
|
|
274
297
|
}
|
|
275
298
|
}
|
|
276
299
|
cancel(waiter) {
|
|
@@ -286,11 +309,44 @@ class ApplicationJobQueue {
|
|
|
286
309
|
this.drainWaiters();
|
|
287
310
|
}
|
|
288
311
|
recordCompletedWait(waiter) {
|
|
312
|
+
this.updateLocalWaiters(waiter.origin, -1);
|
|
289
313
|
if (waiter.metricsEpoch !== this.metricsEpoch)
|
|
290
314
|
return;
|
|
291
315
|
const durationMs = Math.max(0, this.nowMs() - waiter.startedAtMs);
|
|
292
316
|
this.capacityWaitDurationSeconds += durationMs / runtime_metrics_1.MILLISECONDS_PER_SECOND;
|
|
293
317
|
}
|
|
318
|
+
updateLocalWaiters(origin, delta) {
|
|
319
|
+
if (origin !== 'local')
|
|
320
|
+
return undefined;
|
|
321
|
+
this.localWaiters += delta;
|
|
322
|
+
if (this.localWaiters === 0)
|
|
323
|
+
this.localBacklogLogged = false;
|
|
324
|
+
if (!this.localBacklogLogged && this.localWaiters > Number(this.limit())) {
|
|
325
|
+
this.localBacklogLogged = true;
|
|
326
|
+
return this.localWaiters;
|
|
327
|
+
}
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
logLocalBacklog(localWaiters) {
|
|
331
|
+
try {
|
|
332
|
+
message_flow_1.telemetryLogger.emit({
|
|
333
|
+
eventName: 'zlink.runtime.host.local_job_backlog_exceeded',
|
|
334
|
+
timestamp: new Date(),
|
|
335
|
+
severityNumber: api_logs_1.SeverityNumber.WARN,
|
|
336
|
+
severityText: 'WARN',
|
|
337
|
+
body: 'Same-host jobs waiting for a host permit exceeded the application job queue maximum.',
|
|
338
|
+
attributes: {
|
|
339
|
+
source_kind: 'host',
|
|
340
|
+
source_name: 'zlink.runtime.host',
|
|
341
|
+
local_waiters: localWaiters,
|
|
342
|
+
effective_maximum: Number(this.limit())
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
this.loggerFailureReporter?.(error);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
294
350
|
evaluatePressure() {
|
|
295
351
|
const permitsInUse = this.permitsInUse();
|
|
296
352
|
const next = this.pressureStateValue === 'running'
|
|
@@ -66,7 +66,7 @@ class ZLinkEntryActorRuntimeService {
|
|
|
66
66
|
}
|
|
67
67
|
return {
|
|
68
68
|
handled: true,
|
|
69
|
-
response: await spotManager.dispatchRoutedActorPacket(spotId, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef)
|
|
69
|
+
response: await spotManager.dispatchRoutedActorPacket('remote', spotId, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef)
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
requireActorManager() {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ZLinkUserSpotCreationCoordinator = exports.ZLinkHostSpotAddressTransport = exports.ZLinkRelocationStateIncompatibleError = exports.ZLinkRouteMeshRuntimeCoordinator = exports.ZLinkRetiringRollbackError = exports.ZLinkDrainingStatePublishError = exports.transferIdString = exports.ZLinkActorTransferAuthorityRuntime = exports.ZLinkFrameworkRuntimeHost = void 0;
|
|
4
4
|
exports.hasUnsupportedManualTopology = hasUnsupportedManualTopology;
|
|
5
5
|
exports.hasExactPeerReadiness = hasExactPeerReadiness;
|
|
6
|
+
const application_job_queue_scope_1 = require("../application-jobs/application-job-queue-scope");
|
|
6
7
|
const location_store_pages_1 = require("../locations/location-store-pages");
|
|
7
8
|
const stream_wire_1 = require("@zlink-systems/stream-wire");
|
|
8
9
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -21,7 +22,7 @@ const actor_message_follow_context_1 = require("../actors/actor-message-follow-c
|
|
|
21
22
|
const actor_transport_delivery_gate_1 = require("../actors/actor-transport-delivery-gate");
|
|
22
23
|
const admission_1 = require("../admission");
|
|
23
24
|
const application_job_queue_handler_start_gate_1 = require("../application-jobs/application-job-queue-handler-start-gate");
|
|
24
|
-
const
|
|
25
|
+
const application_job_queue_scope_2 = require("../application-jobs/application-job-queue-scope");
|
|
25
26
|
const backend_1 = require("../backend");
|
|
26
27
|
const runtime_message_1 = require("../backend/runtime-message");
|
|
27
28
|
const runtime_values_1 = require("../backend/runtime-values");
|
|
@@ -161,7 +162,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
161
162
|
catch {
|
|
162
163
|
return false;
|
|
163
164
|
}
|
|
164
|
-
});
|
|
165
|
+
}, (error) => (this.errorSink ?? this.preStartErrorSink).reportRuntimeTaskException('logger-provider', error));
|
|
165
166
|
this.capacityStatus = new host_capacity_status_1.HostCapacityStatusProjection(options.registration.coreHwm, this.applicationJobQueue);
|
|
166
167
|
this.clientServerRuntime = new topology_runtime_projections_1.ZLinkClientServerRuntimeProjection(() => this.channelRuntime, () => this.runtimeState);
|
|
167
168
|
this.fanoutRuntime = new topology_runtime_projections_1.ZLinkFanoutRuntimeProjection(() => this.channelRuntime, () => this.runtimeState);
|
|
@@ -452,12 +453,12 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
452
453
|
},
|
|
453
454
|
sessionRelocationWire: () => this.serviceRelocation,
|
|
454
455
|
clearRemoteActorPacketTarget: (actorId) => this.boundSessionRelay.clearRemoteActorPacketTarget(actorId),
|
|
455
|
-
prepareApplicationJob: async (preparationSignal) => {
|
|
456
|
+
prepareApplicationJob: async (preparationSignal, origin) => {
|
|
456
457
|
const runtimeSignal = this.executionState?.abortController.signal;
|
|
457
458
|
const signal = runtimeSignal === undefined
|
|
458
459
|
? preparationSignal
|
|
459
460
|
: AbortSignal.any([runtimeSignal, preparationSignal]);
|
|
460
|
-
const permit = await this.applicationJobQueue.acquire(signal);
|
|
461
|
+
const permit = await this.applicationJobQueue.acquire(signal, origin);
|
|
461
462
|
let state = 'ready';
|
|
462
463
|
let closedReason;
|
|
463
464
|
let abort;
|
|
@@ -491,7 +492,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
491
492
|
state = 'running';
|
|
492
493
|
signal.removeEventListener('abort', abort);
|
|
493
494
|
try {
|
|
494
|
-
return await (0,
|
|
495
|
+
return await (0, application_job_queue_scope_2.runWithApplicationJobPermit)(permit, operation);
|
|
495
496
|
}
|
|
496
497
|
finally {
|
|
497
498
|
state = 'closed';
|
|
@@ -1245,6 +1246,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
1245
1246
|
}
|
|
1246
1247
|
activationNode.registerAsyncInstanceActivationAuthority?.(new instance_activation_authority_1.ZLinkInstanceActivationAuthority({
|
|
1247
1248
|
store: locationStore,
|
|
1249
|
+
relocationPolicy: (stableType) => this.options.registration.spotNodes.get(meshName)?.instanceSpotFactoryRegistrations?.[stableType]?.relocation.kind,
|
|
1248
1250
|
relocationStore: this.options.registration.locations.relocationStoreInstance,
|
|
1249
1251
|
meshName,
|
|
1250
1252
|
owner: () => this.locationOwner.currentRuntime?.currentOwnerToken,
|
|
@@ -1579,6 +1581,8 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
1579
1581
|
});
|
|
1580
1582
|
const coordinator = (this.userSpotCoordinator = new user_spot_creation_coordinator_1.ZLinkUserSpotCreationCoordinator({
|
|
1581
1583
|
store: locationStore,
|
|
1584
|
+
relocationPolicy: (meshName, stableType) => this.options.registration.spotNodes.get(meshName)?.spotFactoryRegistrations?.[stableType]
|
|
1585
|
+
?.relocation.kind,
|
|
1582
1586
|
publishReadyRoute: (meshName, route) => {
|
|
1583
1587
|
this.cachedLocationSpotRouteResolver?.invalidate?.(route.spot.spotId);
|
|
1584
1588
|
this.spotNodeRuntime?.meshNode(meshName)?.rememberSpotRoute?.(route);
|
|
@@ -1961,11 +1965,11 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
1961
1965
|
ownerLeaseGeneration: record.source.ownerLeaseGeneration
|
|
1962
1966
|
});
|
|
1963
1967
|
},
|
|
1964
|
-
meshRecordDispatcher: (meshName, owner, record) => this.dispatchMeshRecord(meshName, owner, record, this.executionState?.abortController.signal),
|
|
1968
|
+
meshRecordDispatcher: (meshName, owner, record) => this.dispatchMeshRecord(application_job_queue_scope_1.currentApplicationJobOrigin, meshName, owner, record, this.executionState?.abortController.signal),
|
|
1965
1969
|
activationConcurrency: (meshName) => this.activationAdmission.current(meshName)
|
|
1966
1970
|
};
|
|
1967
1971
|
}
|
|
1968
|
-
async dispatchMeshRecord(meshName, owner, record, signal) {
|
|
1972
|
+
async dispatchMeshRecord(applicationJobOrigin, meshName, owner, record, signal) {
|
|
1969
1973
|
if (record.operationKind === service_runtime_contracts_1.OperationKind.ActorJoin) {
|
|
1970
1974
|
if (this.spotManager === undefined) {
|
|
1971
1975
|
throw new ConfigurationException_1.ZLinkConfigurationException('MeshNode Actor join dispatch requires the Spot manager.');
|
|
@@ -2023,7 +2027,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
2023
2027
|
nodeRid: binding.actor.nodeRid
|
|
2024
2028
|
};
|
|
2025
2029
|
if (sessionOwnerIsLocal) {
|
|
2026
|
-
(0,
|
|
2030
|
+
(0, application_job_queue_scope_2.releaseApplicationJobPermitBeforeHandler)();
|
|
2027
2031
|
await this.streamBindingRuntime.retireRemoteBinding(actorRef, binding.sessionRid, binding.bindingGeneration, signal);
|
|
2028
2032
|
}
|
|
2029
2033
|
state.retireBoundSessionBinding(binding);
|
|
@@ -2109,7 +2113,7 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
2109
2113
|
if (this.spotManager === undefined) {
|
|
2110
2114
|
throw new ConfigurationException_1.ZLinkConfigurationException('MeshNode Actor dispatch requires the Spot manager.');
|
|
2111
2115
|
}
|
|
2112
|
-
return this.admission.run(meshName, 'RouteMesh Actor dispatch', () => this.spotManager.dispatchMeshActor(meshName, owner, record));
|
|
2116
|
+
return this.admission.run(meshName, 'RouteMesh Actor dispatch', () => this.spotManager.dispatchMeshActor(applicationJobOrigin(), meshName, owner, record));
|
|
2113
2117
|
case service_runtime_contracts_1.ReceiveKind.SendReady:
|
|
2114
2118
|
return Promise.resolve();
|
|
2115
2119
|
default:
|
|
@@ -2143,9 +2147,9 @@ class ZLinkFrameworkRuntimeHost {
|
|
|
2143
2147
|
try {
|
|
2144
2148
|
state.taskRunner.runDetached('mesh-node-local-route-dispatch', async () => {
|
|
2145
2149
|
try {
|
|
2146
|
-
const permit = await this.applicationJobQueue.acquire(state.abortController.signal);
|
|
2150
|
+
const permit = await this.applicationJobQueue.acquire(state.abortController.signal, 'local');
|
|
2147
2151
|
permit.markApplicationQueued();
|
|
2148
|
-
await (0,
|
|
2152
|
+
await (0, application_job_queue_scope_2.runWithApplicationJobPermit)(permit, () => channelRuntime.dispatchLocalMeshRoute(meshName, sourceNodeRid, ownedParts));
|
|
2149
2153
|
}
|
|
2150
2154
|
finally {
|
|
2151
2155
|
for (const part of ownedParts)
|
|
@@ -5,6 +5,7 @@ import type { ServiceSpotState } from '../foundation/service-stateful-registry';
|
|
|
5
5
|
import type { ServiceInstanceActivationTarget, ServiceInstanceRouteFence } from '../foundation/service-stateful-wire-codec';
|
|
6
6
|
import { type ServiceInstanceActivationRecoveryEnvelope } from '../foundation/service-instance-activation-recovery-codec';
|
|
7
7
|
export interface ZLinkInstanceActivationAuthorityOptions {
|
|
8
|
+
readonly relocationPolicy?: (stableType: string) => import('../locations/internal-location-contracts').ZLinkObjectReserveRequest['actorRelocationPolicy'];
|
|
8
9
|
readonly store: ZLinkObjectCreationStore & ZLinkAuthorityStore;
|
|
9
10
|
readonly relocationStore?: ZLinkRelocationStore;
|
|
10
11
|
readonly meshName: string;
|
|
@@ -16,7 +17,7 @@ export declare class ZLinkInstanceActivationAuthority implements ServiceAsyncIns
|
|
|
16
17
|
private readonly options;
|
|
17
18
|
private readonly pending;
|
|
18
19
|
constructor(options: ZLinkInstanceActivationAuthorityOptions);
|
|
19
|
-
read(target: ServiceInstanceActivationTarget): Promise<ServiceInstanceAuthorityRead>;
|
|
20
|
+
read(target: ServiceInstanceActivationTarget, instanceIntent?: true, activation?: ServiceInstanceActivationRecoveryEnvelope, acceptsLocal?: (route: ServiceInstanceRouteFence) => boolean): Promise<ServiceInstanceAuthorityRead>;
|
|
20
21
|
reserve(activation: Omit<ServiceInstanceActivationRecoveryEnvelope, 'targetMeshName'>, signal?: AbortSignal): Promise<ServiceInstanceAuthorityReserve>;
|
|
21
22
|
resume(target: ServiceInstanceActivationTarget, pending: ServicePendingInstanceActivation): Promise<ServiceInstanceActivationReservation>;
|
|
22
23
|
commit(target: ServiceInstanceActivationTarget, reservation: ServiceInstanceActivationReservation, spot: ServiceSpotState, deadlineUnixMs?: bigint): Promise<{
|
|
@@ -17,9 +17,71 @@ class ZLinkInstanceActivationAuthority {
|
|
|
17
17
|
constructor(options) {
|
|
18
18
|
this.options = options;
|
|
19
19
|
}
|
|
20
|
-
async read(target) {
|
|
21
|
-
const
|
|
22
|
-
|
|
20
|
+
async read(target, instanceIntent, activation, acceptsLocal) {
|
|
21
|
+
const key = authorityKey(target.targetSpotId);
|
|
22
|
+
const current = await this.options.store.readAuthority(key);
|
|
23
|
+
if (current.kind !== 'snapshot')
|
|
24
|
+
return { kind: 'missing' };
|
|
25
|
+
const ready = (0, service_authority_payload_codec_1.decodeServiceInstanceAuthorityPayload)(current.payload);
|
|
26
|
+
const resolved = readyRead(current, target, ready);
|
|
27
|
+
if (ready?.state === 'ready' &&
|
|
28
|
+
resolved.kind === 'ready' &&
|
|
29
|
+
acceptsLocal?.(resolved.route) === true) {
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
if (activation !== undefined &&
|
|
33
|
+
current.allocation.objectKind === 'instance_spot' &&
|
|
34
|
+
(0, routing_id_1.routingIdsEqual)(current.allocation.descriptor.rid, target.targetNodeRid) &&
|
|
35
|
+
current.allocation.descriptorLifecycleGeneration === target.targetNodeGeneration) {
|
|
36
|
+
const reference = current.pendingCreation?.requestContentReference ?? ready?.activationRecovery?.reference;
|
|
37
|
+
if (reference !== undefined) {
|
|
38
|
+
const root = await this.options.relocationStore?.read((0, relocation_blob_1.relocationBlobReference)(reference));
|
|
39
|
+
if (root?.kind !== 'found') {
|
|
40
|
+
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.DataLost, 'Stored Instance activation is missing.');
|
|
41
|
+
}
|
|
42
|
+
let stored;
|
|
43
|
+
try {
|
|
44
|
+
stored = (0, service_instance_activation_recovery_codec_1.decodeInstanceActivationRecoveryEnvelope)(root.bytes);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!(error instanceof TypeError || error instanceof RangeError))
|
|
48
|
+
throw error;
|
|
49
|
+
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.ProtocolError, 'Stored Instance activation is invalid.');
|
|
50
|
+
}
|
|
51
|
+
if (stored.operation.high === activation.operation.high &&
|
|
52
|
+
stored.operation.low === activation.operation.low &&
|
|
53
|
+
(stored.targetMeshName !== activation.targetMeshName ||
|
|
54
|
+
stored.target.stableType !== target.stableType ||
|
|
55
|
+
stored.target.descriptorVersion !== target.descriptorVersion ||
|
|
56
|
+
stored.deadlineUnixMs !== activation.deadlineUnixMs ||
|
|
57
|
+
(stored.metadataFrame === undefined) !== (activation.metadataFrame === undefined) ||
|
|
58
|
+
(stored.metadataFrame !== undefined &&
|
|
59
|
+
activation.metadataFrame !== undefined &&
|
|
60
|
+
Buffer.compare(stored.metadataFrame, activation.metadataFrame) !== 0))) {
|
|
61
|
+
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.ProtocolError, 'Instance route does not match the stored activation.');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (instanceIntent === true &&
|
|
66
|
+
current.allocation.state === 'active' &&
|
|
67
|
+
ready?.state === 'ready') {
|
|
68
|
+
if (current.allocation.objectKind !== 'instance_spot' ||
|
|
69
|
+
current.allocation.stableType !== target.stableType) {
|
|
70
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotTypeMismatch, 'Instance activation type does not match the current authority.');
|
|
71
|
+
}
|
|
72
|
+
const released = await this.options.store.releaseEndedReservation?.(key, current.storeVersion.value, undefined, {
|
|
73
|
+
key: { kind: 'instance_spot', globalId: target.targetSpotId },
|
|
74
|
+
intent: { stableType: target.stableType },
|
|
75
|
+
actorRelocationPolicy: this.options.relocationPolicy?.(target.stableType)
|
|
76
|
+
});
|
|
77
|
+
if (released === true)
|
|
78
|
+
return { kind: 'missing' };
|
|
79
|
+
const refreshed = await this.options.store.readAuthority(key);
|
|
80
|
+
return refreshed.kind === 'snapshot'
|
|
81
|
+
? readyRead(refreshed, target, (0, service_authority_payload_codec_1.decodeServiceInstanceAuthorityPayload)(refreshed.payload))
|
|
82
|
+
: { kind: 'missing' };
|
|
83
|
+
}
|
|
84
|
+
return resolved;
|
|
23
85
|
}
|
|
24
86
|
async reserve(activation, signal) {
|
|
25
87
|
const target = activation.target;
|
|
@@ -49,6 +111,7 @@ class ZLinkInstanceActivationAuthority {
|
|
|
49
111
|
try {
|
|
50
112
|
reserved = await this.options.store.reserve({
|
|
51
113
|
key: { kind: 'instance_spot', globalId: target.targetSpotId },
|
|
114
|
+
actorRelocationPolicy: this.options.relocationPolicy?.(target.stableType),
|
|
52
115
|
intent: {
|
|
53
116
|
stableType: target.stableType,
|
|
54
117
|
requestContentReference: stored.reference.value,
|
|
@@ -207,7 +270,7 @@ class ZLinkInstanceActivationAuthority {
|
|
|
207
270
|
}
|
|
208
271
|
const current = await this.options.store.readAuthority(authorityKey(target.targetSpotId));
|
|
209
272
|
if (current.kind === 'snapshot') {
|
|
210
|
-
const ready = readyRead(current, target);
|
|
273
|
+
const ready = readyRead(current, target, (0, service_authority_payload_codec_1.decodeServiceInstanceAuthorityPayload)(current.payload));
|
|
211
274
|
if (ready.kind === 'ready') {
|
|
212
275
|
this.pending.delete(reservation.token);
|
|
213
276
|
return { kind: 'lost', route: ready.route };
|
|
@@ -236,7 +299,7 @@ class ZLinkInstanceActivationAuthority {
|
|
|
236
299
|
}
|
|
237
300
|
const recovery = decoded.activationRecovery;
|
|
238
301
|
if (recovery === undefined)
|
|
239
|
-
return routeFromSnapshot(current);
|
|
302
|
+
return routeFromSnapshot(current, decoded.spotId);
|
|
240
303
|
let completed = current;
|
|
241
304
|
if (recovery.replayCursor < recovery.inboxSequence) {
|
|
242
305
|
const cursorStored = await this.options.store.compareExchangeAuthority(key, current.storeVersion, {
|
|
@@ -338,19 +401,16 @@ class ZLinkInstanceActivationAuthority {
|
|
|
338
401
|
}
|
|
339
402
|
}
|
|
340
403
|
exports.ZLinkInstanceActivationAuthority = ZLinkInstanceActivationAuthority;
|
|
341
|
-
function readyRead(snapshot, target) {
|
|
342
|
-
|
|
343
|
-
(0, service_authority_payload_codec_1.decodeServiceClosingSpotAuthority)(snapshot.payload);
|
|
344
|
-
const creating = (0, service_authority_payload_codec_1.decodeServiceInstanceAuthorityPayload)(snapshot.payload);
|
|
345
|
-
if (creating?.state === 'coldActivating' &&
|
|
404
|
+
function readyRead(snapshot, target, decoded) {
|
|
405
|
+
if (decoded?.state === 'coldActivating' &&
|
|
346
406
|
snapshot.allocation.objectKind === 'instance_spot' &&
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
(0, routing_id_1.routingIdsEqual)(
|
|
407
|
+
decoded.stableType === target.stableType &&
|
|
408
|
+
decoded.spotId === target.targetSpotId &&
|
|
409
|
+
decoded.ownerId === snapshot.ownerId &&
|
|
410
|
+
decoded.ownerLeaseGeneration === snapshot.ownerLeaseGeneration &&
|
|
411
|
+
decoded.ownerMeshName === snapshot.allocation.descriptor.meshName &&
|
|
412
|
+
decoded.ownerNodeGeneration === snapshot.allocation.descriptorLifecycleGeneration &&
|
|
413
|
+
(0, routing_id_1.routingIdsEqual)(decoded.ownerNodeRid, snapshot.allocation.descriptor.rid) &&
|
|
354
414
|
(0, routing_id_1.routingIdsEqual)(target.targetNodeRid, snapshot.allocation.descriptor.rid) &&
|
|
355
415
|
target.targetNodeGeneration === snapshot.allocation.descriptorLifecycleGeneration) {
|
|
356
416
|
return {
|
|
@@ -360,7 +420,8 @@ function readyRead(snapshot, target) {
|
|
|
360
420
|
authority: snapshot
|
|
361
421
|
};
|
|
362
422
|
}
|
|
363
|
-
if (decoded
|
|
423
|
+
if (decoded === undefined ||
|
|
424
|
+
decoded.state === 'coldActivating' ||
|
|
364
425
|
decoded.stableType !== target.stableType ||
|
|
365
426
|
decoded.spotId !== target.targetSpotId ||
|
|
366
427
|
snapshot.allocation.objectKind !== 'instance_spot' ||
|
|
@@ -374,7 +435,7 @@ function readyRead(snapshot, target) {
|
|
|
374
435
|
target.targetNodeGeneration !== snapshot.allocation.descriptorLifecycleGeneration) {
|
|
375
436
|
return { kind: 'missing' };
|
|
376
437
|
}
|
|
377
|
-
return { kind: 'ready', route: routeFromSnapshot(snapshot), authority: snapshot };
|
|
438
|
+
return { kind: 'ready', route: routeFromSnapshot(snapshot, decoded.spotId), authority: snapshot };
|
|
378
439
|
}
|
|
379
440
|
function requireCommitIdentity(target, reservation, creating, spot, meshName) {
|
|
380
441
|
if (creating.allocation.state !== 'reserved' ||
|
|
@@ -392,16 +453,19 @@ function requireCommitIdentity(target, reservation, creating, spot, meshName) {
|
|
|
392
453
|
throw new Error('Instance activation Ready identity does not match its exact reservation.');
|
|
393
454
|
}
|
|
394
455
|
}
|
|
395
|
-
function routeFromSnapshot(snapshot) {
|
|
396
|
-
|
|
397
|
-
(0, service_authority_payload_codec_1.
|
|
398
|
-
|
|
399
|
-
|
|
456
|
+
function routeFromSnapshot(snapshot, spotId) {
|
|
457
|
+
if (spotId === undefined) {
|
|
458
|
+
const decoded = (0, service_authority_payload_codec_1.decodeServiceReadySpotAuthority)(snapshot.payload) ??
|
|
459
|
+
(0, service_authority_payload_codec_1.decodeServiceClosingSpotAuthority)(snapshot.payload);
|
|
460
|
+
if (decoded?.kind !== 'instance_spot') {
|
|
461
|
+
throw new Error('Instance authority is not Ready.');
|
|
462
|
+
}
|
|
463
|
+
spotId = decoded.spotId;
|
|
400
464
|
}
|
|
401
465
|
return {
|
|
402
466
|
targetNodeRid: String(snapshot.allocation.descriptor.rid),
|
|
403
467
|
targetNodeGeneration: snapshot.allocation.descriptorLifecycleGeneration,
|
|
404
|
-
targetSpotId:
|
|
468
|
+
targetSpotId: spotId,
|
|
405
469
|
objectGeneration: snapshot.objectGeneration,
|
|
406
470
|
ownerId: snapshot.ownerId,
|
|
407
471
|
authorityOwnerGeneration: snapshot.authorityOwnerGeneration,
|
|
@@ -3227,9 +3227,9 @@ class LocalTargetPort {
|
|
|
3227
3227
|
if (runtime === undefined) {
|
|
3228
3228
|
throw new Error('Relocated Entry Spot Actor dispatch is unavailable.');
|
|
3229
3229
|
}
|
|
3230
|
-
return runtime.dispatchEntryActorPacket(hidden.actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
|
|
3230
|
+
return runtime.dispatchEntryActorPacket('remote', hidden.actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
|
|
3231
3231
|
}
|
|
3232
|
-
return this.requireSpotManager().dispatchRoutedActorPacket(state.spotId, hidden.actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
|
|
3232
|
+
return this.requireSpotManager().dispatchRoutedActorPacket('remote', state.spotId, hidden.actor.context.actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef);
|
|
3233
3233
|
});
|
|
3234
3234
|
hidden.replayResults.push(...results);
|
|
3235
3235
|
}
|
|
@@ -31,6 +31,7 @@ export declare class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTr
|
|
|
31
31
|
private reportInstanceRequestError;
|
|
32
32
|
private traceInstanceAddress;
|
|
33
33
|
private resolveExisting;
|
|
34
|
+
private reactivationCall;
|
|
34
35
|
private selectMissingTarget;
|
|
35
36
|
private validateExisting;
|
|
36
37
|
private encode;
|
|
@@ -30,7 +30,10 @@ class ZLinkHostSpotAddressTransport {
|
|
|
30
30
|
}
|
|
31
31
|
async sendToSpotAddressScoped(spotId, message, call) {
|
|
32
32
|
const activationDeadlineUnixMs = BigInt(Math.round(Date.now() + this.options.defaultRequestTimeoutMs));
|
|
33
|
-
const
|
|
33
|
+
const resolution = await this.resolveExisting(spotId, undefined, call);
|
|
34
|
+
const existing = resolution !== undefined && !('kind' in resolution) ? resolution : undefined;
|
|
35
|
+
if (resolution !== undefined && 'kind' in resolution)
|
|
36
|
+
call = this.reactivationCall(resolution, call);
|
|
34
37
|
if (existing !== undefined) {
|
|
35
38
|
this.validateExisting(existing, call);
|
|
36
39
|
try {
|
|
@@ -64,7 +67,7 @@ class ZLinkHostSpotAddressTransport {
|
|
|
64
67
|
if (!call.instanceSpot) {
|
|
65
68
|
return { status: submission_result_1.ZLinkSubmitStatus.TargetNotFound };
|
|
66
69
|
}
|
|
67
|
-
const selected = this.selectMissingTarget(spotId, call);
|
|
70
|
+
const selected = this.selectMissingTarget(spotId, call, resolution);
|
|
68
71
|
if (selected.kind === 'unsupported') {
|
|
69
72
|
this.traceInstanceAddress(ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped, ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send, spotId, message, call.initialMeshName, call.instanceSpotType, undefined, ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget);
|
|
70
73
|
return { status: submission_result_1.ZLinkSubmitStatus.TargetNotFound };
|
|
@@ -91,10 +94,13 @@ class ZLinkHostSpotAddressTransport {
|
|
|
91
94
|
const timeoutMs = call.timeoutMs ?? this.options.defaultRequestTimeoutMs;
|
|
92
95
|
const deadline = createSpotAddressDeadline(timeoutMs, call.signal);
|
|
93
96
|
try {
|
|
94
|
-
const
|
|
97
|
+
const resolution = await this.resolveExisting(spotId, deadline.signal, call);
|
|
98
|
+
const existing = resolution !== undefined && !('kind' in resolution) ? resolution : undefined;
|
|
99
|
+
if (resolution !== undefined && 'kind' in resolution)
|
|
100
|
+
call = this.reactivationCall(resolution, call);
|
|
95
101
|
deadline.requireRemaining();
|
|
96
102
|
if (existing === undefined) {
|
|
97
|
-
return await this.requestToMissingInstance(spotId, request, call, deadline);
|
|
103
|
+
return await this.requestToMissingInstance(spotId, request, call, deadline, resolution);
|
|
98
104
|
}
|
|
99
105
|
this.validateExisting(existing, call);
|
|
100
106
|
try {
|
|
@@ -143,11 +149,11 @@ class ZLinkHostSpotAddressTransport {
|
|
|
143
149
|
this.traceInstanceAddress(ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.ReplyReceived, ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Request, spotId, request, existing.routerChannelId, existing.stableType, existing.targetNodeRid);
|
|
144
150
|
return reply;
|
|
145
151
|
}
|
|
146
|
-
async requestToMissingInstance(spotId, request, call, deadline) {
|
|
152
|
+
async requestToMissingInstance(spotId, request, call, deadline, current) {
|
|
147
153
|
if (!call.instanceSpot) {
|
|
148
154
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestTargetNotFound, `Spot '${String(spotId)}' has no Ready authority.`);
|
|
149
155
|
}
|
|
150
|
-
const selected = this.selectMissingTarget(spotId, call);
|
|
156
|
+
const selected = this.selectMissingTarget(spotId, call, current);
|
|
151
157
|
if (selected.kind === 'capacity') {
|
|
152
158
|
throw missingInstancePlacementCapacity(spotId, call.instanceSpotType);
|
|
153
159
|
}
|
|
@@ -214,13 +220,15 @@ class ZLinkHostSpotAddressTransport {
|
|
|
214
220
|
errorReason
|
|
215
221
|
});
|
|
216
222
|
}
|
|
217
|
-
async resolveExisting(spotId, signal) {
|
|
223
|
+
async resolveExisting(spotId, signal, call) {
|
|
218
224
|
const resolver = this.options.resolver();
|
|
219
225
|
if (resolver === undefined) {
|
|
220
226
|
throw new Error('Global Spot address resolution requires a Location Store.');
|
|
221
227
|
}
|
|
222
228
|
try {
|
|
223
|
-
return await (0, abort_1.awaitWithAbort)(
|
|
229
|
+
return await (0, abort_1.awaitWithAbort)(call?.instanceSpot === true
|
|
230
|
+
? resolver.resolve(spotId, signal, true)
|
|
231
|
+
: resolver.resolve(spotId, signal), signal);
|
|
224
232
|
}
|
|
225
233
|
catch (error) {
|
|
226
234
|
if (error instanceof contracts_1.ZLinkFrameworkException &&
|
|
@@ -230,7 +238,11 @@ class ZLinkHostSpotAddressTransport {
|
|
|
230
238
|
throw error;
|
|
231
239
|
}
|
|
232
240
|
}
|
|
233
|
-
|
|
241
|
+
reactivationCall(route, call) {
|
|
242
|
+
this.validateExisting(route, call);
|
|
243
|
+
return { ...call, initialMeshName: route.meshName, instanceSpotType: route.stableType };
|
|
244
|
+
}
|
|
245
|
+
selectMissingTarget(spotId, call, current) {
|
|
234
246
|
const configuredMeshes = this.options.meshNames();
|
|
235
247
|
if (call.initialMeshName !== undefined &&
|
|
236
248
|
this.options.isMeshConfigured?.(call.initialMeshName) === false) {
|
|
@@ -253,11 +265,11 @@ class ZLinkHostSpotAddressTransport {
|
|
|
253
265
|
const stableType = call.instanceSpotType ?? (distinctTypes.length === 1 ? distinctTypes[0] : undefined);
|
|
254
266
|
if (stableType === undefined) {
|
|
255
267
|
if (distinctTypes.length === 0)
|
|
256
|
-
return { kind: 'unsupported' };
|
|
268
|
+
return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
257
269
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.InvalidOperation, 'Instance Spot type is required when multiple types are registered.');
|
|
258
270
|
}
|
|
259
271
|
if (canInspectPlacementTypes && !distinctTypes.includes(stableType)) {
|
|
260
|
-
return { kind: 'unsupported' };
|
|
272
|
+
return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
261
273
|
}
|
|
262
274
|
let unavailable = false;
|
|
263
275
|
let capacity = false;
|
|
@@ -276,6 +288,7 @@ class ZLinkHostSpotAddressTransport {
|
|
|
276
288
|
node,
|
|
277
289
|
target: {
|
|
278
290
|
...placement.target,
|
|
291
|
+
targetMeshName: meshName,
|
|
279
292
|
targetSpotId: String(spotId),
|
|
280
293
|
stableType
|
|
281
294
|
}
|
|
@@ -293,7 +306,7 @@ class ZLinkHostSpotAddressTransport {
|
|
|
293
306
|
if (capacity)
|
|
294
307
|
return { kind: 'capacity' };
|
|
295
308
|
if (unsupported)
|
|
296
|
-
return { kind: 'unsupported' };
|
|
309
|
+
return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
297
310
|
return { kind: 'unavailable' };
|
|
298
311
|
}
|
|
299
312
|
validateExisting(target, call) {
|
|
@@ -25,12 +25,12 @@ class ZLinkSpotRuntimeOptionsFactory {
|
|
|
25
25
|
?.notifyPrimaryEntrySpotActorLeft(actor, signal, actorRef, membershipEpoch) ??
|
|
26
26
|
Promise.resolve()
|
|
27
27
|
},
|
|
28
|
-
dispatchEntryActorPacket: (actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) => {
|
|
28
|
+
dispatchEntryActorPacket: (origin, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin) => {
|
|
29
29
|
const runtime = this.options.spotNodeRuntime();
|
|
30
30
|
if (runtime === undefined) {
|
|
31
31
|
throw new configuration_1.ZLinkConfigurationException('Entry Spot actor packet dispatch requires the MeshNode runtime.');
|
|
32
32
|
}
|
|
33
|
-
return runtime.dispatchEntryActorPacket(actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin);
|
|
33
|
+
return runtime.dispatchEntryActorPacket(origin, actorId, parts, returnResponse, remoteBoundSessionTarget, fallbackActorRef, requestTerminal, messageFollowOrigin);
|
|
34
34
|
},
|
|
35
35
|
dispatchEntryActorJoin: async (meshName, actor, handoffBacklog) => {
|
|
36
36
|
const runtime = this.options.spotNodeRuntime();
|
|
@@ -5,6 +5,7 @@ import type { ZLinkAuthoritySnapshot, ZLinkLocationOwnerToken } from '../locatio
|
|
|
5
5
|
import type { ZLinkAuthorityStore, ZLinkObjectCreationStore } from '../locations/internal-store-contracts';
|
|
6
6
|
import type { ZLinkLocalSpotCreateResult } from '../spots/spot-manager-internal-contracts';
|
|
7
7
|
export interface ZLinkUserSpotCreationCoordinatorOptions {
|
|
8
|
+
readonly relocationPolicy?: (meshName: string, stableType: string) => import('../locations/internal-location-contracts').ZLinkObjectReserveRequest['actorRelocationPolicy'];
|
|
8
9
|
readonly store: ZLinkObjectCreationStore & ZLinkAuthorityStore;
|
|
9
10
|
readonly target: (request: Pick<ZLinkUserSpotCreationRequest, 'meshName' | 'stableType'>, signal?: AbortSignal, excludedNodeRids?: ReadonlySet<string>) => Promise<{
|
|
10
11
|
readonly meshName: string;
|
|
@@ -62,6 +62,7 @@ class ZLinkUserSpotCreationCoordinator {
|
|
|
62
62
|
try {
|
|
63
63
|
reserved = await this.options.store.reserve({
|
|
64
64
|
key: { kind: 'user_spot', globalId: String(request.spotId) },
|
|
65
|
+
actorRelocationPolicy: this.options.relocationPolicy?.(target.meshName, request.stableType),
|
|
65
66
|
intent: {
|
|
66
67
|
stableType: request.stableType,
|
|
67
68
|
requestContentReference: contentReference,
|