@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ServiceInstanceColdActivationTarget } from '../foundation/service-stateful-wire-codec';
|
|
1
2
|
import { ZLinkFrameworkException, ZLinkSpotKind, type RoutingId } from '../../contracts';
|
|
2
3
|
import {
|
|
3
4
|
ZLinkRuntimeDispatchErrorAction as ZLinkDispatchErrorAction,
|
|
@@ -44,7 +45,11 @@ import type {
|
|
|
44
45
|
ZLinkSpotAddressTransport,
|
|
45
46
|
ZLinkSpotRoutedTransport
|
|
46
47
|
} from '../spots/spot-outbound';
|
|
47
|
-
import type {
|
|
48
|
+
import type {
|
|
49
|
+
ZLinkSpotRouteResolver,
|
|
50
|
+
ZLinkSpotRouteTarget,
|
|
51
|
+
ZLinkInstanceReactivationRoute
|
|
52
|
+
} from '../spots/spot-routing-internal';
|
|
48
53
|
|
|
49
54
|
export interface ZLinkHostSpotAddressTransportOptions {
|
|
50
55
|
readonly resolver: () => ZLinkSpotRouteResolver | undefined;
|
|
@@ -65,13 +70,7 @@ export function hasObjectClientCapability(role: 'none' | 'client' | 'server' | u
|
|
|
65
70
|
type MissingTarget = {
|
|
66
71
|
readonly meshName: string;
|
|
67
72
|
readonly node: ZLinkBackendMeshNode;
|
|
68
|
-
readonly target:
|
|
69
|
-
readonly targetNodeRid: string;
|
|
70
|
-
readonly targetNodeGeneration: bigint;
|
|
71
|
-
readonly targetSpotId: string;
|
|
72
|
-
readonly stableType: string;
|
|
73
|
-
readonly descriptorVersion: string;
|
|
74
|
-
};
|
|
73
|
+
readonly target: ServiceInstanceColdActivationTarget;
|
|
75
74
|
};
|
|
76
75
|
|
|
77
76
|
type MissingTargetSelection =
|
|
@@ -106,7 +105,10 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
106
105
|
const activationDeadlineUnixMs = BigInt(
|
|
107
106
|
Math.round(Date.now() + this.options.defaultRequestTimeoutMs)
|
|
108
107
|
);
|
|
109
|
-
const
|
|
108
|
+
const resolution = await this.resolveExisting(spotId, undefined, call);
|
|
109
|
+
const existing = resolution !== undefined && !('kind' in resolution) ? resolution : undefined;
|
|
110
|
+
if (resolution !== undefined && 'kind' in resolution)
|
|
111
|
+
call = this.reactivationCall(resolution, call);
|
|
110
112
|
if (existing !== undefined) {
|
|
111
113
|
this.validateExisting(existing, call);
|
|
112
114
|
try {
|
|
@@ -166,7 +168,7 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
166
168
|
if (!call.instanceSpot) {
|
|
167
169
|
return { status: ZLinkSubmitStatus.TargetNotFound };
|
|
168
170
|
}
|
|
169
|
-
const selected = this.selectMissingTarget(spotId, call);
|
|
171
|
+
const selected = this.selectMissingTarget(spotId, call, resolution);
|
|
170
172
|
if (selected.kind === 'unsupported') {
|
|
171
173
|
this.traceInstanceAddress(
|
|
172
174
|
ZLinkMessageFlowOutcome.Dropped,
|
|
@@ -252,10 +254,13 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
252
254
|
const timeoutMs = call.timeoutMs ?? this.options.defaultRequestTimeoutMs;
|
|
253
255
|
const deadline = createSpotAddressDeadline(timeoutMs, call.signal);
|
|
254
256
|
try {
|
|
255
|
-
const
|
|
257
|
+
const resolution = await this.resolveExisting(spotId, deadline.signal, call);
|
|
258
|
+
const existing = resolution !== undefined && !('kind' in resolution) ? resolution : undefined;
|
|
259
|
+
if (resolution !== undefined && 'kind' in resolution)
|
|
260
|
+
call = this.reactivationCall(resolution, call);
|
|
256
261
|
deadline.requireRemaining();
|
|
257
262
|
if (existing === undefined) {
|
|
258
|
-
return await this.requestToMissingInstance(spotId, request, call, deadline);
|
|
263
|
+
return await this.requestToMissingInstance(spotId, request, call, deadline, resolution);
|
|
259
264
|
}
|
|
260
265
|
this.validateExisting(existing, call);
|
|
261
266
|
try {
|
|
@@ -351,7 +356,8 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
351
356
|
spotId: RoutingId,
|
|
352
357
|
request: unknown,
|
|
353
358
|
call: ZLinkSpotAddressCallOptions,
|
|
354
|
-
deadline: ZLinkSpotAddressDeadline
|
|
359
|
+
deadline: ZLinkSpotAddressDeadline,
|
|
360
|
+
current?: ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute
|
|
355
361
|
): Promise<TReply> {
|
|
356
362
|
if (!call.instanceSpot) {
|
|
357
363
|
throw createInternalFrameworkException(
|
|
@@ -359,7 +365,7 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
359
365
|
`Spot '${String(spotId)}' has no Ready authority.`
|
|
360
366
|
);
|
|
361
367
|
}
|
|
362
|
-
const selected = this.selectMissingTarget(spotId, call);
|
|
368
|
+
const selected = this.selectMissingTarget(spotId, call, current);
|
|
363
369
|
if (selected.kind === 'capacity') {
|
|
364
370
|
throw missingInstancePlacementCapacity(spotId, call.instanceSpotType);
|
|
365
371
|
}
|
|
@@ -507,14 +513,20 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
507
513
|
|
|
508
514
|
private async resolveExisting(
|
|
509
515
|
spotId: RoutingId,
|
|
510
|
-
signal?: AbortSignal
|
|
511
|
-
|
|
516
|
+
signal?: AbortSignal,
|
|
517
|
+
call?: ZLinkSpotAddressCallOptions
|
|
518
|
+
): Promise<ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute | undefined> {
|
|
512
519
|
const resolver = this.options.resolver();
|
|
513
520
|
if (resolver === undefined) {
|
|
514
521
|
throw new Error('Global Spot address resolution requires a Location Store.');
|
|
515
522
|
}
|
|
516
523
|
try {
|
|
517
|
-
return await awaitWithAbort(
|
|
524
|
+
return await awaitWithAbort(
|
|
525
|
+
call?.instanceSpot === true
|
|
526
|
+
? resolver.resolve(spotId, signal, true)
|
|
527
|
+
: resolver.resolve(spotId, signal),
|
|
528
|
+
signal
|
|
529
|
+
);
|
|
518
530
|
} catch (error) {
|
|
519
531
|
if (
|
|
520
532
|
error instanceof ZLinkFrameworkException &&
|
|
@@ -526,9 +538,18 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
526
538
|
}
|
|
527
539
|
}
|
|
528
540
|
|
|
541
|
+
private reactivationCall(
|
|
542
|
+
route: ZLinkInstanceReactivationRoute,
|
|
543
|
+
call: ZLinkSpotAddressCallOptions
|
|
544
|
+
): ZLinkSpotAddressCallOptions {
|
|
545
|
+
this.validateExisting(route, call);
|
|
546
|
+
return { ...call, initialMeshName: route.meshName, instanceSpotType: route.stableType };
|
|
547
|
+
}
|
|
548
|
+
|
|
529
549
|
private selectMissingTarget(
|
|
530
550
|
spotId: RoutingId,
|
|
531
|
-
call: ZLinkSpotAddressCallOptions
|
|
551
|
+
call: ZLinkSpotAddressCallOptions,
|
|
552
|
+
current?: ZLinkSpotRouteTarget | ZLinkInstanceReactivationRoute
|
|
532
553
|
): MissingTargetSelection {
|
|
533
554
|
const configuredMeshes = this.options.meshNames();
|
|
534
555
|
if (
|
|
@@ -574,14 +595,15 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
574
595
|
const stableType =
|
|
575
596
|
call.instanceSpotType ?? (distinctTypes.length === 1 ? distinctTypes[0] : undefined);
|
|
576
597
|
if (stableType === undefined) {
|
|
577
|
-
if (distinctTypes.length === 0)
|
|
598
|
+
if (distinctTypes.length === 0)
|
|
599
|
+
return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
578
600
|
throw createInternalFrameworkException(
|
|
579
601
|
ZLinkFrameworkInternalErrorKind.InvalidOperation,
|
|
580
602
|
'Instance Spot type is required when multiple types are registered.'
|
|
581
603
|
);
|
|
582
604
|
}
|
|
583
605
|
if (canInspectPlacementTypes && !distinctTypes.includes(stableType)) {
|
|
584
|
-
return { kind: 'unsupported' };
|
|
606
|
+
return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
585
607
|
}
|
|
586
608
|
let unavailable = false;
|
|
587
609
|
let capacity = false;
|
|
@@ -600,6 +622,7 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
600
622
|
node,
|
|
601
623
|
target: {
|
|
602
624
|
...placement.target,
|
|
625
|
+
targetMeshName: meshName,
|
|
603
626
|
targetSpotId: String(spotId),
|
|
604
627
|
stableType
|
|
605
628
|
}
|
|
@@ -611,12 +634,12 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
611
634
|
}
|
|
612
635
|
if (unavailable) return { kind: 'unavailable' };
|
|
613
636
|
if (capacity) return { kind: 'capacity' };
|
|
614
|
-
if (unsupported) return { kind: 'unsupported' };
|
|
637
|
+
if (unsupported) return { kind: current === undefined ? 'unsupported' : 'unavailable' };
|
|
615
638
|
return { kind: 'unavailable' };
|
|
616
639
|
}
|
|
617
640
|
|
|
618
641
|
private validateExisting(
|
|
619
|
-
target:
|
|
642
|
+
target: Pick<ZLinkSpotRouteTarget, 'spotId' | 'spotKind' | 'stableType'>,
|
|
620
643
|
call: ZLinkSpotAddressCallOptions
|
|
621
644
|
): void {
|
|
622
645
|
if (!call.instanceSpot) return;
|
|
@@ -102,6 +102,7 @@ export class ZLinkSpotRuntimeOptionsFactory {
|
|
|
102
102
|
Promise.resolve()
|
|
103
103
|
},
|
|
104
104
|
dispatchEntryActorPacket: (
|
|
105
|
+
origin,
|
|
105
106
|
actorId,
|
|
106
107
|
parts,
|
|
107
108
|
returnResponse,
|
|
@@ -117,6 +118,7 @@ export class ZLinkSpotRuntimeOptionsFactory {
|
|
|
117
118
|
);
|
|
118
119
|
}
|
|
119
120
|
return runtime.dispatchEntryActorPacket(
|
|
121
|
+
origin,
|
|
120
122
|
actorId,
|
|
121
123
|
parts,
|
|
122
124
|
returnResponse,
|
|
@@ -38,6 +38,10 @@ const DEFAULT_USER_SPOT_CLEANUP_TIMEOUT_MS = 1_000;
|
|
|
38
38
|
const DEFAULT_USER_SPOT_POLL_INTERVAL_MS = 10;
|
|
39
39
|
|
|
40
40
|
export interface ZLinkUserSpotCreationCoordinatorOptions {
|
|
41
|
+
readonly relocationPolicy?: (
|
|
42
|
+
meshName: string,
|
|
43
|
+
stableType: string
|
|
44
|
+
) => import('../locations/internal-location-contracts').ZLinkObjectReserveRequest['actorRelocationPolicy'];
|
|
41
45
|
readonly store: ZLinkObjectCreationStore & ZLinkAuthorityStore;
|
|
42
46
|
readonly target: (
|
|
43
47
|
request: Pick<ZLinkUserSpotCreationRequest, 'meshName' | 'stableType'>,
|
|
@@ -169,6 +173,10 @@ export class ZLinkUserSpotCreationCoordinator {
|
|
|
169
173
|
reserved = await this.options.store.reserve(
|
|
170
174
|
{
|
|
171
175
|
key: { kind: 'user_spot', globalId: String(request.spotId) },
|
|
176
|
+
actorRelocationPolicy: this.options.relocationPolicy?.(
|
|
177
|
+
target.meshName,
|
|
178
|
+
request.stableType
|
|
179
|
+
),
|
|
172
180
|
intent: {
|
|
173
181
|
stableType: request.stableType,
|
|
174
182
|
requestContentReference: contentReference,
|
|
@@ -39,7 +39,10 @@ import type {
|
|
|
39
39
|
ZLinkObjectCreationCompleteResult,
|
|
40
40
|
ZLinkObjectReserveResult
|
|
41
41
|
} from '../../contracts/Locations/Authority';
|
|
42
|
-
import type {
|
|
42
|
+
import type {
|
|
43
|
+
ZLinkObjectReserveRequest,
|
|
44
|
+
ZLinkEndedOwnerReleaseIntent
|
|
45
|
+
} from './internal-location-contracts';
|
|
43
46
|
|
|
44
47
|
/**
|
|
45
48
|
* Framework-private domain repository. Provider implementations never
|
|
@@ -143,7 +146,8 @@ export interface ZLinkDomainLocationStore {
|
|
|
143
146
|
releaseEndedReservation?(
|
|
144
147
|
key: ZLinkAuthorityKey,
|
|
145
148
|
expectedStoreVersion: string,
|
|
146
|
-
signal?: AbortSignal
|
|
149
|
+
signal?: AbortSignal,
|
|
150
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
147
151
|
): Promise<boolean>;
|
|
148
152
|
abort(
|
|
149
153
|
request: ZLinkObjectAbortRequest,
|
|
@@ -32,6 +32,7 @@ import type {
|
|
|
32
32
|
ZLinkObjectCommitResult,
|
|
33
33
|
ZLinkObjectCreationCompleteRequest,
|
|
34
34
|
ZLinkObjectCreationCompleteResult,
|
|
35
|
+
ZLinkEndedOwnerReleaseIntent,
|
|
35
36
|
ZLinkObjectReserveRequest,
|
|
36
37
|
ZLinkObjectReserveResult,
|
|
37
38
|
ZLinkCreationOperationIdentity,
|
|
@@ -42,7 +43,13 @@ import type {
|
|
|
42
43
|
} from './internal-location-contracts';
|
|
43
44
|
import { encodeAuthorityKey } from './authority-key-codec';
|
|
44
45
|
import { creationTerminalPreimage } from './opaque-record-key';
|
|
45
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
ServiceRelocationAuthorityPayloadCodec,
|
|
48
|
+
serviceRelocationAuthorityApplicationPayload
|
|
49
|
+
} from '../foundation/service-relocation-runtime';
|
|
50
|
+
import { decodeServiceReadySpotAuthority } from '../foundation/service-authority-payload-codec';
|
|
51
|
+
import { decodeActorAuthorityPayload } from '../actors/actor-authority-payload-codec';
|
|
52
|
+
import { ZLinkSpotKind } from '../../contracts';
|
|
46
53
|
|
|
47
54
|
const MAX_GENERATION = 0x7fff_ffff_ffff_ffffn;
|
|
48
55
|
|
|
@@ -64,6 +71,7 @@ export interface ZLinkInMemoryAuthorityValidation {
|
|
|
64
71
|
currentActive: ZLinkCapacityVector
|
|
65
72
|
): boolean;
|
|
66
73
|
identityClaimed?(authorityKey: string): boolean;
|
|
74
|
+
hasSpotMembers?(spotId: string, objectGeneration: bigint): boolean;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
interface AuthorityRow {
|
|
@@ -203,6 +211,26 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
203
211
|
if (!this.isOwnerLive(row.snapshot)) {
|
|
204
212
|
return { kind: 'conflict', current: this.read(keyValue) };
|
|
205
213
|
}
|
|
214
|
+
const actor =
|
|
215
|
+
row.snapshot.allocation.objectKind === 'actor'
|
|
216
|
+
? decodeActorAuthorityPayload(
|
|
217
|
+
serviceRelocationAuthorityApplicationPayload(mutation.payload)
|
|
218
|
+
)
|
|
219
|
+
: undefined;
|
|
220
|
+
const previousActor =
|
|
221
|
+
actor === undefined
|
|
222
|
+
? undefined
|
|
223
|
+
: decodeActorAuthorityPayload(
|
|
224
|
+
serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
|
|
225
|
+
);
|
|
226
|
+
if (
|
|
227
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
228
|
+
(previousActor?.currentSpotKind !== ZLinkSpotKind.User ||
|
|
229
|
+
previousActor.currentSpotId !== actor.currentSpotId ||
|
|
230
|
+
previousActor.currentSpotGeneration !== actor.currentSpotGeneration) &&
|
|
231
|
+
!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration)
|
|
232
|
+
)
|
|
233
|
+
return { kind: 'conflict', current: this.read(keyValue) };
|
|
206
234
|
if (
|
|
207
235
|
mutation.generationTransition === 'reincarnate' &&
|
|
208
236
|
(this.objectGeneration >= MAX_GENERATION || this.ownerGeneration >= MAX_GENERATION)
|
|
@@ -283,27 +311,41 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
283
311
|
async releaseEndedReservation(
|
|
284
312
|
key: ZLinkAuthorityKey,
|
|
285
313
|
expectedStoreVersion: string,
|
|
286
|
-
signal?: AbortSignal
|
|
314
|
+
signal?: AbortSignal,
|
|
315
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
287
316
|
): Promise<boolean> {
|
|
288
317
|
signal?.throwIfAborted();
|
|
289
|
-
return this.tryReleaseEndedReservation(key, expectedStoreVersion);
|
|
318
|
+
return this.tryReleaseEndedReservation(key, expectedStoreVersion, request);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
acceptsUserSpotMembership(spotId: string, objectGeneration: bigint): boolean {
|
|
322
|
+
const row = this.rows.get(encodeAuthorityKey('user_spot', spotId).value);
|
|
323
|
+
return (
|
|
324
|
+
row !== undefined &&
|
|
325
|
+
row.snapshot.allocation.objectKind === 'user_spot' &&
|
|
326
|
+
row.snapshot.allocation.state === 'active' &&
|
|
327
|
+
row.snapshot.objectGeneration === objectGeneration &&
|
|
328
|
+
decodeServiceReadySpotAuthority(row.snapshot.payload)?.kind === 'user_spot' &&
|
|
329
|
+
this.isOwnerLive(row.snapshot)
|
|
330
|
+
);
|
|
290
331
|
}
|
|
291
332
|
|
|
292
333
|
private tryReleaseEndedReservation(
|
|
293
334
|
key: ZLinkAuthorityKey,
|
|
294
335
|
expectedStoreVersion: string,
|
|
295
|
-
request?:
|
|
336
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
296
337
|
): boolean {
|
|
297
338
|
const current = this.rows.get(key.value);
|
|
298
339
|
if (
|
|
299
340
|
current === undefined ||
|
|
300
341
|
current.snapshot.storeVersion.value !== expectedStoreVersion ||
|
|
301
342
|
(current.snapshot.allocation.state === 'active'
|
|
302
|
-
? request
|
|
343
|
+
? request === undefined
|
|
303
344
|
: current.creation === undefined)
|
|
304
345
|
)
|
|
305
346
|
return false;
|
|
306
347
|
if (current.snapshot.allocation.state === 'active') {
|
|
348
|
+
let unavailable = false;
|
|
307
349
|
for (const aggregate of this.aggregates.values()) {
|
|
308
350
|
if (
|
|
309
351
|
aggregate.state === 'prepared' &&
|
|
@@ -311,9 +353,9 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
311
353
|
(participant) => participant.authorityKey.value === key.value
|
|
312
354
|
)
|
|
313
355
|
)
|
|
314
|
-
|
|
356
|
+
unavailable = true;
|
|
315
357
|
}
|
|
316
|
-
|
|
358
|
+
unavailable ||= relocationAuthorityCodec.read(current.snapshot.payload) !== undefined;
|
|
317
359
|
if (
|
|
318
360
|
this.validation.isOwnerLive({
|
|
319
361
|
ownerId: current.snapshot.ownerId,
|
|
@@ -321,10 +363,37 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
321
363
|
})
|
|
322
364
|
)
|
|
323
365
|
return false;
|
|
324
|
-
|
|
366
|
+
const spot =
|
|
367
|
+
current.snapshot.allocation.objectKind === 'actor'
|
|
368
|
+
? undefined
|
|
369
|
+
: decodeServiceReadySpotAuthority(current.snapshot.payload);
|
|
370
|
+
if (current.snapshot.allocation.objectKind !== 'actor') {
|
|
371
|
+
unavailable ||=
|
|
372
|
+
spot === undefined ||
|
|
373
|
+
spot.kind !== request?.key.kind ||
|
|
374
|
+
spot.stableType !== request.intent.stableType ||
|
|
375
|
+
spot.spotId !== request.key.globalId ||
|
|
376
|
+
spot.activationRecovery !== undefined;
|
|
377
|
+
if (spot?.kind === 'user_spot') {
|
|
378
|
+
unavailable ||=
|
|
379
|
+
this.validation.hasSpotMembers?.(spot.spotId, current.snapshot.objectGeneration) ===
|
|
380
|
+
true;
|
|
381
|
+
for (const row of this.rows.values()) {
|
|
382
|
+
if (row.snapshot.allocation.objectKind !== 'actor') continue;
|
|
383
|
+
const actor = decodeActorAuthorityPayload(
|
|
384
|
+
serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
|
|
385
|
+
);
|
|
386
|
+
unavailable ||=
|
|
387
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
388
|
+
actor.currentSpotId === spot.spotId &&
|
|
389
|
+
actor.currentSpotGeneration === current.snapshot.objectGeneration;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (unavailable || request?.actorRelocationPolicy !== 'disabled')
|
|
325
394
|
throw new ZLinkFrameworkException(
|
|
326
395
|
ZLinkFrameworkErrorKind.Unavailable,
|
|
327
|
-
'
|
|
396
|
+
'Object owner lease is unavailable.'
|
|
328
397
|
);
|
|
329
398
|
} else if (
|
|
330
399
|
this.validation.isTargetLive(
|
|
@@ -532,6 +601,17 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
532
601
|
if (!this.creationTerminalAvailable(terminalRecord)) {
|
|
533
602
|
return { kind: 'stale' };
|
|
534
603
|
}
|
|
604
|
+
const actor =
|
|
605
|
+
request.completion.kind === 'created'
|
|
606
|
+
? decodeActorAuthorityPayload(
|
|
607
|
+
serviceRelocationAuthorityApplicationPayload(request.completion.readyPayload)
|
|
608
|
+
)
|
|
609
|
+
: undefined;
|
|
610
|
+
if (
|
|
611
|
+
actor?.currentSpotKind === ZLinkSpotKind.User &&
|
|
612
|
+
!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration)
|
|
613
|
+
)
|
|
614
|
+
return { kind: 'stale' };
|
|
535
615
|
const nextVersion = this.tryNextStoreVersion();
|
|
536
616
|
if (nextVersion === undefined) return { kind: 'generationExhausted' };
|
|
537
617
|
const pending = row.snapshot.allocation;
|
|
@@ -698,6 +778,30 @@ export class ZLinkInMemoryAuthorityStore {
|
|
|
698
778
|
) {
|
|
699
779
|
return { kind: 'stale' };
|
|
700
780
|
}
|
|
781
|
+
const actor =
|
|
782
|
+
row.snapshot.allocation.objectKind === 'actor'
|
|
783
|
+
? decodeActorAuthorityPayload(
|
|
784
|
+
serviceRelocationAuthorityApplicationPayload(participant.authorityPayload)
|
|
785
|
+
)
|
|
786
|
+
: undefined;
|
|
787
|
+
if (actor?.currentSpotKind === ZLinkSpotKind.User) {
|
|
788
|
+
const participantSpot = aggregate.request.participants.find(
|
|
789
|
+
(candidate) =>
|
|
790
|
+
candidate.authorityKey.value ===
|
|
791
|
+
encodeAuthorityKey('user_spot', actor.currentSpotId).value
|
|
792
|
+
);
|
|
793
|
+
if (participantSpot === undefined) {
|
|
794
|
+
if (!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration))
|
|
795
|
+
return { kind: 'stale' };
|
|
796
|
+
} else {
|
|
797
|
+
const spot = this.rows.get(participantSpot.authorityKey.value);
|
|
798
|
+
if (
|
|
799
|
+
spot?.snapshot.allocation.objectKind !== 'user_spot' ||
|
|
800
|
+
spot.snapshot.objectGeneration !== actor.currentSpotGeneration
|
|
801
|
+
)
|
|
802
|
+
return { kind: 'stale' };
|
|
803
|
+
}
|
|
804
|
+
}
|
|
701
805
|
if (participant.ownerTransition === 'newOwner') {
|
|
702
806
|
if (
|
|
703
807
|
!this.validation.isTargetLive(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RoutingId } from '../../contracts/Common';
|
|
2
|
+
import { ZLinkSpotKind } from '../../contracts';
|
|
2
3
|
import { ZLINK_MAX_IDENTITY_TEXT_BYTES } from '../../contracts/Common/CoreTypes';
|
|
3
4
|
import {
|
|
4
5
|
isValidPublicWeight,
|
|
@@ -58,6 +59,7 @@ import {
|
|
|
58
59
|
type ZLinkObjectCommitResult,
|
|
59
60
|
type ZLinkObjectCreationCompleteRequest,
|
|
60
61
|
type ZLinkObjectCreationCompleteResult,
|
|
62
|
+
type ZLinkEndedOwnerReleaseIntent,
|
|
61
63
|
type ZLinkObjectReserveRequest,
|
|
62
64
|
type ZLinkObjectReserveResult,
|
|
63
65
|
type ZLinkOwnerLeaseClaimResult,
|
|
@@ -143,7 +145,18 @@ export class ZLinkInMemoryLocationStore
|
|
|
143
145
|
typeCapacity.limit)))
|
|
144
146
|
);
|
|
145
147
|
},
|
|
146
|
-
identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey)
|
|
148
|
+
identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey),
|
|
149
|
+
hasSpotMembers: (spotId, objectGeneration) => {
|
|
150
|
+
for (const actor of this.actors.rows.values()) {
|
|
151
|
+
if (
|
|
152
|
+
actor.spotKind === ZLinkSpotKind.User &&
|
|
153
|
+
String(actor.spotId) === spotId &&
|
|
154
|
+
actor.spotGeneration === objectGeneration
|
|
155
|
+
)
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
147
160
|
},
|
|
148
161
|
now
|
|
149
162
|
);
|
|
@@ -205,9 +218,10 @@ export class ZLinkInMemoryLocationStore
|
|
|
205
218
|
async releaseEndedReservation(
|
|
206
219
|
key: ZLinkAuthorityKey,
|
|
207
220
|
expectedStoreVersion: string,
|
|
208
|
-
signal?: AbortSignal
|
|
221
|
+
signal?: AbortSignal,
|
|
222
|
+
request?: ZLinkEndedOwnerReleaseIntent
|
|
209
223
|
): Promise<boolean> {
|
|
210
|
-
return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal);
|
|
224
|
+
return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal, request);
|
|
211
225
|
}
|
|
212
226
|
|
|
213
227
|
async abort(
|
|
@@ -705,6 +719,14 @@ export class ZLinkInMemoryLocationStore
|
|
|
705
719
|
});
|
|
706
720
|
const updatedAt = this.now();
|
|
707
721
|
const current = this.actors.rows.get(key);
|
|
722
|
+
if (
|
|
723
|
+
actor.spotKind === ZLinkSpotKind.User &&
|
|
724
|
+
(current?.spotKind !== ZLinkSpotKind.User ||
|
|
725
|
+
String(current.spotId) !== String(actor.spotId) ||
|
|
726
|
+
current.spotGeneration !== actor.spotGeneration) &&
|
|
727
|
+
!this.authority.acceptsUserSpotMembership(String(actor.spotId), actor.spotGeneration)
|
|
728
|
+
)
|
|
729
|
+
return rejectedConflict();
|
|
708
730
|
if (
|
|
709
731
|
intent === ZLinkLocationWriteIntent.NewClaim &&
|
|
710
732
|
current !== undefined &&
|
|
@@ -5,6 +5,10 @@ import type { ZLinkRelocationConfiguration } from '../../contracts/Configuration
|
|
|
5
5
|
export interface ZLinkObjectReserveRequest extends ReserveRequest {
|
|
6
6
|
readonly actorRelocationPolicy?: ZLinkRelocationConfiguration<unknown>['kind'];
|
|
7
7
|
}
|
|
8
|
+
export type ZLinkEndedOwnerReleaseIntent = Pick<
|
|
9
|
+
ZLinkObjectReserveRequest,
|
|
10
|
+
'key' | 'actorRelocationPolicy'
|
|
11
|
+
> & { readonly intent: Pick<ZLinkObjectReserveRequest['intent'], 'stableType'> };
|
|
8
12
|
export type * from '../../contracts/Locations/Authority';
|
|
9
13
|
export type {
|
|
10
14
|
ZLinkActorLocation,
|