@zlink-systems/framework 0.29.0 → 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/actors/actor-runtime-contracts.d.ts +1 -0
- package/dist/runtime/actors/index.d.ts +2 -0
- package/dist/runtime/actors/index.js +21 -6
- 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 +60 -41
- 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/handlers/handler-instance-scope.js +1 -1
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-placement-coordinator.d.ts +2 -1
- package/dist/runtime/host/actor-placement-coordinator.js +2 -1
- package/dist/runtime/host/actor-runtime-options-factory.d.ts +2 -1
- package/dist/runtime/host/actor-runtime-options-factory.js +2 -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.d.ts +1 -1
- package/dist/runtime/host/index.js +18 -13
- 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 +3 -2
- package/dist/runtime/locations/in-memory-authority-store.d.ts +5 -2
- package/dist/runtime/locations/in-memory-authority-store.js +107 -14
- package/dist/runtime/locations/in-memory-location-store.d.ts +3 -3
- package/dist/runtime/locations/in-memory-location-store.js +31 -13
- package/dist/runtime/locations/internal-location-contracts.d.ts +8 -0
- package/dist/runtime/locations/location-store-repository.d.ts +4 -2
- package/dist/runtime/locations/location-store-repository.js +209 -33
- 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.d.ts +1 -0
- package/dist/runtime/spots/spot-entry-activation.js +6 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +3 -1
- package/dist/runtime/spots/spot-node-runtime-manager.js +10 -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/spots/spot-serial-executor.d.ts +1 -0
- package/dist/runtime/spots/spot-serial-executor.js +10 -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/actors/actor-runtime-contracts.ts +4 -0
- package/src/runtime/actors/index.ts +77 -42
- 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 +109 -77
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
- package/src/runtime/foundation/service-topology-registry.ts +13 -7
- package/src/runtime/handlers/handler-instance-scope.ts +2 -1
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-placement-coordinator.ts +8 -2
- package/src/runtime/host/actor-runtime-options-factory.ts +7 -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 +30 -7
- 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 +153 -12
- package/src/runtime/locations/in-memory-location-store.ts +39 -13
- package/src/runtime/locations/internal-location-contracts.ts +10 -0
- package/src/runtime/locations/location-store-repository.ts +295 -36
- 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 +7 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +14 -12
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +2 -0
- package/src/runtime/spots/spot-serial-executor.ts +10 -4
- package/src/runtime/streams/stream-session-runtime.ts +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ApplicationJobRecordLease } from '../application-jobs/application-ingress-record-owner';
|
|
2
|
+
import type { ReceiveRecord } from './service-runtime-contracts';
|
|
2
3
|
export type ServiceMailboxDomain = 'application' | 'infrastructure';
|
|
3
4
|
export interface ServiceMailboxRecord {
|
|
4
5
|
readonly owner: string;
|
|
@@ -17,6 +18,8 @@ export interface ServiceMailboxRecord {
|
|
|
17
18
|
readonly stateful?: unknown;
|
|
18
19
|
/** Host queue permit plus its ordinary Framework-owned ingress record. */
|
|
19
20
|
readonly applicationJob?: ApplicationJobRecordLease;
|
|
21
|
+
/** Unregistered raw-pull terminal, retained by the existing mailbox owner. */
|
|
22
|
+
readonly completion?: ReceiveRecord;
|
|
20
23
|
}
|
|
21
24
|
export interface ServiceMailboxClaim {
|
|
22
25
|
readonly owner: string;
|
|
@@ -24,7 +24,8 @@ class ServiceMailbox {
|
|
|
24
24
|
record.parts = [];
|
|
25
25
|
}
|
|
26
26
|
tryEnqueue(record) {
|
|
27
|
-
if (record.owner.length === 0 ||
|
|
27
|
+
if (record.owner.length === 0 ||
|
|
28
|
+
(record.parts.length === 0 && record.completion === undefined)) {
|
|
28
29
|
throw new TypeError('Mailbox records require an owner and retained payload.');
|
|
29
30
|
}
|
|
30
31
|
const target = this.domain(record.domain);
|
|
@@ -5,7 +5,7 @@ import type { ServiceInstanceActivationRecoveryEnvelope } from './service-instan
|
|
|
5
5
|
import type { ServiceMailboxRecord } from './service-mailbox';
|
|
6
6
|
import { type ReceiveKindData, type ServiceStreamSessionBinding, type StreamSessionActorAuthorityFence } from './service-runtime-contracts';
|
|
7
7
|
import { ServiceStatefulRegistry, type ServiceActorRef, type ServiceActorState, type ServiceSessionBinding, type ServiceSpotRef, type ServiceSpotState } from './service-stateful-registry';
|
|
8
|
-
import { type ServiceActorCreateRecord, type ServiceActorRouteFence, type ServiceDirectSpotRouteFence, type ServiceInstanceActivationTarget, type ServiceInstanceRouteFence, type ServiceRetiredBoundSessionRouteFence, type ServiceStatefulReplyTail, type ServiceStatefulWireRecord, type ServiceUserSpotCloseRecord, type ServiceUserSpotCreateRecord } from './service-stateful-wire-codec';
|
|
8
|
+
import { type ServiceActorCreateRecord, type ServiceActorRouteFence, type ServiceDirectSpotRouteFence, type ServiceInstanceActivationTarget, type ServiceInstanceColdActivationTarget, type ServiceInstanceRouteFence, type ServiceRetiredBoundSessionRouteFence, type ServiceStatefulReplyTail, type ServiceStatefulWireRecord, type ServiceUserSpotCloseRecord, type ServiceUserSpotCreateRecord } from './service-stateful-wire-codec';
|
|
9
9
|
import { type ServiceApplicationPayload } from './service-wire-m6a-codec';
|
|
10
10
|
export interface ServiceSpotMessageFollowSeal {
|
|
11
11
|
readonly key: string;
|
|
@@ -148,7 +148,7 @@ export interface ServiceInstanceActivationAuthority {
|
|
|
148
148
|
* operation completes; the binding callback itself never blocks.
|
|
149
149
|
*/
|
|
150
150
|
export interface ServiceAsyncInstanceActivationAuthority {
|
|
151
|
-
read(target: ServiceInstanceActivationTarget): Promise<ServiceInstanceAuthorityRead>;
|
|
151
|
+
read(target: ServiceInstanceActivationTarget, instanceIntent?: true, activation?: ServiceInstanceActivationRecoveryEnvelope, acceptsLocal?: (route: ServiceInstanceRouteFence) => boolean): Promise<ServiceInstanceAuthorityRead>;
|
|
152
152
|
reserve(activation: Omit<ServiceInstanceActivationRecoveryEnvelope, 'targetMeshName'>, signal?: AbortSignal): Promise<ServiceInstanceAuthorityReserve>;
|
|
153
153
|
resume(target: ServiceInstanceActivationTarget, pending: ServicePendingInstanceActivation): Promise<ServiceInstanceActivationReservation>;
|
|
154
154
|
commit(target: ServiceInstanceActivationTarget, reservation: ServiceInstanceActivationReservation, spot: ServiceSpotState, deadlineUnixMs?: bigint): Promise<{
|
|
@@ -280,11 +280,11 @@ export declare class ServiceStatefulRuntime {
|
|
|
280
280
|
readonly bindingGeneration: bigint;
|
|
281
281
|
}): ServiceStatefulPendingOperation;
|
|
282
282
|
sendToInstanceSpot(route: ServiceInstanceRouteFence, payload: ServiceApplicationPayload, sourceSpotId?: string, metadataFrame?: Uint8Array, instanceIntent?: boolean): Promise<number>;
|
|
283
|
-
sendToMissingInstanceSpot(target:
|
|
284
|
-
sendToMissingInstanceSpotFrame(target:
|
|
283
|
+
sendToMissingInstanceSpot(target: ServiceInstanceColdActivationTarget, payload: ServiceApplicationPayload, deadlineUnixMs: bigint, sourceSpotId?: string, metadataFrame?: Uint8Array): Promise<number>;
|
|
284
|
+
sendToMissingInstanceSpotFrame(target: ServiceInstanceColdActivationTarget, payloadFrame: Buffer, deadlineUnixMs: bigint, sourceSpotId?: string, metadataFrame?: Uint8Array): Promise<number>;
|
|
285
285
|
requestToInstanceSpot(route: ServiceInstanceRouteFence, payload: ServiceApplicationPayload, timeoutMs: number, sourceSpotId?: string, metadataFrame?: Uint8Array, instanceIntent?: boolean): ServiceStatefulPendingOperation;
|
|
286
|
-
requestToMissingInstanceSpot(target:
|
|
287
|
-
requestToMissingInstanceSpotFrame(target:
|
|
286
|
+
requestToMissingInstanceSpot(target: ServiceInstanceColdActivationTarget, payload: ServiceApplicationPayload, timeoutMs: number, sourceSpotId?: string, metadataFrame?: Uint8Array): ServiceStatefulPendingOperation;
|
|
287
|
+
requestToMissingInstanceSpotFrame(target: ServiceInstanceColdActivationTarget, payloadFrame: Buffer, deadlineUnixMs: bigint, sourceSpotId?: string, metadataFrame?: Uint8Array): ServiceStatefulPendingOperation;
|
|
288
288
|
lookupRemoteActor(targetNodeRid: string, actorId: string, timeoutMs: number): ServiceStatefulPendingOperation;
|
|
289
289
|
destroyActor(actor: ServiceActorRef, timeoutMs: number): ServiceStatefulPendingOperation;
|
|
290
290
|
joinActor(actor: ServiceActorRef, targetNodeRid: string, targetSpot: ServiceSpotRef, targetSpotGeneration: bigint, payload: ServiceApplicationPayload | undefined, timeoutMs: number): ServiceStatefulPendingOperation;
|
|
@@ -324,6 +324,7 @@ export declare class ServiceStatefulRuntime {
|
|
|
324
324
|
private requireReadyInstanceApplicationRoute;
|
|
325
325
|
private validateInstanceIngress;
|
|
326
326
|
private activateMissingInstance;
|
|
327
|
+
private localReadyInstance;
|
|
327
328
|
private activateMissingInstanceAsync;
|
|
328
329
|
private runMissingInstanceActivation;
|
|
329
330
|
private acceptsLocalMissingInstancePlacement;
|
|
@@ -345,7 +345,7 @@ class ServiceStatefulRuntime {
|
|
|
345
345
|
const record = {
|
|
346
346
|
kind: 'instanceSpot',
|
|
347
347
|
activation: 'missing',
|
|
348
|
-
target,
|
|
348
|
+
target: { ...target, targetMeshName: envelope.targetMeshName },
|
|
349
349
|
sourceNodeGeneration: envelope.sourceNodeGeneration,
|
|
350
350
|
sourceNodeRid: envelope.sourceNodeRid,
|
|
351
351
|
...(envelope.sourceSpotId === undefined ? {} : { sourceSpotId: envelope.sourceSpotId }),
|
|
@@ -362,7 +362,7 @@ class ServiceStatefulRuntime {
|
|
|
362
362
|
flags: envelope.metadataFrame === undefined ? 0 : service_stateful_wire_codec_1.M6bServiceWireFlag.metadata,
|
|
363
363
|
sourceRoutingId: envelope.sourceNodeRid,
|
|
364
364
|
parts: [
|
|
365
|
-
(0, service_stateful_wire_codec_1.encodeInstanceSpotActivationHeader)(target, envelope.sourceNodeGeneration, envelope.sourceNodeRid, envelope.sourceSpotId, envelope.operationKind, envelope.operation, envelope.deadlineUnixMs, envelope.replyRouteId, envelope.metadataFrame !== undefined)
|
|
365
|
+
(0, service_stateful_wire_codec_1.encodeInstanceSpotActivationHeader)(record.target, envelope.sourceNodeGeneration, envelope.sourceNodeRid, envelope.sourceSpotId, envelope.operationKind, envelope.operation, envelope.deadlineUnixMs, envelope.replyRouteId, envelope.metadataFrame !== undefined)
|
|
366
366
|
],
|
|
367
367
|
applicationJobOwner
|
|
368
368
|
}, record, Buffer.from(envelope.applicationPayloadFrame), spot, undefined, terminal.onTerminalCompletion, envelope.metadataFrame === undefined
|
|
@@ -754,7 +754,7 @@ class ServiceStatefulRuntime {
|
|
|
754
754
|
const timeoutMs = remainingDeadlineMs(deadlineUnixMs);
|
|
755
755
|
const pending = this.operations.register(timeoutMs);
|
|
756
756
|
this.submitRequest(pending, target.targetNodeRid, instanceOperationParts([
|
|
757
|
-
(0, service_stateful_wire_codec_1.encodeInstanceSpotActivationHeader)(target, this.nodeGeneration, this.nodeRid, sourceSpotId, 'request', { high:
|
|
757
|
+
(0, service_stateful_wire_codec_1.encodeInstanceSpotActivationHeader)(target, this.nodeGeneration, this.nodeRid, sourceSpotId, 'request', { high: operation_identity_1.ZLINK_NATIVE_CORRELATION_OPERATION_NAMESPACE, low: pending.id }, deadlineUnixMs, pending.id, metadataFrame !== undefined),
|
|
758
758
|
payloadFrame
|
|
759
759
|
], metadataFrame), timeoutMs, 'instanceSpotRequest');
|
|
760
760
|
return pending;
|
|
@@ -1436,14 +1436,15 @@ class ServiceStatefulRuntime {
|
|
|
1436
1436
|
async continueMissingInstanceActivation(ingress, record, payloadFrame, localReply, metadataFrame) {
|
|
1437
1437
|
try {
|
|
1438
1438
|
this.validateInstanceIngress(ingress, record);
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1439
|
+
await this.activateMissingInstanceAsync(record, payloadFrame, metadataFrame, (activation) => {
|
|
1440
|
+
if (this.closed)
|
|
1441
|
+
return;
|
|
1442
|
+
const terminal = this.activationTerminalCompletion(record.target, activation.route);
|
|
1443
|
+
const admitted = this.enqueueActivatedInstanceSpot(ingress, record, payloadFrame, activation.spot, localReply, terminal.onTerminalCompletion, metadataFrame, terminal.onHandlerTurnStarted, this.instanceApplicationTarget(record, activation.route.objectGeneration));
|
|
1444
|
+
if (admitted !== 'application') {
|
|
1445
|
+
throw new Error('Activated Instance message was not admitted to the local queue.');
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1447
1448
|
}
|
|
1448
1449
|
catch (error) {
|
|
1449
1450
|
this.finishMissingInstanceActivationFailure(ingress, record, error, localReply);
|
|
@@ -1738,12 +1739,43 @@ class ServiceStatefulRuntime {
|
|
|
1738
1739
|
}
|
|
1739
1740
|
return activation.spot;
|
|
1740
1741
|
}
|
|
1741
|
-
|
|
1742
|
-
const
|
|
1742
|
+
localReadyInstance(target, route) {
|
|
1743
|
+
const local = this.registry.spot(target.targetSpotId);
|
|
1744
|
+
if (local !== undefined &&
|
|
1745
|
+
(local.kind !== 'instance' || local.stableType !== target.stableType)) {
|
|
1746
|
+
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1747
|
+
}
|
|
1748
|
+
return local !== undefined &&
|
|
1749
|
+
local.state === 'ready' &&
|
|
1750
|
+
routeMatchesLocal(route, local, this.nodeRid, this.nodeGeneration)
|
|
1751
|
+
? local
|
|
1752
|
+
: undefined;
|
|
1753
|
+
}
|
|
1754
|
+
activateMissingInstanceAsync(record, payloadFrame, metadataFrame, admit) {
|
|
1755
|
+
const key = record.target.targetSpotId;
|
|
1743
1756
|
const pending = this.pendingInstanceActivations.get(key);
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1757
|
+
const ready = pending ??
|
|
1758
|
+
this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) => ({
|
|
1759
|
+
...activation,
|
|
1760
|
+
stableType: record.target.stableType
|
|
1761
|
+
}));
|
|
1762
|
+
const operation = ready.then(async (value) => {
|
|
1763
|
+
if (pending !== undefined) {
|
|
1764
|
+
await this.asyncInstanceAuthority?.read(record.target, undefined, {
|
|
1765
|
+
...record,
|
|
1766
|
+
targetMeshName: record.target.targetMeshName,
|
|
1767
|
+
...(metadataFrame === undefined ? {} : { metadataFrame }),
|
|
1768
|
+
applicationPayloadFrame: payloadFrame
|
|
1769
|
+
}, (route) => this.localReadyInstance(record.target, route) !== undefined);
|
|
1770
|
+
}
|
|
1771
|
+
if (value.stableType !== record.target.stableType) {
|
|
1772
|
+
throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.TypeMismatch, 'Instance Spot type does not match.');
|
|
1773
|
+
}
|
|
1774
|
+
admit(value);
|
|
1775
|
+
return value;
|
|
1776
|
+
});
|
|
1777
|
+
// The caller owns operation failure. Keep the activation available for later participants.
|
|
1778
|
+
const activation = operation.then((value) => value, () => ready);
|
|
1747
1779
|
this.pendingInstanceActivations.set(key, activation);
|
|
1748
1780
|
const clear = () => {
|
|
1749
1781
|
if (this.pendingInstanceActivations.get(key) === activation) {
|
|
@@ -1751,7 +1783,7 @@ class ServiceStatefulRuntime {
|
|
|
1751
1783
|
}
|
|
1752
1784
|
};
|
|
1753
1785
|
void activation.then(clear, clear);
|
|
1754
|
-
return
|
|
1786
|
+
return operation;
|
|
1755
1787
|
}
|
|
1756
1788
|
async runMissingInstanceActivation(record, payloadFrame, metadataFrame) {
|
|
1757
1789
|
const target = record.target;
|
|
@@ -1764,8 +1796,14 @@ class ServiceStatefulRuntime {
|
|
|
1764
1796
|
if (authority === undefined) {
|
|
1765
1797
|
throw new Error('Async Instance activation authority is not registered.');
|
|
1766
1798
|
}
|
|
1799
|
+
const activationRequest = {
|
|
1800
|
+
...record,
|
|
1801
|
+
targetMeshName: record.target.targetMeshName,
|
|
1802
|
+
...(metadataFrame === undefined ? {} : { metadataFrame }),
|
|
1803
|
+
applicationPayloadFrame: payloadFrame
|
|
1804
|
+
};
|
|
1805
|
+
const current = await authority.read(target, true, activationRequest, (route) => this.localReadyInstance(target, route) !== undefined);
|
|
1767
1806
|
const local = this.registry.spot(target.targetSpotId);
|
|
1768
|
-
const current = await authority.read(target);
|
|
1769
1807
|
if (current.kind === 'creating' &&
|
|
1770
1808
|
current.authority?.allocation.state === 'active' &&
|
|
1771
1809
|
this.instanceApplicationLifecycle?.isMaterializing?.(target) === true) {
|
|
@@ -1809,13 +1847,9 @@ class ServiceStatefulRuntime {
|
|
|
1809
1847
|
if (current.route.targetNodeGeneration !== this.nodeGeneration) {
|
|
1810
1848
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1811
1849
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
}
|
|
1816
|
-
if (local !== undefined &&
|
|
1817
|
-
routeMatchesLocal(current.route, local, this.nodeRid, this.nodeGeneration)) {
|
|
1818
|
-
return { spot: local, route: current.route };
|
|
1850
|
+
const readyLocal = this.localReadyInstance(target, current.route);
|
|
1851
|
+
if (readyLocal !== undefined) {
|
|
1852
|
+
return { spot: readyLocal, route: current.route };
|
|
1819
1853
|
}
|
|
1820
1854
|
return await this.reconcileReadyInstanceProjection(target, current.route, authority);
|
|
1821
1855
|
}
|
|
@@ -1852,18 +1886,7 @@ class ServiceStatefulRuntime {
|
|
|
1852
1886
|
const deadline = operationDeadline(record.deadlineUnixMs);
|
|
1853
1887
|
let reserved;
|
|
1854
1888
|
try {
|
|
1855
|
-
reserved = await authority.reserve(
|
|
1856
|
-
target,
|
|
1857
|
-
sourceNodeRid: record.sourceNodeRid,
|
|
1858
|
-
sourceNodeGeneration: record.sourceNodeGeneration,
|
|
1859
|
-
...(record.sourceSpotId === undefined ? {} : { sourceSpotId: record.sourceSpotId }),
|
|
1860
|
-
operationKind: record.operationKind,
|
|
1861
|
-
operation: record.operation,
|
|
1862
|
-
...(record.replyRouteId === undefined ? {} : { replyRouteId: record.replyRouteId }),
|
|
1863
|
-
deadlineUnixMs: record.deadlineUnixMs,
|
|
1864
|
-
...(metadataFrame === undefined ? {} : { metadataFrame }),
|
|
1865
|
-
applicationPayloadFrame: payloadFrame
|
|
1866
|
-
}, deadline.signal);
|
|
1889
|
+
reserved = await authority.reserve(activationRequest, deadline.signal);
|
|
1867
1890
|
}
|
|
1868
1891
|
finally {
|
|
1869
1892
|
deadline.close();
|
|
@@ -3855,10 +3878,6 @@ function instanceOperationKey(record) {
|
|
|
3855
3878
|
return (`${record.sourceNodeRid}\0${record.sourceNodeGeneration}\0` +
|
|
3856
3879
|
`${record.operation.high}\0${record.operation.low}`);
|
|
3857
3880
|
}
|
|
3858
|
-
function instanceActivationKey(record) {
|
|
3859
|
-
return (`${record.target.targetNodeRid}\0${record.target.targetNodeGeneration}\0` +
|
|
3860
|
-
`${record.target.targetSpotId}\0${record.target.stableType}`);
|
|
3861
|
-
}
|
|
3862
3881
|
function subscriptionKey(channelName, topicFilter) {
|
|
3863
3882
|
if (channelName.length === 0 || topicFilter.length === 0) {
|
|
3864
3883
|
throw new TypeError('Channel name and topic filter must be non-empty.');
|
|
@@ -320,6 +320,9 @@ export interface ServiceInstanceActivationTarget {
|
|
|
320
320
|
readonly stableType: string;
|
|
321
321
|
readonly descriptorVersion: string;
|
|
322
322
|
}
|
|
323
|
+
export interface ServiceInstanceColdActivationTarget extends ServiceInstanceActivationTarget {
|
|
324
|
+
readonly targetMeshName: string;
|
|
325
|
+
}
|
|
323
326
|
export interface ServiceUserSpotReservationFence {
|
|
324
327
|
readonly reservationId: string;
|
|
325
328
|
readonly expectedStoreVersion: string;
|
|
@@ -475,7 +478,7 @@ export type ServiceStatefulWireRecord = {
|
|
|
475
478
|
} | {
|
|
476
479
|
readonly kind: 'instanceSpot';
|
|
477
480
|
readonly activation: 'missing';
|
|
478
|
-
readonly target:
|
|
481
|
+
readonly target: ServiceInstanceColdActivationTarget;
|
|
479
482
|
readonly sourceNodeGeneration: bigint;
|
|
480
483
|
readonly sourceNodeRid: string;
|
|
481
484
|
readonly sourceSpotId?: string;
|
|
@@ -549,7 +552,7 @@ export declare function encodeInstanceSpotHeader(route: ServiceInstanceRouteFenc
|
|
|
549
552
|
readonly high: bigint;
|
|
550
553
|
readonly low: bigint;
|
|
551
554
|
}, replyRouteId?: bigint, hasMetadata?: boolean, instanceIntent?: boolean): Buffer;
|
|
552
|
-
export declare function encodeInstanceSpotActivationHeader(target:
|
|
555
|
+
export declare function encodeInstanceSpotActivationHeader(target: ServiceInstanceColdActivationTarget, sourceNodeGeneration: bigint, sourceNodeRid: string, sourceSpotId: string | undefined, operationKind: 'send' | 'request', operation: {
|
|
553
556
|
readonly high: bigint;
|
|
554
557
|
readonly low: bigint;
|
|
555
558
|
}, deadlineUnixMs: bigint, replyRouteId?: bigint, hasMetadata?: boolean): Buffer;
|
|
@@ -47,8 +47,6 @@ const service_wire_constants_generated_1 = require("./service-wire-constants.gen
|
|
|
47
47
|
const service_wire_m6a_codec_1 = require("./service-wire-m6a-codec");
|
|
48
48
|
const MESSAGE_FOLLOW_MAX_BODY_BYTES = 16 * 1024 * 1024;
|
|
49
49
|
const MESSAGE_FOLLOW_VERSION = 1;
|
|
50
|
-
const INSTANCE_ROUTE_VERSION = 1;
|
|
51
|
-
const INSTANCE_ACTIVATION_VERSION = 2;
|
|
52
50
|
const PREFIX_SIZE = service_wire_binary_primitives_1.SERVICE_WIRE_PREFIX_SIZE;
|
|
53
51
|
const MAGIC_0 = service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[0];
|
|
54
52
|
const MAGIC_1 = service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[1];
|
|
@@ -653,8 +651,17 @@ function encodeInstanceSpotActivationHeader(target, sourceNodeGeneration, source
|
|
|
653
651
|
if (operationKind === 'send' && replyRouteId !== undefined) {
|
|
654
652
|
throw new RangeError('Instance Spot send must not carry a reply route.');
|
|
655
653
|
}
|
|
656
|
-
const
|
|
657
|
-
|
|
654
|
+
const encodedRoute = (0, service_wire_codec_generated_1.encodeInstanceRouteV1)({
|
|
655
|
+
routeKind: 'coldActivation',
|
|
656
|
+
targetNodeRid: toGeneratedRoutingId(target.targetNodeRid, 'targetNodeRid'),
|
|
657
|
+
targetNodeGeneration: target.targetNodeGeneration,
|
|
658
|
+
targetSpotId: target.targetSpotId,
|
|
659
|
+
targetMeshName: target.targetMeshName,
|
|
660
|
+
stableType: target.stableType,
|
|
661
|
+
targetDescriptorVersion: target.descriptorVersion,
|
|
662
|
+
deadlineUnixMs
|
|
663
|
+
}, STATEFUL_MESSAGE_CONTEXT);
|
|
664
|
+
return concat(prefix(exports.M6bServiceWireCommand.instanceSpot, hasMetadata ? exports.M6bServiceWireFlag.metadata : 0), encodedRoute, u64Any(sourceNodeGeneration), rid(sourceNodeRid, 'sourceNodeRid'), optionalRid(sourceSpotId), Buffer.of(operationKind === 'send' ? 1 : 2), u64Any(operation.high), u64Any(operation.low), ...(operationKind === 'request' ? [u64(requirePositive(replyRouteId, 'replyRouteId'))] : []));
|
|
658
665
|
}
|
|
659
666
|
function encodeUserSpotCreateHeader(record) {
|
|
660
667
|
return Buffer.from((0, service_wire_pilot_codec_generated_1.encodeUserSpotCreate47)(toGeneratedUserSpotCreate(record)));
|
|
@@ -878,45 +885,27 @@ function decodeStatefulHeader(frame, payloadFrame, metadataFrame) {
|
|
|
878
885
|
fail(`Invalid command flags '${command.flags}'.`);
|
|
879
886
|
}
|
|
880
887
|
const routeStart = reader.offset;
|
|
881
|
-
|
|
882
|
-
if (version !== INSTANCE_ROUTE_VERSION && version !== INSTANCE_ACTIVATION_VERSION)
|
|
883
|
-
fail('Unsupported Instance route version.');
|
|
888
|
+
reader.u8('instanceRoute.kind');
|
|
884
889
|
const routeLength = reader.u16('instanceRoute.length');
|
|
885
890
|
const routeEnd = reader.offset + routeLength;
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
:
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
892
|
-
const
|
|
893
|
-
? {
|
|
894
|
-
targetNodeRid: fromGeneratedRoutingId(generatedReadyRoute.targetNodeRid, 'targetNodeRid'),
|
|
895
|
-
targetNodeGeneration: generatedReadyRoute.targetNodeGeneration,
|
|
896
|
-
targetSpotId: generatedReadyRoute.targetSpotId
|
|
897
|
-
}
|
|
898
|
-
: {
|
|
899
|
-
targetNodeRid: reader.rid('targetNodeRid'),
|
|
900
|
-
targetNodeGeneration: reader.nonZeroU64('targetNodeGeneration'),
|
|
901
|
-
targetSpotId: reader.rid('targetSpotId')
|
|
902
|
-
};
|
|
903
|
-
const route = generatedReadyRoute?.routeKind === 'ready'
|
|
904
|
-
? {
|
|
905
|
-
...commonTarget,
|
|
906
|
-
...generatedReadyRoute.authority
|
|
907
|
-
}
|
|
891
|
+
const generatedRoute = decodeCanonicalInstanceRoute(reader.bytes.subarray(routeStart, routeEnd));
|
|
892
|
+
const commonTarget = {
|
|
893
|
+
targetNodeRid: fromGeneratedRoutingId(generatedRoute.targetNodeRid, 'targetNodeRid'),
|
|
894
|
+
targetNodeGeneration: generatedRoute.targetNodeGeneration,
|
|
895
|
+
targetSpotId: generatedRoute.targetSpotId
|
|
896
|
+
};
|
|
897
|
+
const route = generatedRoute.routeKind === 'ready'
|
|
898
|
+
? { ...commonTarget, ...generatedRoute.authority }
|
|
908
899
|
: undefined;
|
|
909
|
-
const target =
|
|
900
|
+
const target = generatedRoute.routeKind === 'coldActivation'
|
|
910
901
|
? {
|
|
911
902
|
...commonTarget,
|
|
912
|
-
|
|
913
|
-
|
|
903
|
+
targetMeshName: generatedRoute.targetMeshName,
|
|
904
|
+
stableType: generatedRoute.stableType,
|
|
905
|
+
descriptorVersion: generatedRoute.targetDescriptorVersion
|
|
914
906
|
}
|
|
915
907
|
: undefined;
|
|
916
|
-
|
|
917
|
-
reader.offset = routeEnd;
|
|
918
|
-
if (reader.offset !== routeEnd)
|
|
919
|
-
fail('Invalid Instance route body length.');
|
|
908
|
+
reader.offset = routeEnd;
|
|
920
909
|
const sourceNodeGeneration = reader.nonZeroU64('sourceNodeGeneration');
|
|
921
910
|
const sourceNodeRid = reader.rid('sourceNodeRid');
|
|
922
911
|
const sourceSpotId = reader.optionalRid('sourceSpotId');
|
|
@@ -928,17 +917,17 @@ function decodeStatefulHeader(frame, payloadFrame, metadataFrame) {
|
|
|
928
917
|
low: reader.u64('operation.low')
|
|
929
918
|
};
|
|
930
919
|
const operationKind = operationValue === 1 ? 'send' : 'request';
|
|
931
|
-
if (
|
|
920
|
+
if (generatedRoute.routeKind === 'ready' &&
|
|
932
921
|
((operationKind === 'send' && (operation.high !== 0n || operation.low !== 0n)) ||
|
|
933
922
|
(operationKind === 'request' && operation.high === 0n && operation.low === 0n))) {
|
|
934
923
|
fail('Invalid Instance operation identity.');
|
|
935
924
|
}
|
|
936
|
-
if (
|
|
925
|
+
if (generatedRoute.routeKind === 'coldActivation' &&
|
|
937
926
|
operation.high === 0n &&
|
|
938
927
|
operation.low === 0n) {
|
|
939
928
|
fail('Instance activation requires a non-zero operation identity.');
|
|
940
929
|
}
|
|
941
|
-
const deadlineUnixMs =
|
|
930
|
+
const deadlineUnixMs = generatedRoute.routeKind === 'coldActivation' ? generatedRoute.deadlineUnixMs : undefined;
|
|
942
931
|
const replyRouteId = operationKind === 'request' ? reader.nonZeroU64('replyRouteId') : undefined;
|
|
943
932
|
reader.end();
|
|
944
933
|
const common = {
|
|
@@ -950,12 +939,12 @@ function decodeStatefulHeader(frame, payloadFrame, metadataFrame) {
|
|
|
950
939
|
operation,
|
|
951
940
|
...(replyRouteId === undefined ? {} : { replyRouteId })
|
|
952
941
|
};
|
|
953
|
-
return
|
|
942
|
+
return generatedRoute.routeKind === 'ready'
|
|
954
943
|
? {
|
|
955
944
|
...common,
|
|
956
945
|
activation: 'ready',
|
|
957
946
|
route: route,
|
|
958
|
-
instanceIntent:
|
|
947
|
+
instanceIntent: generatedRoute.instanceIntent === 'true'
|
|
959
948
|
}
|
|
960
949
|
: {
|
|
961
950
|
...common,
|
|
@@ -1375,10 +1364,6 @@ function rid(value, name) {
|
|
|
1375
1364
|
function text8(value, name) {
|
|
1376
1365
|
return sized8(value, name);
|
|
1377
1366
|
}
|
|
1378
|
-
function text16(value, name) {
|
|
1379
|
-
const bytes = (0, service_wire_binary_primitives_1.encodeCanonicalServiceWireText)(value, name, 0xffff, outOfRange);
|
|
1380
|
-
return concat(u16(bytes.byteLength), bytes);
|
|
1381
|
-
}
|
|
1382
1367
|
function optionalRid(value) {
|
|
1383
1368
|
return value === undefined ? Buffer.of(0) : rid(value, 'sourceSpotId');
|
|
1384
1369
|
}
|
|
@@ -1428,6 +1413,16 @@ function requireFlags(actual, expected) {
|
|
|
1428
1413
|
function concat(...parts) {
|
|
1429
1414
|
return Buffer.concat(parts.map((part) => Buffer.from(part)));
|
|
1430
1415
|
}
|
|
1416
|
+
function decodeCanonicalInstanceRoute(bytes) {
|
|
1417
|
+
try {
|
|
1418
|
+
return (0, service_wire_codec_generated_1.decodeInstanceRouteV1)(bytes, STATEFUL_MESSAGE_CONTEXT);
|
|
1419
|
+
}
|
|
1420
|
+
catch (error) {
|
|
1421
|
+
if (error instanceof RangeError)
|
|
1422
|
+
throw new service_wire_m6a_codec_1.ServiceWireProtocolError(error.message);
|
|
1423
|
+
throw error;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1431
1426
|
function fail(message) {
|
|
1432
1427
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError(message);
|
|
1433
1428
|
}
|
|
@@ -2009,22 +2004,9 @@ class FrozenReader {
|
|
|
2009
2004
|
}
|
|
2010
2005
|
instanceRoute() {
|
|
2011
2006
|
const start = this.offset;
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
const body = this.body16('Instance route');
|
|
2016
|
-
if (kind === INSTANCE_ROUTE_VERSION) {
|
|
2017
|
-
(0, service_wire_codec_generated_1.decodeInstanceRouteV1)(this.bytes.subarray(start, this.offset), STATEFUL_MESSAGE_CONTEXT);
|
|
2018
|
-
return;
|
|
2019
|
-
}
|
|
2020
|
-
body.rid8('targetNodeRid');
|
|
2021
|
-
body.nonZeroU64('targetNodeGeneration');
|
|
2022
|
-
body.text8('targetSpotId');
|
|
2023
|
-
body.text8('targetMeshName');
|
|
2024
|
-
body.text8('stableType');
|
|
2025
|
-
body.text8('targetDescriptorVersion');
|
|
2026
|
-
body.nonZeroU64('deadlineUnixMs');
|
|
2027
|
-
body.end('Instance route');
|
|
2007
|
+
this.u8('instanceRouteKind');
|
|
2008
|
+
this.body16('Instance route');
|
|
2009
|
+
decodeCanonicalInstanceRoute(this.bytes.subarray(start, this.offset));
|
|
2028
2010
|
}
|
|
2029
2011
|
relocationObject() {
|
|
2030
2012
|
const kind = this.u8('relocationObjectKind');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ServiceLivenessConnection } from './service-liveness-registry';
|
|
1
2
|
export type ServiceNodeState = 'preparing' | 'serving' | 'retiring' | 'draining' | 'stopped' | 'error';
|
|
2
3
|
export type ServiceObjectRole = 'none' | 'client' | 'server';
|
|
3
4
|
export interface ServiceChannelDescriptor {
|
|
@@ -25,7 +26,8 @@ export interface ServiceNodeDescriptor {
|
|
|
25
26
|
}
|
|
26
27
|
export interface AdmittedServicePeer {
|
|
27
28
|
readonly descriptor: ServiceNodeDescriptor;
|
|
28
|
-
readonly connectionId: string;
|
|
29
|
+
readonly connectionId: string | bigint;
|
|
30
|
+
readonly liveness?: ServiceLivenessConnection;
|
|
29
31
|
}
|
|
30
32
|
export interface ServicePeerAdmissionExpectation {
|
|
31
33
|
readonly endpoint?: string;
|
|
@@ -44,8 +46,8 @@ export declare class ServiceTopologyRegistry {
|
|
|
44
46
|
constructor(local: ServiceNodeDescriptor);
|
|
45
47
|
localDescriptor(): ServiceNodeDescriptor;
|
|
46
48
|
publishLocal(descriptor: ServiceNodeDescriptor): void;
|
|
47
|
-
admit(descriptor: ServiceNodeDescriptor, connectionId: string, expected?: ServicePeerAdmissionExpectation): PeerAdmissionResult;
|
|
48
|
-
disconnect(nodeRoutingId: string, connectionId: string): boolean;
|
|
49
|
+
admit(descriptor: ServiceNodeDescriptor, connectionId: string | bigint, expected?: ServicePeerAdmissionExpectation, admitLiveness?: () => ServiceLivenessConnection): PeerAdmissionResult;
|
|
50
|
+
disconnect(nodeRoutingId: string, connectionId: string | bigint): boolean;
|
|
49
51
|
peer(nodeRoutingId: string): AdmittedServicePeer | undefined;
|
|
50
52
|
peers(): readonly AdmittedServicePeer[];
|
|
51
53
|
private peersCore;
|
|
@@ -41,10 +41,13 @@ class ServiceTopologyRegistry {
|
|
|
41
41
|
}
|
|
42
42
|
this.rebuildSelections();
|
|
43
43
|
}
|
|
44
|
-
admit(descriptor, connectionId, expected) {
|
|
44
|
+
admit(descriptor, connectionId, expected, admitLiveness) {
|
|
45
45
|
try {
|
|
46
46
|
validateDescriptor(descriptor);
|
|
47
|
-
|
|
47
|
+
if (typeof connectionId === 'string')
|
|
48
|
+
requireText(connectionId, 'connectionId');
|
|
49
|
+
else if (connectionId === 0n)
|
|
50
|
+
throw new TypeError('connectionId must be nonzero.');
|
|
48
51
|
}
|
|
49
52
|
catch (error) {
|
|
50
53
|
return 'invalidDescriptor';
|
|
@@ -86,7 +89,8 @@ class ServiceTopologyRegistry {
|
|
|
86
89
|
// that route replaces the admission of a route it replaced.
|
|
87
90
|
this.peersByRid.set(descriptor.nodeRoutingId, {
|
|
88
91
|
descriptor: cloneDescriptor(descriptor),
|
|
89
|
-
connectionId
|
|
92
|
+
connectionId,
|
|
93
|
+
liveness: admitLiveness?.() ?? current?.liveness
|
|
90
94
|
});
|
|
91
95
|
this.remember(descriptor);
|
|
92
96
|
this.rebuildSelections();
|
|
@@ -329,7 +333,8 @@ function cloneDescriptor(descriptor) {
|
|
|
329
333
|
function clonePeer(peer) {
|
|
330
334
|
return {
|
|
331
335
|
descriptor: cloneDescriptor(peer.descriptor),
|
|
332
|
-
connectionId: peer.connectionId
|
|
336
|
+
connectionId: peer.connectionId,
|
|
337
|
+
liveness: peer.liveness
|
|
333
338
|
};
|
|
334
339
|
}
|
|
335
340
|
function sameServiceNodeDescriptor(left, right) {
|
|
@@ -158,7 +158,7 @@ class LifecycleHandlerInstanceScope {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
async dispose(detachedTaskRunner) {
|
|
161
|
-
const disposeFromActiveInvocation = activeLifecycleScope.getStore() === this;
|
|
161
|
+
const disposeFromActiveInvocation = this.activeInvocations > 0 && activeLifecycleScope.getStore() === this;
|
|
162
162
|
const disposal = this.beginDisposeCore();
|
|
163
163
|
if (disposal.deferred !== undefined) {
|
|
164
164
|
startOutsideLifecycleInvocation(() => {
|
|
@@ -173,8 +173,8 @@ class ZLinkActorPacketRelay {
|
|
|
173
173
|
const state = this.options.actorManager()?.getState(relay.actorId);
|
|
174
174
|
if (frameHeader.kind === protocol_1.ZLinkStreamMessageKind.Send) {
|
|
175
175
|
const dispatch = state?.spotId === undefined
|
|
176
|
-
? this.requireSpotNodeRuntime().dispatchEntryActorPacket(relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef)
|
|
177
|
-
: this.requireSpotManager().dispatchRoutedActorPacket(state.spotId, relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef);
|
|
176
|
+
? this.requireSpotNodeRuntime().dispatchEntryActorPacket('remote', relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef)
|
|
177
|
+
: this.requireSpotManager().dispatchRoutedActorPacket('remote', state.spotId, relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef);
|
|
178
178
|
// Spec 05 §1.3: a one-way Session Actor relay completes at relay
|
|
179
179
|
// queue admission, not after the remote application turn. In
|
|
180
180
|
// particular, a handler may register a deferred Join whose relocation
|
|
@@ -207,8 +207,8 @@ class ZLinkActorPacketRelay {
|
|
|
207
207
|
frameHeader.requestSeq !== undefined &&
|
|
208
208
|
relay.returnResponse !== true) {
|
|
209
209
|
const dispatch = state?.spotId === undefined
|
|
210
|
-
? this.requireSpotNodeRuntime().dispatchEntryActorPacket(relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef)
|
|
211
|
-
: this.requireSpotManager().dispatchRoutedActorPacket(state.spotId, relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef);
|
|
210
|
+
? this.requireSpotNodeRuntime().dispatchEntryActorPacket('remote', relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef)
|
|
211
|
+
: this.requireSpotManager().dispatchRoutedActorPacket('remote', state.spotId, relay.actorId, [header, body], false, remoteBoundSessionTarget, fallbackActorRef);
|
|
212
212
|
closeFrameMessages = false;
|
|
213
213
|
const deferredPacketName = frameHeader.name;
|
|
214
214
|
const deferredRequestSeq = frameHeader.requestSeq;
|
|
@@ -249,8 +249,8 @@ class ZLinkActorPacketRelay {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
const response = state?.spotId === undefined
|
|
252
|
-
? await this.requireSpotNodeRuntime().dispatchEntryActorPacket(relay.actorId, [header, body], relay.returnResponse === true, remoteBoundSessionTarget, fallbackActorRef)
|
|
253
|
-
: await this.requireSpotManager().dispatchRoutedActorPacket(state.spotId, relay.actorId, [header, body], relay.returnResponse === true, remoteBoundSessionTarget, fallbackActorRef);
|
|
252
|
+
? await this.requireSpotNodeRuntime().dispatchEntryActorPacket('remote', relay.actorId, [header, body], relay.returnResponse === true, remoteBoundSessionTarget, fallbackActorRef)
|
|
253
|
+
: await this.requireSpotManager().dispatchRoutedActorPacket('remote', state.spotId, relay.actorId, [header, body], relay.returnResponse === true, remoteBoundSessionTarget, fallbackActorRef);
|
|
254
254
|
return {
|
|
255
255
|
ok: true,
|
|
256
256
|
response,
|
|
@@ -551,7 +551,7 @@ class ZLinkActorPacketRelay {
|
|
|
551
551
|
try {
|
|
552
552
|
this.options.detachedTaskRunner.runDetached('local actor packet relay', async () => {
|
|
553
553
|
try {
|
|
554
|
-
const response = await this.requireSpotManager().dispatchRoutedActorPacket(spotId, actor.actorId, [header, body], returnResponse);
|
|
554
|
+
const response = await this.requireSpotManager().dispatchRoutedActorPacket('local', spotId, actor.actorId, [header, body], returnResponse);
|
|
555
555
|
if (!returnResponse) {
|
|
556
556
|
return;
|
|
557
557
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ActorRef, RoutingId, ZLinkActorCreateResult } from '../../contracts';
|
|
2
|
-
import type { ZLinkAuthoritySnapshot, ZLinkLocationOwnerToken } from '../locations/internal-location-contracts';
|
|
2
|
+
import type { ZLinkAuthoritySnapshot, ZLinkLocationOwnerToken, ZLinkObjectReserveRequest } from '../locations/internal-location-contracts';
|
|
3
3
|
import type { ZLinkAuthorityStore, ZLinkObjectCreationStore } from '../locations/internal-store-contracts';
|
|
4
4
|
import type { ServiceActorCreateRecord } from '../foundation/service-stateful-wire-codec';
|
|
5
5
|
import type { ServiceUserSpotOperationResult } from '../foundation/service-stateful-runtime';
|
|
@@ -14,6 +14,7 @@ export interface ZLinkActorPlacementTarget {
|
|
|
14
14
|
readonly sourceNodeGeneration: bigint;
|
|
15
15
|
}
|
|
16
16
|
export interface ZLinkActorPlacementCoordinatorOptions {
|
|
17
|
+
readonly actorRelocationPolicy?: (meshName: string, stableType: string) => ZLinkObjectReserveRequest['actorRelocationPolicy'];
|
|
17
18
|
readonly store: ZLinkObjectCreationStore & ZLinkAuthorityStore;
|
|
18
19
|
readonly target: (meshName: string | undefined, stableType: string, signal?: AbortSignal, excludedNodeRids?: ReadonlySet<string>) => Promise<ZLinkActorPlacementTarget | undefined>;
|
|
19
20
|
readonly remoteCreate: (meshName: string, targetNodeRid: string, request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'>, timeoutMs: number) => Promise<ServiceUserSpotOperationResult>;
|
|
@@ -61,7 +61,8 @@ class ZLinkActorPlacementCoordinator {
|
|
|
61
61
|
},
|
|
62
62
|
target: reservationTarget(target),
|
|
63
63
|
creatingPayload,
|
|
64
|
-
capacity: { actors: 1, spots: 0 }
|
|
64
|
+
capacity: { actors: 1, spots: 0 },
|
|
65
|
+
actorRelocationPolicy: this.options.actorRelocationPolicy?.(target.meshName, stableType)
|
|
65
66
|
}, deadline.signal, BigInt(deadlineUnixMs));
|
|
66
67
|
const existing = existingActor(reserved, actorId, stableType);
|
|
67
68
|
if (existing !== undefined) {
|
|
@@ -15,6 +15,7 @@ import type { ZLinkRuntimeAdmissionGate } from '../admission';
|
|
|
15
15
|
import type { ZLinkRemoteActorPacketTarget } from '../actors';
|
|
16
16
|
import type { ZLinkActorJoinRelocation } from '../actors/actor-join-relocation';
|
|
17
17
|
export interface ZLinkActorRuntimeOptionsFactoryOptions {
|
|
18
|
+
readonly terminateActorActivation: (actor: ZLinkActor, terminal: () => Promise<void>) => Promise<void>;
|
|
18
19
|
readonly registration: ZLinkFrameworkRegistration;
|
|
19
20
|
/** Message flow tracer, so a failed deferred Join records its cause on the flow. */
|
|
20
21
|
readonly messageFlow?: () => import('../diagnostics/message-flow').ZLinkMessageFlowTracer | undefined;
|
|
@@ -61,7 +62,7 @@ export interface ZLinkActorRuntimeOptionsFactoryOptions {
|
|
|
61
62
|
export declare class ZLinkActorRuntimeOptionsFactory {
|
|
62
63
|
private readonly options;
|
|
63
64
|
constructor(options: ZLinkActorRuntimeOptionsFactoryOptions);
|
|
64
|
-
createActorManagerOptions(): Pick<ZLinkActorManagerOptions, 'joinCoordinator' | 'actorMeshNameProvider' | 'actorLeaveSpot' | 'messageSerializers' | 'nativeActorNode' | 'nativeActorNodeProvider' | 'nativeActorCompletionTableProvider' | 'actorCreatedNodeRidProvider' | 'actorRefResolver' | 'actorCreatedNotifier' | 'actorDestroyedCleanup' | 'publishActorAuthority' | 'locationLifecycle' | 'boundSessionFactory' | 'actorTransferRegistry' | 'shutdownSignal' | 'metrics' | 'admission'>;
|
|
65
|
+
createActorManagerOptions(): Pick<ZLinkActorManagerOptions, 'joinCoordinator' | 'actorMeshNameProvider' | 'actorLeaveSpot' | 'messageSerializers' | 'nativeActorNode' | 'nativeActorNodeProvider' | 'nativeActorCompletionTableProvider' | 'actorCreatedNodeRidProvider' | 'actorRefResolver' | 'actorCreatedNotifier' | 'actorDestroyedCleanup' | 'terminateActorActivation' | 'publishActorAuthority' | 'locationLifecycle' | 'boundSessionFactory' | 'actorTransferRegistry' | 'shutdownSignal' | 'metrics' | 'admission'>;
|
|
65
66
|
createActorClientOptions(): ConstructorParameters<typeof DefaultZLinkActorClient>[0];
|
|
66
67
|
private actorBelongsToMesh;
|
|
67
68
|
}
|
|
@@ -13,6 +13,7 @@ class ZLinkActorRuntimeOptionsFactory {
|
|
|
13
13
|
createActorManagerOptions() {
|
|
14
14
|
const actorTransferRegistry = this.options.actorTransferRegistry;
|
|
15
15
|
return {
|
|
16
|
+
terminateActorActivation: this.options.terminateActorActivation,
|
|
16
17
|
actorMeshNameProvider: this.options.actorMeshName,
|
|
17
18
|
actorLeaveSpot: (meshName, spotId, actor, signal) => {
|
|
18
19
|
const spotManager = this.options.spotManager();
|
|
@@ -150,7 +151,7 @@ class ZLinkActorRuntimeOptionsFactory {
|
|
|
150
151
|
this.options.actorHandoff.isKnownStale(actor),
|
|
151
152
|
handoffCapture: (meshName, actorId, parts, returnResponse, actor, deadlineUnixMs) => this.actorBelongsToMesh(meshName, actorId) &&
|
|
152
153
|
!this.options.actorHandoff.isProvisional(actorId)
|
|
153
|
-
? this.options.actorHandoff.capture(actorId, parts, returnResponse, undefined, actor, deadlineUnixMs)
|
|
154
|
+
? this.options.actorHandoff.capture('local', actorId, parts, returnResponse, undefined, actor, deadlineUnixMs)
|
|
154
155
|
: undefined,
|
|
155
156
|
sendErrorReporter: this.options.reportPostCommitError
|
|
156
157
|
};
|