@zlink-systems/framework 0.29.1 → 0.30.1
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/LICENSE +150 -68
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
- package/dist/contracts/Channels/Calls.d.ts +2 -1
- package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
- 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/contracts/Handlers/Attributes.d.ts +5 -13
- package/dist/contracts/Handlers/Attributes.js +7 -11
- package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
- package/dist/contracts/Handlers/JsonContract.js +4 -153
- package/dist/contracts/Spots/Contracts.d.ts +2 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/nest-integration.d.ts +1 -1
- package/dist/nest-integration.js +2 -1
- package/dist/runtime/actors/actor-client.d.ts +1 -1
- package/dist/runtime/actors/actor-client.js +14 -12
- package/dist/runtime/actors/actor-handoff.d.ts +3 -2
- package/dist/runtime/actors/actor-handoff.js +15 -7
- package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
- package/dist/runtime/actors/actor-local-native-join.js +9 -12
- package/dist/runtime/actors/actor-remote-wire.js +15 -0
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
- package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
- package/dist/runtime/actors/index.d.ts +2 -1
- package/dist/runtime/actors/index.js +18 -6
- package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
- package/dist/runtime/admission.d.ts +1 -1
- package/dist/runtime/admission.js +15 -5
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +9 -9
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +45 -23
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +5 -2
- package/dist/runtime/application-jobs/application-job-queue-scope.js +41 -21
- package/dist/runtime/application-jobs/contracts.d.ts +15 -2
- package/dist/runtime/backend/contracts/index.d.ts +27 -27
- package/dist/runtime/backend/mesh-completion-table.d.ts +15 -5
- package/dist/runtime/backend/mesh-completion-table.js +160 -50
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
- package/dist/runtime/backend/mesh-dispatch-pump.js +53 -36
- 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 +33 -31
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
- 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 +50 -25
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +22 -16
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +133 -149
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +15 -10
- package/dist/runtime/backend/raw-binding-port.d.ts +10 -3
- package/dist/runtime/backend/runtime-message.d.ts +1 -0
- package/dist/runtime/backend/runtime-message.js +5 -0
- package/dist/runtime/backend/runtime-values.d.ts +1 -0
- package/dist/runtime/backend/runtime-values.js +2 -1
- package/dist/runtime/channels/channel-clients.d.ts +1 -0
- package/dist/runtime/channels/channel-clients.js +58 -21
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
- package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
- package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
- package/dist/runtime/channels/channel-dispatch-services.js +45 -0
- package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
- package/dist/runtime/channels/channel-dispatchers.js +27 -26
- package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
- package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
- package/dist/runtime/channels/channel-envelope.d.ts +1 -0
- package/dist/runtime/channels/channel-envelope.js +83 -8
- package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
- package/dist/runtime/channels/channel-outbound-operations.js +8 -8
- 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-runtime-manager.d.ts +6 -6
- package/dist/runtime/channels/channel-runtime-manager.js +12 -12
- package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
- package/dist/runtime/channels/channel-socket-registry.js +59 -82
- package/dist/runtime/channels/channel-transports.d.ts +18 -15
- package/dist/runtime/channels/channel-transports.js +48 -31
- package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.js +2 -1
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
- package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
- package/dist/runtime/channels/source-spot-router.d.ts +2 -2
- package/dist/runtime/channels/source-spot-router.js +4 -4
- package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-node-route-transport.js +4 -4
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
- package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow.js +3 -3
- package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
- package/dist/runtime/execution/serial-execution-queue.js +1 -0
- package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
- package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
- package/dist/runtime/foundation/durable-service-request.js +98 -0
- package/dist/runtime/foundation/operation-identity.d.ts +1 -0
- package/dist/runtime/foundation/operation-identity.js +5 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +37 -6
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +473 -220
- 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-relocation-object-owner.d.ts +1 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
- package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
- package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -9
- package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -7
- package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
- package/dist/runtime/foundation/service-topology-registry.d.ts +16 -4
- package/dist/runtime/foundation/service-topology-registry.js +69 -30
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
- package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
- package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
- package/dist/runtime/handlers/handler-instance-scope.js +54 -11
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
- package/dist/runtime/host/application-job-queue.d.ts +28 -9
- package/dist/runtime/host/application-job-queue.js +214 -50
- package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
- package/dist/runtime/host/entry-actor-runtime.js +4 -1
- package/dist/runtime/host/index.d.ts +7 -1
- package/dist/runtime/host/index.js +154 -126
- 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/remote-bound-session-relay.js +2 -18
- package/dist/runtime/host/route-mesh-runtime.js +1 -1
- package/dist/runtime/host/service-relocation-control.d.ts +1 -0
- package/dist/runtime/host/service-relocation-control.js +10 -4
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +215 -243
- package/dist/runtime/host/spot-address-transport.d.ts +1 -0
- package/dist/runtime/host/spot-address-transport.js +28 -14
- package/dist/runtime/host/spot-runtime-options-factory.js +3 -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/actor-location-claims.d.ts +2 -2
- package/dist/runtime/locations/actor-location-claims.js +34 -19
- 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/lifecycle.d.ts +1 -2
- package/dist/runtime/locations/lifecycle.js +2 -5
- 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/locations/runtime.d.ts +1 -1
- package/dist/runtime/locations/runtime.js +24 -23
- package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
- package/dist/runtime/messaging/framework-json-v1.js +38 -294
- package/dist/runtime/messaging/packet-name.d.ts +1 -1
- package/dist/runtime/messaging/packet-name.js +8 -24
- package/dist/runtime/messaging/request-result.d.ts +2 -0
- package/dist/runtime/messaging/request-result.js +54 -0
- package/dist/runtime/messaging/submission-result.d.ts +2 -1
- package/dist/runtime/messaging/submission-result.js +7 -4
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +9 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
- package/dist/runtime/spots/index.d.ts +7 -3
- package/dist/runtime/spots/index.js +23 -16
- package/dist/runtime/spots/spot-activation.d.ts +3 -1
- package/dist/runtime/spots/spot-activation.js +21 -12
- 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 +9 -3
- package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
- package/dist/runtime/spots/spot-handler-registry.js +18 -8
- package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
- 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-outbound.d.ts +3 -0
- package/dist/runtime/spots/spot-outbound.js +24 -15
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
- package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
- package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -1
- package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
- package/dist/runtime/spots/spot-timer.js +1 -0
- package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
- package/dist/runtime/streams/stream-session-runtime.js +14 -28
- package/package.json +3 -3
- package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
- package/src/contracts/Channels/Calls.ts +2 -1
- package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
- 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/contracts/Handlers/Attributes.ts +14 -21
- package/src/contracts/Handlers/JsonContract.ts +8 -216
- package/src/contracts/Spots/Contracts.ts +2 -1
- package/src/internal.ts +1 -0
- package/src/nest-integration.ts +1 -0
- package/src/runtime/actors/actor-client.ts +40 -16
- package/src/runtime/actors/actor-handoff.ts +22 -8
- package/src/runtime/actors/actor-join-relocation.ts +1 -0
- package/src/runtime/actors/actor-local-native-join.ts +17 -26
- package/src/runtime/actors/actor-remote-wire.ts +17 -0
- package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
- package/src/runtime/actors/actor-routed-json-request.ts +10 -2
- package/src/runtime/actors/index.ts +19 -5
- package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
- package/src/runtime/admission.ts +18 -5
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +53 -27
- package/src/runtime/application-jobs/application-job-queue-scope.ts +56 -22
- package/src/runtime/application-jobs/contracts.ts +28 -2
- package/src/runtime/backend/contracts/index.ts +63 -32
- package/src/runtime/backend/mesh-completion-table.ts +175 -59
- package/src/runtime/backend/mesh-dispatch-pump.ts +59 -32
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
- package/src/runtime/backend/node/node-backend-adapter-support.ts +42 -31
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
- package/src/runtime/backend/node/node-raw-binding-port.ts +73 -37
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +209 -176
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +32 -13
- package/src/runtime/backend/raw-binding-port.ts +18 -3
- package/src/runtime/backend/runtime-message.ts +6 -0
- package/src/runtime/backend/runtime-values.ts +1 -0
- package/src/runtime/channels/channel-clients.ts +90 -41
- package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
- package/src/runtime/channels/channel-dispatch-services.ts +69 -1
- package/src/runtime/channels/channel-dispatchers.ts +29 -27
- package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
- package/src/runtime/channels/channel-envelope.ts +133 -8
- package/src/runtime/channels/channel-outbound-operations.ts +22 -8
- 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-runtime-manager.ts +29 -12
- package/src/runtime/channels/channel-socket-registry.ts +84 -130
- package/src/runtime/channels/channel-transports.ts +128 -60
- package/src/runtime/channels/local-spot-route-transport.ts +3 -1
- package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
- package/src/runtime/channels/source-spot-router.ts +8 -4
- package/src/runtime/channels/spot-node-route-transport.ts +8 -4
- package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
- package/src/runtime/diagnostics/message-flow.ts +1 -1
- package/src/runtime/execution/serial-execution-queue.ts +2 -0
- package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
- package/src/runtime/foundation/durable-service-request.ts +137 -0
- package/src/runtime/foundation/operation-identity.ts +5 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +642 -253
- package/src/runtime/foundation/service-liveness-registry.ts +68 -59
- package/src/runtime/foundation/service-mailbox.ts +7 -1
- package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
- package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
- package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +128 -160
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -84
- package/src/runtime/foundation/service-topology-registry.ts +103 -42
- package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
- package/src/runtime/handlers/handler-instance-scope.ts +67 -16
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-runtime-options-factory.ts +14 -2
- package/src/runtime/host/application-job-queue.ts +249 -48
- package/src/runtime/host/entry-actor-runtime.ts +5 -0
- package/src/runtime/host/index.ts +224 -160
- package/src/runtime/host/instance-activation-authority.ts +132 -27
- package/src/runtime/host/remote-bound-session-relay.ts +2 -23
- package/src/runtime/host/route-mesh-runtime.ts +1 -1
- package/src/runtime/host/service-relocation-control.ts +11 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +317 -291
- package/src/runtime/host/spot-address-transport.ts +49 -24
- package/src/runtime/host/spot-runtime-options-factory.ts +4 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
- package/src/runtime/locations/actor-location-claims.ts +52 -30
- 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/lifecycle.ts +8 -26
- package/src/runtime/locations/location-store-repository.ts +220 -15
- package/src/runtime/locations/resolvers.ts +25 -2
- package/src/runtime/locations/runtime.ts +28 -24
- package/src/runtime/messaging/framework-json-v1.ts +5 -325
- package/src/runtime/messaging/packet-name.ts +5 -25
- package/src/runtime/messaging/request-result.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +7 -3
- package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +45 -23
- package/src/runtime/spots/index.ts +30 -2
- package/src/runtime/spots/spot-activation.ts +33 -10
- 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 +12 -2
- package/src/runtime/spots/spot-handler-registry.ts +41 -8
- package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
- package/src/runtime/spots/spot-outbound.ts +36 -16
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +3 -0
- package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
- package/src/runtime/spots/spot-timer.ts +5 -1
- package/src/runtime/streams/stream-session-runtime.ts +13 -30
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { durableRequestCanReplay } from '../foundation/durable-service-request';
|
|
1
2
|
import { UINT64_MAX, ZlinkStreamContentType } from '@zlink-systems/stream-wire';
|
|
2
3
|
import { randomBytes } from 'node:crypto';
|
|
3
4
|
import {
|
|
@@ -44,7 +45,7 @@ import {
|
|
|
44
45
|
type ZLinkRemoteBoundSessionTarget
|
|
45
46
|
} from '../actors/actor-runtime-state';
|
|
46
47
|
import type { ZLinkBackendMeshNode, ZLinkMeshCompletionTable } from '../backend';
|
|
47
|
-
import { RequestResult, SubmitResult } from '../backend/runtime-values';
|
|
48
|
+
import { RequestResult, SubmitResult, ZLinkBackendResultError } from '../backend/runtime-values';
|
|
48
49
|
import type { ZLinkFrameworkRegistration } from '../configuration';
|
|
49
50
|
import {
|
|
50
51
|
type ZLinkRuntimeEventPublisher,
|
|
@@ -184,13 +185,13 @@ import {
|
|
|
184
185
|
} from './relocation-state-adapter';
|
|
185
186
|
import {
|
|
186
187
|
decodeServiceRelocationControlRequest,
|
|
188
|
+
serviceRelocationControlCommand,
|
|
187
189
|
decodeServiceRelocationControlResponse,
|
|
188
190
|
encodeServiceRelocationControlRequest,
|
|
189
191
|
encodeServiceRelocationControlResponse,
|
|
190
192
|
type ZLinkServiceRelocationControlRequest,
|
|
191
193
|
type ZLinkServiceRelocationControlResponse
|
|
192
194
|
} from './service-relocation-control';
|
|
193
|
-
const RELOCATION_ATTEMPT_TIMEOUT_MS = 250;
|
|
194
195
|
|
|
195
196
|
const RELOCATION_AUTHORITY_RETRY_DELAY_MS = 25;
|
|
196
197
|
|
|
@@ -215,6 +216,7 @@ const RELOCATION_PARTICIPANT_STATE_LIMIT_BYTES = 64 * 1024 * 1024;
|
|
|
215
216
|
const RELOCATION_TARGET_TOMBSTONE_LIMIT = 1024;
|
|
216
217
|
const RELOCATION_OPERATION_RETENTION_MS = 5 * 60_000;
|
|
217
218
|
const SERVICE_CONTROL_TERMINAL_CAPACITY = 4096;
|
|
219
|
+
const INITIAL_MEMBERSHIP_EPOCH = 1n;
|
|
218
220
|
|
|
219
221
|
interface ZLinkHostRelocationOptions {
|
|
220
222
|
readonly registration: ZLinkFrameworkRegistration;
|
|
@@ -222,6 +224,7 @@ interface ZLinkHostRelocationOptions {
|
|
|
222
224
|
readonly locationStore: () => ZLinkLocationStore | undefined;
|
|
223
225
|
readonly currentOwner: () => ZLinkLocationOwnerToken | undefined;
|
|
224
226
|
readonly targetAdmissionSealed?: () => boolean;
|
|
227
|
+
readonly sourceQuiescenceChanged?: () => void;
|
|
225
228
|
readonly liveDescriptors: (
|
|
226
229
|
meshName: string,
|
|
227
230
|
signal?: AbortSignal
|
|
@@ -280,6 +283,7 @@ interface LocalStage {
|
|
|
280
283
|
finalize?: Promise<void>;
|
|
281
284
|
/** The Restore's activation admission (MeshNode §5.1); held until target commit or abort. */
|
|
282
285
|
readonly releaseActivation: () => void;
|
|
286
|
+
readonly releaseJoinAdmission: () => void;
|
|
283
287
|
}
|
|
284
288
|
|
|
285
289
|
interface TargetPayloadAssembly {
|
|
@@ -294,8 +298,8 @@ interface SourceCutoverWindow {
|
|
|
294
298
|
readonly targetNodeRid: RoutingId;
|
|
295
299
|
/** Boundary batch frames plus the cutover frame, retained until authority settlement. */
|
|
296
300
|
frames?: readonly Buffer[];
|
|
297
|
-
/**
|
|
298
|
-
|
|
301
|
+
/** The ready route used to submit the retained batch. */
|
|
302
|
+
submittedRouteGeneration?: bigint;
|
|
299
303
|
readonly cutoverSubmittedAtMs: number;
|
|
300
304
|
followTimer?: ReturnType<typeof setTimeout>;
|
|
301
305
|
windowClosed: boolean;
|
|
@@ -500,7 +504,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
500
504
|
},
|
|
501
505
|
input.relocationId,
|
|
502
506
|
true,
|
|
503
|
-
input.advertisedReceiveChunkLimitBytes
|
|
507
|
+
input.advertisedReceiveChunkLimitBytes,
|
|
508
|
+
input.deadlineAtMs
|
|
504
509
|
);
|
|
505
510
|
resolveReady();
|
|
506
511
|
} catch (error) {
|
|
@@ -542,7 +547,9 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
542
547
|
for (const window of this.sourceCutoverWindows.values()) {
|
|
543
548
|
if (window.followTimer !== undefined) clearTimeout(window.followTimer);
|
|
544
549
|
}
|
|
550
|
+
const hadSourceWindows = this.sourceCutoverWindows.size !== 0;
|
|
545
551
|
this.sourceCutoverWindows.clear();
|
|
552
|
+
if (hadSourceWindows) this.options.sourceQuiescenceChanged?.();
|
|
546
553
|
const stopped = new Error('Relocation runtime stopped.');
|
|
547
554
|
stopped.name = 'AbortError';
|
|
548
555
|
this.targetPrepareOperations.clear();
|
|
@@ -806,14 +813,32 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
806
813
|
throw failure;
|
|
807
814
|
}
|
|
808
815
|
|
|
809
|
-
|
|
816
|
+
tryHandleControl(
|
|
810
817
|
meshName: string,
|
|
811
818
|
record: ReceiveRecord,
|
|
812
819
|
signal?: AbortSignal
|
|
813
|
-
): Promise<boolean> {
|
|
820
|
+
): boolean | Promise<boolean> {
|
|
814
821
|
if (record.parts.length === 0) return false;
|
|
815
822
|
const payload = record.parts[0]!.data();
|
|
816
|
-
|
|
823
|
+
const command = serviceRelocationControlCommand(payload);
|
|
824
|
+
if (command === undefined) {
|
|
825
|
+
if (record.kind !== ReceiveKind.NodeSend) return false;
|
|
826
|
+
const sourceLeave = decodeRemoteActorSourceLeaveTerminal(payload);
|
|
827
|
+
if (sourceLeave === undefined) return false;
|
|
828
|
+
if (record.parts.length !== 1) return false;
|
|
829
|
+
return this.acceptActorJoinSourceLeave(sourceLeave);
|
|
830
|
+
}
|
|
831
|
+
return this.handleControl(meshName, record, payload, command, signal);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
private async handleControl(
|
|
835
|
+
meshName: string,
|
|
836
|
+
record: ReceiveRecord,
|
|
837
|
+
payload: Buffer,
|
|
838
|
+
command: number,
|
|
839
|
+
signal?: AbortSignal
|
|
840
|
+
): Promise<boolean> {
|
|
841
|
+
if (command === M6bServiceWireCommand.replyRelay) {
|
|
817
842
|
await this.handleReplyRelay(
|
|
818
843
|
meshName,
|
|
819
844
|
decodeMaintenanceReplyRelay(record.parts.map((part) => part.data())),
|
|
@@ -822,25 +847,21 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
822
847
|
);
|
|
823
848
|
return true;
|
|
824
849
|
}
|
|
825
|
-
|
|
826
|
-
record.parts.length === 1
|
|
827
|
-
? undefined
|
|
828
|
-
: decodePrepareSideband(record.parts.slice(1).map((part) => part.data()));
|
|
829
|
-
if (record.parts.length > 1 && sideband === undefined) return false;
|
|
850
|
+
if (record.parts.length !== 1) return false;
|
|
830
851
|
if (record.kind === ReceiveKind.NodeSend) {
|
|
831
852
|
const sourceLeave = decodeRemoteActorSourceLeaveTerminal(payload);
|
|
832
853
|
if (sourceLeave !== undefined) {
|
|
833
854
|
return this.acceptActorJoinSourceLeave(sourceLeave);
|
|
834
855
|
}
|
|
835
856
|
}
|
|
836
|
-
if (
|
|
857
|
+
if (command === M6bServiceWireCommand.sessionRelocationSealed) {
|
|
837
858
|
this.acceptSessionRelocationResponse(
|
|
838
859
|
decodeSessionRelocationSealed(payload),
|
|
839
860
|
record.sourceNodeRid
|
|
840
861
|
);
|
|
841
862
|
return true;
|
|
842
863
|
}
|
|
843
|
-
if (
|
|
864
|
+
if (command === M6bServiceWireCommand.sessionRelocationSeal) {
|
|
844
865
|
const request = decodeSessionRelocationSeal(payload);
|
|
845
866
|
const response = await this.handleSessionRelocationSeal(
|
|
846
867
|
meshName,
|
|
@@ -855,12 +876,12 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
855
876
|
);
|
|
856
877
|
return true;
|
|
857
878
|
}
|
|
858
|
-
if (
|
|
879
|
+
if (command === M6bServiceWireCommand.sessionRelocationRoute) {
|
|
859
880
|
const request = decodeSessionRelocationRoute(payload);
|
|
860
881
|
await this.handleSessionRelocationRoute(meshName, request, record.sourceNodeRid, signal);
|
|
861
882
|
return true;
|
|
862
883
|
}
|
|
863
|
-
if (
|
|
884
|
+
if (command === M6bServiceWireCommand.replyRelayAck) {
|
|
864
885
|
await this.acceptReplyRelayAck(
|
|
865
886
|
meshName,
|
|
866
887
|
decodeMaintenanceReplyRelayAck(payload),
|
|
@@ -871,10 +892,6 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
871
892
|
}
|
|
872
893
|
let request = decodeServiceRelocationControlRequest(payload);
|
|
873
894
|
if (request === undefined) return false;
|
|
874
|
-
if (sideband !== undefined) {
|
|
875
|
-
if (request.kind !== 'prepare') return false;
|
|
876
|
-
request = { ...request, nodeInternalBoundSessions: sideband };
|
|
877
|
-
}
|
|
878
895
|
// Ready(30) and Failed(53) are replies to Prepare(40), never independent
|
|
879
896
|
// inbound controls. The source consumes them on Core's request reply leg.
|
|
880
897
|
if (request.kind === 'ready' || request.kind === 'failed') return false;
|
|
@@ -1473,7 +1490,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
1473
1490
|
const status = this.requireMeshNode(meshName).status();
|
|
1474
1491
|
const owner = this.options.currentOwner();
|
|
1475
1492
|
if (
|
|
1476
|
-
|
|
1493
|
+
!routingIdsEqual(status.routingId, session.sessionOwnerNodeRid) ||
|
|
1477
1494
|
status.lifecycleGeneration !== session.sessionOwnerNodeGeneration ||
|
|
1478
1495
|
owner?.ownerId !== session.sessionOwnerId ||
|
|
1479
1496
|
owner.leaseGeneration !== session.sessionOwnerLeaseGeneration
|
|
@@ -1833,7 +1850,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
1833
1850
|
aggregateIdOverride?: string,
|
|
1834
1851
|
retainSourceForActorJoin = false,
|
|
1835
1852
|
/** Target's advertised relocation state chunk cap (Actor Join only; spec 15 §4.2). */
|
|
1836
|
-
advertisedReceiveChunkLimitBytes?: number
|
|
1853
|
+
advertisedReceiveChunkLimitBytes?: number,
|
|
1854
|
+
deadlineAtMs?: number
|
|
1837
1855
|
): Promise<void> {
|
|
1838
1856
|
if (isRelocationDebugEnabled()) {
|
|
1839
1857
|
relocationDebug('standalone_actor.begin', { actorId: state.actorId });
|
|
@@ -1922,7 +1940,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
1922
1940
|
new Map([[measuredUnit.authorityKey, authority]]),
|
|
1923
1941
|
signal,
|
|
1924
1942
|
sessions,
|
|
1925
|
-
advertisedReceiveChunkLimitBytes
|
|
1943
|
+
advertisedReceiveChunkLimitBytes,
|
|
1944
|
+
deadlineAtMs
|
|
1926
1945
|
);
|
|
1927
1946
|
} catch (error) {
|
|
1928
1947
|
outcome = 'failed';
|
|
@@ -2128,14 +2147,37 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2128
2147
|
}
|
|
2129
2148
|
const prepared = standalone ? ownSession : sessions.find((value) => value.state === state);
|
|
2130
2149
|
return {
|
|
2131
|
-
boundSessionState:
|
|
2150
|
+
boundSessionState: Buffer.alloc(0),
|
|
2151
|
+
...(prepared?.prepared.target?.serviceWireRelocation === undefined
|
|
2152
|
+
? {}
|
|
2153
|
+
: {
|
|
2154
|
+
sessionBinding: {
|
|
2155
|
+
participantId: 1n,
|
|
2156
|
+
sessionOwnerNodeRid: Buffer.from(
|
|
2157
|
+
encodeRoutingIdStorageHex(prepared.prepared.target.sessionNodeRid!),
|
|
2158
|
+
'hex'
|
|
2159
|
+
),
|
|
2160
|
+
sessionOwnerNodeGeneration:
|
|
2161
|
+
prepared.prepared.target.serviceWireRelocation.session
|
|
2162
|
+
.sessionOwnerNodeGeneration,
|
|
2163
|
+
sessionOwnerId:
|
|
2164
|
+
prepared.prepared.target.serviceWireRelocation.session.sessionOwnerId,
|
|
2165
|
+
sessionOwnerLeaseGeneration:
|
|
2166
|
+
prepared.prepared.target.serviceWireRelocation.session
|
|
2167
|
+
.sessionOwnerLeaseGeneration,
|
|
2168
|
+
sessionRid: Buffer.from(
|
|
2169
|
+
encodeRoutingIdStorageHex(prepared.prepared.target.sessionRid!),
|
|
2170
|
+
'hex'
|
|
2171
|
+
),
|
|
2172
|
+
bindingGeneration:
|
|
2173
|
+
prepared.prepared.target.serviceWireRelocation.session.bindingGeneration
|
|
2174
|
+
}
|
|
2175
|
+
}),
|
|
2132
2176
|
queuedMessages: encodeHandoffQueuedMessages(prepared?.prepared.handoffBacklog ?? []),
|
|
2133
2177
|
timers: []
|
|
2134
2178
|
};
|
|
2135
2179
|
},
|
|
2136
|
-
// The
|
|
2137
|
-
// state. The sealed bound-session target remains in sealed work and is
|
|
2138
|
-
// transported only by Prepare's NODE-INTERNAL sideband frames.
|
|
2180
|
+
// The sealed Session identity is part of the canonical participant vector.
|
|
2139
2181
|
captureApplicationState: (signal) =>
|
|
2140
2182
|
this.captureApplication(registration.relocation, state.actor!, signal),
|
|
2141
2183
|
commitSeal: async () => {
|
|
@@ -2229,7 +2271,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2229
2271
|
signal?: AbortSignal,
|
|
2230
2272
|
sessions: readonly SourceActorSession[] = [],
|
|
2231
2273
|
/** Target's advertised relocation state chunk cap (Actor Join only; spec 15 §4.2). */
|
|
2232
|
-
advertisedReceiveChunkLimitBytes?: number
|
|
2274
|
+
advertisedReceiveChunkLimitBytes?: number,
|
|
2275
|
+
controlDeadlineAtMs = performance.now() + RELOCATION_OPERATION_TIMEOUT_MS
|
|
2233
2276
|
): Promise<void> {
|
|
2234
2277
|
if (isRelocationDebugEnabled()) {
|
|
2235
2278
|
relocationDebug('coordinator.begin', {
|
|
@@ -2238,10 +2281,6 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2238
2281
|
});
|
|
2239
2282
|
}
|
|
2240
2283
|
const localStatus = this.requireMeshNode(meshName).status();
|
|
2241
|
-
const controlDeadlineAtMs =
|
|
2242
|
-
signal === undefined
|
|
2243
|
-
? performance.now() + RELOCATION_OPERATION_TIMEOUT_MS
|
|
2244
|
-
: Number.MAX_SAFE_INTEGER;
|
|
2245
2284
|
const coordinator = {
|
|
2246
2285
|
ownerId: primary.ownerId,
|
|
2247
2286
|
leaseGeneration: primary.ownerLeaseGeneration,
|
|
@@ -2326,29 +2365,31 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2326
2365
|
// queue and the assembly on the target), then stream the payload chunks
|
|
2327
2366
|
// on the same ordered connection. The Ready reply arrives only after
|
|
2328
2367
|
// the target assembled, verified, and restored the payload.
|
|
2329
|
-
const
|
|
2368
|
+
const ready = await this.sendControl(
|
|
2330
2369
|
meshName,
|
|
2331
2370
|
target.rid,
|
|
2332
2371
|
prepare,
|
|
2333
2372
|
signal,
|
|
2334
2373
|
controlDeadlineAtMs,
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2374
|
+
async (attemptSignal) => {
|
|
2375
|
+
if (isRelocationDebugEnabled())
|
|
2376
|
+
relocationDebug('coordinator.state_transfer_begin', {
|
|
2377
|
+
aggregateId: captured.envelope.aggregateId
|
|
2378
|
+
});
|
|
2379
|
+
await this.sendRelocationStateChunks(
|
|
2380
|
+
meshName,
|
|
2381
|
+
target,
|
|
2382
|
+
prepare,
|
|
2383
|
+
encoded,
|
|
2384
|
+
plan,
|
|
2385
|
+
attemptSignal
|
|
2386
|
+
);
|
|
2387
|
+
if (isRelocationDebugEnabled())
|
|
2388
|
+
relocationDebug('coordinator.await_ready', {
|
|
2389
|
+
aggregateId: captured.envelope.aggregateId
|
|
2390
|
+
});
|
|
2342
2391
|
}
|
|
2343
|
-
|
|
2344
|
-
} catch (chunkError) {
|
|
2345
|
-
readyOperation.catch(() => undefined);
|
|
2346
|
-
throw chunkError;
|
|
2347
|
-
}
|
|
2348
|
-
if (isRelocationDebugEnabled()) {
|
|
2349
|
-
relocationDebug('coordinator.await_ready', { aggregateId: captured.envelope.aggregateId });
|
|
2350
|
-
}
|
|
2351
|
-
const ready = await readyOperation;
|
|
2392
|
+
);
|
|
2352
2393
|
if (isRelocationDebugEnabled()) {
|
|
2353
2394
|
relocationDebug('coordinator.ready_received', {
|
|
2354
2395
|
aggregateId: captured.envelope.aggregateId
|
|
@@ -2413,14 +2454,16 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2413
2454
|
// The cutover submit result is not the authority result. The memory
|
|
2414
2455
|
// copy of the boundary batch and cutover stays until the authority
|
|
2415
2456
|
// settlement below (spec 28 §4.4).
|
|
2416
|
-
|
|
2457
|
+
const submittedRouteGeneration = this.requireMeshNode(meshName).observePeerRoute?.(
|
|
2458
|
+
target.rid
|
|
2459
|
+
).generation;
|
|
2417
2460
|
try {
|
|
2418
2461
|
for (const record of boundaryBatch) {
|
|
2419
2462
|
await this.submitControlFrame(meshName, target.rid, record.frame, 'relay');
|
|
2420
2463
|
}
|
|
2421
2464
|
await this.submitControlFrame(meshName, target.rid, cutoverFrame, 'cutover');
|
|
2422
2465
|
} catch (error) {
|
|
2423
|
-
|
|
2466
|
+
if (!durableRequestCanReplay(error)) throw error;
|
|
2424
2467
|
console.warn('[zlink.runtime.relocation.cutover_submit_failed]', relayAuthorityId, error);
|
|
2425
2468
|
}
|
|
2426
2469
|
const window = this.beginSourceCutoverWindow(
|
|
@@ -2428,7 +2471,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2428
2471
|
target.rid,
|
|
2429
2472
|
relayAuthorityId,
|
|
2430
2473
|
[...boundaryBatch.map((value) => value.frame), cutoverFrame],
|
|
2431
|
-
|
|
2474
|
+
submittedRouteGeneration,
|
|
2432
2475
|
limits
|
|
2433
2476
|
);
|
|
2434
2477
|
try {
|
|
@@ -2461,7 +2504,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2461
2504
|
// pending request without a terminal gets one Unavailable.
|
|
2462
2505
|
const unavailable = createInternalFrameworkException(
|
|
2463
2506
|
ZLinkFrameworkInternalErrorKind.RouteNotConnected,
|
|
2464
|
-
`Relocation '${relayAuthorityId}' source owner lease
|
|
2507
|
+
`Relocation '${relayAuthorityId}' source authority ended (source owner lease expired, authority Missing, or owner changed).`,
|
|
2465
2508
|
true
|
|
2466
2509
|
);
|
|
2467
2510
|
await captured.discardSource(unavailable);
|
|
@@ -2518,6 +2561,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2518
2561
|
signal
|
|
2519
2562
|
);
|
|
2520
2563
|
try {
|
|
2564
|
+
signal?.throwIfAborted();
|
|
2521
2565
|
await this.sendControlOneWay(meshName, target.rid, {
|
|
2522
2566
|
kind: 'state',
|
|
2523
2567
|
relocation: identity.relocation,
|
|
@@ -2597,7 +2641,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2597
2641
|
targetNodeRid: RoutingId,
|
|
2598
2642
|
relocationKey: string,
|
|
2599
2643
|
frames: readonly Buffer[],
|
|
2600
|
-
|
|
2644
|
+
submittedRouteGeneration: bigint | undefined,
|
|
2601
2645
|
limits: ReturnType<ZLinkHostServiceRelocationRuntime['relocationLimits']>
|
|
2602
2646
|
): SourceCutoverWindow {
|
|
2603
2647
|
const submittedAt = performance.now();
|
|
@@ -2605,12 +2649,14 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2605
2649
|
meshName,
|
|
2606
2650
|
targetNodeRid,
|
|
2607
2651
|
frames,
|
|
2608
|
-
|
|
2652
|
+
submittedRouteGeneration,
|
|
2609
2653
|
cutoverSubmittedAtMs: submittedAt,
|
|
2610
2654
|
windowClosed: false,
|
|
2611
2655
|
followExpired: false
|
|
2612
2656
|
};
|
|
2657
|
+
const wasQuiescent = this.isSafeToShutdown();
|
|
2613
2658
|
this.sourceCutoverWindows.set(relocationKey, window);
|
|
2659
|
+
if (wasQuiescent) this.options.sourceQuiescenceChanged?.();
|
|
2614
2660
|
window.followTimer = setTimeout(() => {
|
|
2615
2661
|
window.followExpired = true;
|
|
2616
2662
|
// S1→S4 route convergence: the span the source must keep its Message
|
|
@@ -2640,27 +2686,17 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2640
2686
|
this.sourceCutoverWindows.get(relocationKey) === window
|
|
2641
2687
|
) {
|
|
2642
2688
|
this.sourceCutoverWindows.delete(relocationKey);
|
|
2689
|
+
if (this.isSafeToShutdown()) this.options.sourceQuiescenceChanged?.();
|
|
2643
2690
|
}
|
|
2644
2691
|
}
|
|
2645
2692
|
|
|
2646
|
-
/**
|
|
2647
|
-
* Sends the whole boundary batch and cutover again after a failed submit
|
|
2648
|
-
* or an observed loss of the target connection (spec 28 §4.4). The target
|
|
2649
|
-
* replaces its partial span with the whole batch.
|
|
2650
|
-
*/
|
|
2693
|
+
/** Relocation flow §4.4: replay the whole batch on a different ready route. */
|
|
2651
2694
|
private async resendSourceCutover(window: SourceCutoverWindow): Promise<void> {
|
|
2652
2695
|
const frames = window.frames;
|
|
2653
2696
|
if (frames === undefined) return;
|
|
2654
|
-
const
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
value.routingId !== null && String(value.routingId) === String(window.targetNodeRid)
|
|
2658
|
-
);
|
|
2659
|
-
if (peer !== undefined && peer.state !== MeshPeerRuntimeState.Serving) {
|
|
2660
|
-
window.resendPending = true;
|
|
2661
|
-
return;
|
|
2662
|
-
}
|
|
2663
|
-
if (!window.resendPending) return;
|
|
2697
|
+
const route = this.requireMeshNode(window.meshName).observePeerRoute?.(window.targetNodeRid);
|
|
2698
|
+
if (route?.ready !== true || route.generation === window.submittedRouteGeneration) return;
|
|
2699
|
+
window.submittedRouteGeneration = route.generation;
|
|
2664
2700
|
try {
|
|
2665
2701
|
for (const frame of frames) {
|
|
2666
2702
|
await this.submitControlFrame(
|
|
@@ -2670,9 +2706,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2670
2706
|
'cutover retransmission'
|
|
2671
2707
|
);
|
|
2672
2708
|
}
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
// The next settlement round retries the whole batch.
|
|
2709
|
+
} catch (error) {
|
|
2710
|
+
if (!durableRequestCanReplay(error)) throw error;
|
|
2676
2711
|
}
|
|
2677
2712
|
}
|
|
2678
2713
|
|
|
@@ -2684,8 +2719,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2684
2719
|
* excludes a late target commit. `target`: the
|
|
2685
2720
|
* target committed. `source`: Preserve fenced the target out while the
|
|
2686
2721
|
* source owner lease was valid. `lost`: the source owner lease ended first
|
|
2687
|
-
* or another authority owns the object. An uncertain
|
|
2688
|
-
* keeps the work retained and repeats the same decision.
|
|
2722
|
+
* or authority is Missing or another authority owns the object. An uncertain
|
|
2723
|
+
* Store or lease result keeps the work retained and repeats the same decision.
|
|
2689
2724
|
*/
|
|
2690
2725
|
private async settleSourceAuthority(
|
|
2691
2726
|
envelope: ServiceRelocationEnvelope,
|
|
@@ -2871,17 +2906,24 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2871
2906
|
throw new ServiceRelocationDataLostError(String(message));
|
|
2872
2907
|
}
|
|
2873
2908
|
const envelope = decodeServiceRelocationEnvelope(payload, request.targetAttemptGeneration);
|
|
2874
|
-
const
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
const releaseActivation =
|
|
2880
|
-
(await this.options.activationAdmission?.acquire(meshName, signal)) ?? (() => undefined);
|
|
2909
|
+
const recovery = canonicalActorJoinRecovery(envelope.participants);
|
|
2910
|
+
const releaseJoinAdmission =
|
|
2911
|
+
recovery === undefined
|
|
2912
|
+
? () => undefined
|
|
2913
|
+
: this.options.spotManager()!.beginActorJoinRelocation(recovery.request.handoffId);
|
|
2881
2914
|
let materialized:
|
|
2882
2915
|
(Pick<LocalStage, 'owner' | 'staging'> & { readonly target: LocalTargetPort }) | undefined;
|
|
2883
2916
|
let reservation: TargetRelocationReservation | undefined;
|
|
2917
|
+
let releaseActivation: () => void = () => undefined;
|
|
2884
2918
|
try {
|
|
2919
|
+
const inventoryEnvelope = attachCanonicalBoundSessions(
|
|
2920
|
+
await this.resolveTargetParticipantInventory(meshName, request, envelope, signal),
|
|
2921
|
+
request,
|
|
2922
|
+
meshName
|
|
2923
|
+
);
|
|
2924
|
+
validatePrepareEnvelope(request, inventoryEnvelope);
|
|
2925
|
+
releaseActivation =
|
|
2926
|
+
(await this.options.activationAdmission?.acquire(meshName, signal)) ?? (() => undefined);
|
|
2885
2927
|
// Deferred Join completion publishes into the source authority's
|
|
2886
2928
|
// canonical relocation slot. Do that while the row is still CAS-able;
|
|
2887
2929
|
// the aggregate marker installed by reserveTargetForPrepare deliberately
|
|
@@ -2908,10 +2950,12 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
2908
2950
|
lane: Promise.resolve(),
|
|
2909
2951
|
cutoverReceived: false,
|
|
2910
2952
|
boundaryRelay: [],
|
|
2911
|
-
releaseActivation
|
|
2953
|
+
releaseActivation,
|
|
2954
|
+
releaseJoinAdmission
|
|
2912
2955
|
};
|
|
2913
2956
|
this.targetStages.set(stagingId, stage);
|
|
2914
2957
|
} catch (error) {
|
|
2958
|
+
releaseJoinAdmission();
|
|
2915
2959
|
releaseActivation();
|
|
2916
2960
|
if (reservation !== undefined) {
|
|
2917
2961
|
await this.abortTargetReservation(reservation, signal).catch(() => undefined);
|
|
@@ -3134,6 +3178,8 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3134
3178
|
throw new ServiceRelocationPostCommitError(authority, stage.staging, error);
|
|
3135
3179
|
}
|
|
3136
3180
|
throw error;
|
|
3181
|
+
} finally {
|
|
3182
|
+
stage.releaseJoinAdmission();
|
|
3137
3183
|
}
|
|
3138
3184
|
}
|
|
3139
3185
|
|
|
@@ -3154,7 +3200,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3154
3200
|
target.generation !== request.object.objectGeneration ||
|
|
3155
3201
|
target.targetNodeRid !== preparedTarget.nodeRid ||
|
|
3156
3202
|
target.targetNodeGeneration !== preparedTarget.nodeGeneration ||
|
|
3157
|
-
target.authorityOwnerGeneration !== request.object.expectedAuthorityOwnerGeneration
|
|
3203
|
+
target.authorityOwnerGeneration !== request.object.expectedAuthorityOwnerGeneration ||
|
|
3158
3204
|
target.ownerLeaseGeneration !== preparedTarget.ownerLeaseGeneration
|
|
3159
3205
|
) {
|
|
3160
3206
|
throw new Error('Relocation data does not target the exact temporary Actor queue.');
|
|
@@ -3293,7 +3339,9 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3293
3339
|
): Promise<void> {
|
|
3294
3340
|
const submitted = await this.sendInfrastructureControl(meshName, targetNodeRid, frame);
|
|
3295
3341
|
if (submitted !== SubmitResult.Ok) {
|
|
3296
|
-
throw new
|
|
3342
|
+
throw new ZLinkBackendResultError('submit', submitted, undefined, {
|
|
3343
|
+
cause: new Error(`Relocation ${kind} was not accepted by RouteMesh.`)
|
|
3344
|
+
});
|
|
3297
3345
|
}
|
|
3298
3346
|
}
|
|
3299
3347
|
|
|
@@ -3611,70 +3659,39 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3611
3659
|
request: ZLinkServiceRelocationControlRequest,
|
|
3612
3660
|
signal?: AbortSignal,
|
|
3613
3661
|
deadlineAtMs: number = performance.now() + RELOCATION_OPERATION_TIMEOUT_MS,
|
|
3614
|
-
|
|
3662
|
+
onSubmitted?: (signal: AbortSignal) => Promise<void>
|
|
3615
3663
|
): Promise<ReturnType<typeof decodeServiceRelocationControlResponse>> {
|
|
3616
3664
|
const key = controlAckKey(request);
|
|
3617
|
-
const frames =
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
if (remainingMs <= 0) {
|
|
3626
|
-
throw createInternalFrameworkException(
|
|
3627
|
-
ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
|
|
3628
|
-
`Relocation control ACK '${key}' timed out.`,
|
|
3629
|
-
true,
|
|
3630
|
-
lastRequestError
|
|
3631
|
-
);
|
|
3632
|
-
}
|
|
3633
|
-
const attemptTimeoutMs = Math.max(
|
|
3634
|
-
1,
|
|
3635
|
-
Math.min(RELOCATION_ATTEMPT_TIMEOUT_MS, Math.ceil(remainingMs))
|
|
3665
|
+
const frames = [encodeServiceRelocationControlRequest(request)];
|
|
3666
|
+
signal?.throwIfAborted();
|
|
3667
|
+
const remainingMs = Math.ceil(deadlineAtMs - performance.now());
|
|
3668
|
+
if (remainingMs <= 0) {
|
|
3669
|
+
throw createInternalFrameworkException(
|
|
3670
|
+
ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
|
|
3671
|
+
`Relocation control ACK '${key}' timed out.`,
|
|
3672
|
+
true
|
|
3636
3673
|
);
|
|
3637
|
-
const startedAtMs = performance.now();
|
|
3638
|
-
try {
|
|
3639
|
-
const replyFrames = await this.requestInfrastructureControl(
|
|
3640
|
-
meshName,
|
|
3641
|
-
targetNodeRid,
|
|
3642
|
-
frames,
|
|
3643
|
-
attemptTimeoutMs
|
|
3644
|
-
);
|
|
3645
|
-
if (replyFrames.length !== 1) {
|
|
3646
|
-
throw new ServiceWireProtocolError(
|
|
3647
|
-
`Relocation control '${key}' reply must contain exactly one frame.`
|
|
3648
|
-
);
|
|
3649
|
-
}
|
|
3650
|
-
const response = decodeServiceRelocationControlResponse(Buffer.from(replyFrames[0]!));
|
|
3651
|
-
if (response.kind === 'failed') {
|
|
3652
|
-
validateControlFailureResponse(request, response);
|
|
3653
|
-
throw relocationFailureException(response);
|
|
3654
|
-
}
|
|
3655
|
-
validateControlResponse(request, response);
|
|
3656
|
-
return response;
|
|
3657
|
-
} catch (error) {
|
|
3658
|
-
if (error instanceof ServiceWireProtocolError || error instanceof ZLinkFrameworkException) {
|
|
3659
|
-
throw error;
|
|
3660
|
-
}
|
|
3661
|
-
lastRequestError = error;
|
|
3662
|
-
if (isRelocationDebugEnabled()) {
|
|
3663
|
-
relocationDebug('control.request_retry', {
|
|
3664
|
-
key,
|
|
3665
|
-
kind: request.kind,
|
|
3666
|
-
targetRid: String(targetNodeRid)
|
|
3667
|
-
});
|
|
3668
|
-
}
|
|
3669
|
-
const retryDelayMs = Math.min(
|
|
3670
|
-
Math.max(0, attemptTimeoutMs - (performance.now() - startedAtMs)),
|
|
3671
|
-
Math.max(0, deadlineAtMs - performance.now())
|
|
3672
|
-
);
|
|
3673
|
-
if (retryDelayMs > 0) {
|
|
3674
|
-
await waitForRelocationRetry(retryDelayMs, signal);
|
|
3675
|
-
}
|
|
3676
|
-
}
|
|
3677
3674
|
}
|
|
3675
|
+
const replyFrames = await this.requestInfrastructureControl(
|
|
3676
|
+
meshName,
|
|
3677
|
+
targetNodeRid,
|
|
3678
|
+
frames,
|
|
3679
|
+
remainingMs,
|
|
3680
|
+
signal,
|
|
3681
|
+
onSubmitted
|
|
3682
|
+
);
|
|
3683
|
+
if (replyFrames.length !== 1) {
|
|
3684
|
+
throw new ServiceWireProtocolError(
|
|
3685
|
+
`Relocation control '${key}' reply must contain exactly one frame.`
|
|
3686
|
+
);
|
|
3687
|
+
}
|
|
3688
|
+
const response = decodeServiceRelocationControlResponse(Buffer.from(replyFrames[0]!));
|
|
3689
|
+
if (response.kind === 'failed') {
|
|
3690
|
+
validateControlFailureResponse(request, response);
|
|
3691
|
+
throw relocationFailureException(response);
|
|
3692
|
+
}
|
|
3693
|
+
validateControlResponse(request, response);
|
|
3694
|
+
return response;
|
|
3678
3695
|
}
|
|
3679
3696
|
|
|
3680
3697
|
private async selectTarget(
|
|
@@ -3761,7 +3778,10 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3761
3778
|
const publication = relocationPublication(prepare, envelope);
|
|
3762
3779
|
const participants = envelope.participants.map((participant) => {
|
|
3763
3780
|
const expected = authorities.get(participant.key)!;
|
|
3764
|
-
const membership = actorMembershipTarget(
|
|
3781
|
+
const membership = actorMembershipTarget(
|
|
3782
|
+
envelope.memberships.find((value) => value.actorKey === participant.key),
|
|
3783
|
+
this.options.localDescriptor?.(meshName)
|
|
3784
|
+
);
|
|
3765
3785
|
const entrySpotId =
|
|
3766
3786
|
expected.allocation.objectKind === 'actor' && membership === undefined
|
|
3767
3787
|
? this.options.spotManager()?.entrySpotIdForMesh(meshName)
|
|
@@ -3788,18 +3808,14 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3788
3808
|
objectGeneration: expected.objectGeneration,
|
|
3789
3809
|
targetAttemptGeneration: prepare.targetAttemptGeneration,
|
|
3790
3810
|
coordinatorExpectedStoreVersion: expected.storeVersion.value,
|
|
3791
|
-
...(membership
|
|
3792
|
-
|
|
3811
|
+
...(membership ??
|
|
3812
|
+
(expected.allocation.objectKind === 'actor'
|
|
3793
3813
|
? {
|
|
3794
3814
|
actorSpotId: entrySpotId!,
|
|
3795
3815
|
actorSpotGeneration: prepare.target.nodeGeneration,
|
|
3796
3816
|
actorSpotKind: ZLinkSpotKind.Entry as const
|
|
3797
3817
|
}
|
|
3798
|
-
: {}
|
|
3799
|
-
: {
|
|
3800
|
-
...membership,
|
|
3801
|
-
actorSpotKind: ZLinkSpotKind.User as const
|
|
3802
|
-
})
|
|
3818
|
+
: {}))
|
|
3803
3819
|
}),
|
|
3804
3820
|
membershipMutation: encodeMembershipMutation(envelope.memberships, participant.key)
|
|
3805
3821
|
};
|
|
@@ -3934,6 +3950,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
3934
3950
|
failures.push(error);
|
|
3935
3951
|
}
|
|
3936
3952
|
stage.phase = 'failed';
|
|
3953
|
+
stage.releaseJoinAdmission();
|
|
3937
3954
|
if (failures.length === 1) throw failures[0];
|
|
3938
3955
|
if (failures.length > 1) {
|
|
3939
3956
|
throw new AggregateError(failures, 'Relocation target rollback was incomplete.');
|
|
@@ -4098,6 +4115,7 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
4098
4115
|
|
|
4099
4116
|
/** Maps schema ordinals to the authoritative Location Store inventory. */
|
|
4100
4117
|
private async resolveTargetParticipantInventory(
|
|
4118
|
+
meshName: string,
|
|
4101
4119
|
request: ServiceMaintenanceRelocationPrepare,
|
|
4102
4120
|
envelope: ServiceRelocationEnvelope,
|
|
4103
4121
|
signal?: AbortSignal
|
|
@@ -4136,7 +4154,10 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
4136
4154
|
candidate.snapshot.payload,
|
|
4137
4155
|
candidate.snapshot.objectGeneration
|
|
4138
4156
|
);
|
|
4139
|
-
if (
|
|
4157
|
+
if (
|
|
4158
|
+
actor?.spotId === request.object.spotId &&
|
|
4159
|
+
actor.spotGeneration === request.object.objectGeneration
|
|
4160
|
+
) {
|
|
4140
4161
|
entries.push(candidate);
|
|
4141
4162
|
}
|
|
4142
4163
|
}
|
|
@@ -4184,21 +4205,23 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
4184
4205
|
authorityOwnerGeneration: snapshot.authorityOwnerGeneration
|
|
4185
4206
|
};
|
|
4186
4207
|
});
|
|
4187
|
-
//
|
|
4188
|
-
//
|
|
4189
|
-
// Location Store still names the source Spot until target cutover. Rebuild
|
|
4190
|
-
// the Actor lane from the already accepted ActorJoin admission, preserving
|
|
4191
|
-
// the target queue boundary for decoded saved-work.
|
|
4208
|
+
// Join recovery uses its accepted target membership. Maintenance Actor
|
|
4209
|
+
// roots restore into the target's startup Entry incarnation (§10.1).
|
|
4192
4210
|
const memberships =
|
|
4193
4211
|
request.object.kind === 'actor'
|
|
4194
|
-
?
|
|
4212
|
+
? actorRootTargetMembership(
|
|
4213
|
+
manager,
|
|
4214
|
+
envelope.aggregateId,
|
|
4215
|
+
participants,
|
|
4216
|
+
this.options.localDescriptor?.(meshName)
|
|
4217
|
+
)
|
|
4195
4218
|
: entries
|
|
4196
4219
|
.filter((entry) => entry.snapshot.allocation.objectKind === 'actor')
|
|
4197
4220
|
.map((entry) => ({
|
|
4198
4221
|
actorKey: entry.key.value,
|
|
4199
4222
|
spotKey: primaryKey.value,
|
|
4200
4223
|
spotObjectGeneration: primary.objectGeneration,
|
|
4201
|
-
membershipEpoch:
|
|
4224
|
+
membershipEpoch: INITIAL_MEMBERSHIP_EPOCH
|
|
4202
4225
|
}));
|
|
4203
4226
|
return {
|
|
4204
4227
|
...envelope,
|
|
@@ -4482,14 +4505,16 @@ export class ZLinkHostServiceRelocationRuntime implements ZLinkActorJoinRelocati
|
|
|
4482
4505
|
meshName: string,
|
|
4483
4506
|
targetNodeRid: RoutingId,
|
|
4484
4507
|
frames: readonly Uint8Array[],
|
|
4485
|
-
timeoutMs: number
|
|
4508
|
+
timeoutMs: number,
|
|
4509
|
+
signal?: AbortSignal,
|
|
4510
|
+
onSubmitted?: (signal: AbortSignal) => Promise<void>
|
|
4486
4511
|
): Promise<readonly Uint8Array[]> {
|
|
4487
4512
|
const node = this.requireMeshNode(meshName);
|
|
4488
4513
|
const request = node.requestInfrastructureControlFrames;
|
|
4489
4514
|
if (request === undefined) {
|
|
4490
4515
|
throw new Error('RouteMesh backend cannot submit bare infrastructure requests.');
|
|
4491
4516
|
}
|
|
4492
|
-
return await request.call(node, targetNodeRid, frames, { timeoutMs });
|
|
4517
|
+
return await request.call(node, targetNodeRid, frames, { timeoutMs, signal, onSubmitted });
|
|
4493
4518
|
}
|
|
4494
4519
|
}
|
|
4495
4520
|
|
|
@@ -4514,13 +4539,28 @@ function actorJoinAdmissionIdentity(envelope: ServiceRelocationEnvelope): string
|
|
|
4514
4539
|
);
|
|
4515
4540
|
}
|
|
4516
4541
|
|
|
4517
|
-
function
|
|
4542
|
+
function actorRootTargetMembership(
|
|
4518
4543
|
manager: DefaultZLinkSpotManager | undefined,
|
|
4519
4544
|
relocationId: string,
|
|
4520
|
-
participants: readonly ServiceRelocationParticipant[]
|
|
4545
|
+
participants: readonly ServiceRelocationParticipant[],
|
|
4546
|
+
localDescriptor: ZLinkMeshNodeDescriptor | undefined
|
|
4521
4547
|
): readonly ServiceRelocationMembership[] {
|
|
4522
4548
|
const recovery = canonicalActorJoinRecovery(participants);
|
|
4523
|
-
const
|
|
4549
|
+
const actor = participants.find((value) => value.objectKind === 'actor');
|
|
4550
|
+
if (recovery === undefined) {
|
|
4551
|
+
if (actor === undefined || localDescriptor?.entrySpotId === undefined) {
|
|
4552
|
+
throw new Error(`Actor relocation '${relocationId}' has no target Entry membership.`);
|
|
4553
|
+
}
|
|
4554
|
+
return [
|
|
4555
|
+
{
|
|
4556
|
+
actorKey: actor.key,
|
|
4557
|
+
spotKey: encodeAuthorityKey('user_spot', localDescriptor.entrySpotId).value,
|
|
4558
|
+
spotObjectGeneration: localDescriptor.lifecycleGeneration,
|
|
4559
|
+
membershipEpoch: INITIAL_MEMBERSHIP_EPOCH
|
|
4560
|
+
}
|
|
4561
|
+
];
|
|
4562
|
+
}
|
|
4563
|
+
const admissionId = recovery.request.handoffId;
|
|
4524
4564
|
const admission = (
|
|
4525
4565
|
manager as unknown as
|
|
4526
4566
|
| {
|
|
@@ -4538,7 +4578,6 @@ function actorJoinTargetMembership(
|
|
|
4538
4578
|
}
|
|
4539
4579
|
| undefined
|
|
4540
4580
|
)?.formalRemoteActorAdmissions?.get(admissionId);
|
|
4541
|
-
const actor = participants.find((value) => value.objectKind === 'actor');
|
|
4542
4581
|
if (admission === undefined || actor === undefined) {
|
|
4543
4582
|
throw new Error(`Actor relocation '${relocationId}' has no accepted target membership.`);
|
|
4544
4583
|
}
|
|
@@ -4570,18 +4609,19 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4570
4609
|
);
|
|
4571
4610
|
if (membership === undefined)
|
|
4572
4611
|
throw new Error(`Actor '${identity}' relocation membership is missing.`);
|
|
4573
|
-
const
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
const nativeEntrySpot = localDescriptor?.entrySpotId === spotIdentity;
|
|
4612
|
+
const targetMembership = actorMembershipTarget(
|
|
4613
|
+
membership,
|
|
4614
|
+
this.options.localDescriptor?.(this.meshName)
|
|
4615
|
+
)!;
|
|
4578
4616
|
const actor = await this.requireActorManager().prepareRelocationActor(
|
|
4579
4617
|
identity,
|
|
4580
4618
|
participant.stableType,
|
|
4581
4619
|
participant.objectGeneration,
|
|
4582
|
-
participant.authorityOwnerGeneration
|
|
4583
|
-
|
|
4584
|
-
|
|
4620
|
+
participant.authorityOwnerGeneration,
|
|
4621
|
+
targetMembership.actorSpotKind === ZLinkSpotKind.Entry
|
|
4622
|
+
? undefined
|
|
4623
|
+
: (targetMembership.actorSpotId as RoutingId),
|
|
4624
|
+
targetMembership.actorSpotGeneration,
|
|
4585
4625
|
membership.membershipEpoch,
|
|
4586
4626
|
signal
|
|
4587
4627
|
);
|
|
@@ -4603,7 +4643,7 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4603
4643
|
registration.implementation as Type<ZLinkSpot | ZLinkInstanceSpot>,
|
|
4604
4644
|
identity as RoutingId,
|
|
4605
4645
|
participant.objectGeneration,
|
|
4606
|
-
participant.authorityOwnerGeneration
|
|
4646
|
+
participant.authorityOwnerGeneration,
|
|
4607
4647
|
signal
|
|
4608
4648
|
);
|
|
4609
4649
|
return {
|
|
@@ -4654,9 +4694,11 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4654
4694
|
): Promise<void> {
|
|
4655
4695
|
for (const membership of memberships) {
|
|
4656
4696
|
const actor = hidden.get(membership.actorKey)?.actor;
|
|
4657
|
-
const
|
|
4658
|
-
|
|
4659
|
-
|
|
4697
|
+
const targetMembership = actorMembershipTarget(
|
|
4698
|
+
membership,
|
|
4699
|
+
this.options.localDescriptor?.(this.meshName)
|
|
4700
|
+
)!;
|
|
4701
|
+
const spotIdentity = targetMembership.actorSpotId;
|
|
4660
4702
|
const spot =
|
|
4661
4703
|
hidden.get(membership.spotKey)?.activation ??
|
|
4662
4704
|
this.requireSpotManager().resolveRelocationActivation(
|
|
@@ -4665,9 +4707,7 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4665
4707
|
);
|
|
4666
4708
|
if (actor === undefined) throw new Error('Relocation membership Actor staging is missing.');
|
|
4667
4709
|
const state = this.requireActorManager().getState(actor.context.actorId)!;
|
|
4668
|
-
|
|
4669
|
-
const isEntryMembership = localDescriptor?.entrySpotId === spotIdentity;
|
|
4670
|
-
if (isEntryMembership) {
|
|
4710
|
+
if (targetMembership.actorSpotKind === ZLinkSpotKind.Entry) {
|
|
4671
4711
|
// Entry Spot identity is published as a Location membership key, but
|
|
4672
4712
|
// it is not a User Spot activation in the Actor runtime. The native
|
|
4673
4713
|
// restore already received the target MeshNode RID as its Entry
|
|
@@ -4675,7 +4715,12 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4675
4715
|
// local Entry Spot path after the target commit.
|
|
4676
4716
|
state.clearJoinedSpot();
|
|
4677
4717
|
} else {
|
|
4678
|
-
state.setJoinedSpot(
|
|
4718
|
+
state.setJoinedSpot(
|
|
4719
|
+
spotIdentity as RoutingId,
|
|
4720
|
+
spot?.spot,
|
|
4721
|
+
membership.membershipEpoch,
|
|
4722
|
+
membership.spotObjectGeneration
|
|
4723
|
+
);
|
|
4679
4724
|
}
|
|
4680
4725
|
spot?.commitActorJoin(actor);
|
|
4681
4726
|
}
|
|
@@ -4812,6 +4857,7 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4812
4857
|
throw new Error('Relocated Entry Spot Actor dispatch is unavailable.');
|
|
4813
4858
|
}
|
|
4814
4859
|
return runtime.dispatchEntryActorPacket(
|
|
4860
|
+
'remote',
|
|
4815
4861
|
hidden.actor!.context.actorId,
|
|
4816
4862
|
parts,
|
|
4817
4863
|
returnResponse,
|
|
@@ -4820,6 +4866,7 @@ class LocalTargetPort implements ServiceRelocationTargetObjectPort<LocalHidden>
|
|
|
4820
4866
|
);
|
|
4821
4867
|
}
|
|
4822
4868
|
return this.requireSpotManager().dispatchRoutedActorPacket(
|
|
4869
|
+
'remote',
|
|
4823
4870
|
state.spotId,
|
|
4824
4871
|
hidden.actor!.context.actorId,
|
|
4825
4872
|
parts,
|
|
@@ -4942,14 +4989,22 @@ function rewriteAuthorityApplicationRoute(
|
|
|
4942
4989
|
}
|
|
4943
4990
|
|
|
4944
4991
|
function actorMembershipTarget(
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
):
|
|
4948
|
-
|
|
4992
|
+
membership: ServiceRelocationMembership | undefined,
|
|
4993
|
+
localDescriptor: ZLinkMeshNodeDescriptor | undefined
|
|
4994
|
+
):
|
|
4995
|
+
| {
|
|
4996
|
+
readonly actorSpotId: string;
|
|
4997
|
+
readonly actorSpotGeneration: bigint;
|
|
4998
|
+
readonly actorSpotKind: ZLinkSpotKind.Entry | ZLinkSpotKind.User;
|
|
4999
|
+
}
|
|
5000
|
+
| undefined {
|
|
4949
5001
|
if (membership === undefined) return undefined;
|
|
5002
|
+
const spotId = decodeAuthorityKey({ value: membership.spotKey } as ZLinkAuthorityKey).globalId;
|
|
4950
5003
|
return {
|
|
4951
|
-
actorSpotId:
|
|
4952
|
-
actorSpotGeneration: membership.spotObjectGeneration
|
|
5004
|
+
actorSpotId: spotId,
|
|
5005
|
+
actorSpotGeneration: membership.spotObjectGeneration,
|
|
5006
|
+
actorSpotKind:
|
|
5007
|
+
spotId === localDescriptor?.entrySpotId ? ZLinkSpotKind.Entry : ZLinkSpotKind.User
|
|
4953
5008
|
};
|
|
4954
5009
|
}
|
|
4955
5010
|
|
|
@@ -5703,7 +5758,7 @@ function canonicalQueuedFrozenRecord(
|
|
|
5703
5758
|
objectGeneration: participant.objectGeneration,
|
|
5704
5759
|
nodeRid: target.nodeRid,
|
|
5705
5760
|
nodeGeneration: target.nodeGeneration,
|
|
5706
|
-
authorityOwnerGeneration: participant.authorityOwnerGeneration
|
|
5761
|
+
authorityOwnerGeneration: participant.authorityOwnerGeneration,
|
|
5707
5762
|
ownerLeaseGeneration: target.ownerLeaseGeneration
|
|
5708
5763
|
},
|
|
5709
5764
|
operationId,
|
|
@@ -5902,16 +5957,6 @@ function replyRelayPendingKey(
|
|
|
5902
5957
|
return JSON.stringify([ackTargetNodeRid, replyRelayIdentityKey(value)]);
|
|
5903
5958
|
}
|
|
5904
5959
|
|
|
5905
|
-
function isServiceWireCommand(payload: Uint8Array, command: number): boolean {
|
|
5906
|
-
return (
|
|
5907
|
-
payload.byteLength >= 5 &&
|
|
5908
|
-
payload[0] === 0x5a &&
|
|
5909
|
-
payload[1] === 0x4d &&
|
|
5910
|
-
payload[2] === 1 &&
|
|
5911
|
-
payload[3] === command
|
|
5912
|
-
);
|
|
5913
|
-
}
|
|
5914
|
-
|
|
5915
5960
|
export function encodeHandoffQueuedMessages(
|
|
5916
5961
|
backlog: readonly ZLinkActorHandoffPacket[]
|
|
5917
5962
|
): readonly ServiceRelocationQueuedMessage[] {
|
|
@@ -5998,97 +6043,58 @@ function toServiceTimer(
|
|
|
5998
6043
|
};
|
|
5999
6044
|
}
|
|
6000
6045
|
|
|
6001
|
-
const PREPARE_SIDEBAND_MAGIC = 'ZLNI';
|
|
6002
|
-
const PREPARE_SIDEBAND_VERSION = 1;
|
|
6003
|
-
const PREPARE_SIDEBAND_HEADER_BYTES = 11;
|
|
6004
|
-
const PREPARE_SIDEBAND_VERSION_OFFSET = 4;
|
|
6005
|
-
const PREPARE_SIDEBAND_KEY_LENGTH_OFFSET = 5;
|
|
6006
|
-
const PREPARE_SIDEBAND_PAYLOAD_LENGTH_OFFSET = 7;
|
|
6007
6046
|
const ACTOR_SESSION_JOURNAL_VERSION = 1;
|
|
6008
6047
|
const SERVICE_RELOCATION_REPLY_PACKET_NAME = 'zlink.relocation.reply';
|
|
6009
6048
|
|
|
6010
|
-
|
|
6011
|
-
* NODE-INTERNAL Prepare sideband. Frame zero remains the exact canonical
|
|
6012
|
-
* command-40 schema record; each following ZLNI frame carries one sealed
|
|
6013
|
-
* actor-session journal keyed by its canonical participant authority key.
|
|
6014
|
-
* Sessionless relocation remains a single-frame, wire-identical Prepare.
|
|
6015
|
-
*/
|
|
6016
|
-
function encodePrepareSideband(envelope: ServiceRelocationEnvelope): readonly Buffer[] {
|
|
6017
|
-
return envelope.participants
|
|
6018
|
-
.filter((participant) => participant.boundSessionState.byteLength !== 0)
|
|
6019
|
-
.map((participant) => {
|
|
6020
|
-
const key = Buffer.from(participant.key, 'utf8');
|
|
6021
|
-
const payload = Buffer.from(participant.boundSessionState);
|
|
6022
|
-
if (key.byteLength === 0 || key.byteLength > 0xffff || payload.byteLength > 0xffff_ffff) {
|
|
6023
|
-
throw new TypeError('Bound-session relocation sideband is out of bounds.');
|
|
6024
|
-
}
|
|
6025
|
-
const header = Buffer.allocUnsafe(PREPARE_SIDEBAND_HEADER_BYTES);
|
|
6026
|
-
header.write(PREPARE_SIDEBAND_MAGIC, 0, 'ascii');
|
|
6027
|
-
header[PREPARE_SIDEBAND_VERSION_OFFSET] = PREPARE_SIDEBAND_VERSION;
|
|
6028
|
-
header.writeUInt16BE(key.byteLength, PREPARE_SIDEBAND_KEY_LENGTH_OFFSET);
|
|
6029
|
-
header.writeUInt32BE(payload.byteLength, PREPARE_SIDEBAND_PAYLOAD_LENGTH_OFFSET);
|
|
6030
|
-
return Buffer.concat([header, key, payload]);
|
|
6031
|
-
});
|
|
6032
|
-
}
|
|
6033
|
-
|
|
6034
|
-
function decodePrepareSideband(frames: readonly Uint8Array[]):
|
|
6035
|
-
| readonly {
|
|
6036
|
-
readonly participantKey: string;
|
|
6037
|
-
readonly payload: Buffer;
|
|
6038
|
-
}[]
|
|
6039
|
-
| undefined {
|
|
6040
|
-
const result: Array<{ readonly participantKey: string; readonly payload: Buffer }> = [];
|
|
6041
|
-
const keys = new Set<string>();
|
|
6042
|
-
for (const frame of frames) {
|
|
6043
|
-
const bytes = Buffer.from(frame);
|
|
6044
|
-
if (
|
|
6045
|
-
bytes.byteLength < PREPARE_SIDEBAND_HEADER_BYTES ||
|
|
6046
|
-
bytes.subarray(0, PREPARE_SIDEBAND_VERSION_OFFSET).toString('ascii') !==
|
|
6047
|
-
PREPARE_SIDEBAND_MAGIC ||
|
|
6048
|
-
bytes[PREPARE_SIDEBAND_VERSION_OFFSET] !== PREPARE_SIDEBAND_VERSION
|
|
6049
|
-
) {
|
|
6050
|
-
return undefined;
|
|
6051
|
-
}
|
|
6052
|
-
const keyLength = bytes.readUInt16BE(PREPARE_SIDEBAND_KEY_LENGTH_OFFSET);
|
|
6053
|
-
const payloadLength = bytes.readUInt32BE(PREPARE_SIDEBAND_PAYLOAD_LENGTH_OFFSET);
|
|
6054
|
-
if (
|
|
6055
|
-
PREPARE_SIDEBAND_HEADER_BYTES + keyLength + payloadLength !== bytes.byteLength ||
|
|
6056
|
-
keyLength === 0
|
|
6057
|
-
)
|
|
6058
|
-
return undefined;
|
|
6059
|
-
const participantKey = bytes
|
|
6060
|
-
.subarray(PREPARE_SIDEBAND_HEADER_BYTES, PREPARE_SIDEBAND_HEADER_BYTES + keyLength)
|
|
6061
|
-
.toString('utf8');
|
|
6062
|
-
if (keys.has(participantKey)) return undefined;
|
|
6063
|
-
keys.add(participantKey);
|
|
6064
|
-
result.push({
|
|
6065
|
-
participantKey,
|
|
6066
|
-
payload: Buffer.from(bytes.subarray(PREPARE_SIDEBAND_HEADER_BYTES + keyLength))
|
|
6067
|
-
});
|
|
6068
|
-
}
|
|
6069
|
-
return result;
|
|
6070
|
-
}
|
|
6071
|
-
|
|
6072
|
-
function attachPrepareBoundSessions(
|
|
6049
|
+
function attachCanonicalBoundSessions(
|
|
6073
6050
|
envelope: ServiceRelocationEnvelope,
|
|
6074
|
-
|
|
6051
|
+
request: ServiceMaintenanceRelocationPrepare,
|
|
6052
|
+
meshName: string
|
|
6075
6053
|
): ServiceRelocationEnvelope {
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6054
|
+
return {
|
|
6055
|
+
...envelope,
|
|
6056
|
+
participants: envelope.participants.map((participant) => {
|
|
6057
|
+
const binding = participant.sessionBinding;
|
|
6058
|
+
if (binding === undefined) return participant;
|
|
6059
|
+
if (participant.objectKind !== 'actor')
|
|
6060
|
+
throw new TypeError('Session binding names a non-Actor participant.');
|
|
6061
|
+
const sessionNodeRid = decodeRoutingId(
|
|
6062
|
+
'',
|
|
6063
|
+
Buffer.from(binding.sessionOwnerNodeRid).toString('hex')
|
|
6064
|
+
);
|
|
6065
|
+
const sessionRid = decodeRoutingId('', Buffer.from(binding.sessionRid).toString('hex'));
|
|
6066
|
+
const session = {
|
|
6067
|
+
sessionOwnerNodeRid: sessionNodeRid as string,
|
|
6068
|
+
sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
|
|
6069
|
+
sessionOwnerId: binding.sessionOwnerId,
|
|
6070
|
+
sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
|
|
6071
|
+
sessionRid: sessionRid as string,
|
|
6072
|
+
bindingGeneration: binding.bindingGeneration
|
|
6073
|
+
};
|
|
6074
|
+
const target: ZLinkRemoteBoundSessionTarget = {
|
|
6075
|
+
routerChannelId: meshName,
|
|
6076
|
+
targetNodeRid: sessionNodeRid,
|
|
6077
|
+
spotId:
|
|
6078
|
+
request.object.kind === 'actor'
|
|
6079
|
+
? ((participant.rootSpotId ?? '') as RoutingId)
|
|
6080
|
+
: (request.object.spotId as RoutingId),
|
|
6081
|
+
sessionNodeRid,
|
|
6082
|
+
sessionRid,
|
|
6083
|
+
sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
|
|
6084
|
+
sessionOwnerId: binding.sessionOwnerId,
|
|
6085
|
+
sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
|
|
6086
|
+
bindingGeneration: binding.bindingGeneration,
|
|
6087
|
+
previousAuthorityOwnerGeneration: participant.authorityOwnerGeneration,
|
|
6088
|
+
relocationSealId: envelope.aggregateId,
|
|
6089
|
+
serviceWireRelocation: {
|
|
6090
|
+
relocation: request.relocation,
|
|
6091
|
+
coordinator: request.coordinator,
|
|
6092
|
+
session
|
|
6093
|
+
}
|
|
6094
|
+
};
|
|
6095
|
+
return { ...participant, boundSessionState: encodeActorSession(target) };
|
|
6096
|
+
})
|
|
6097
|
+
};
|
|
6092
6098
|
}
|
|
6093
6099
|
|
|
6094
6100
|
function encodeActorSession(target: ZLinkRemoteBoundSessionTarget | undefined): Buffer {
|
|
@@ -6101,7 +6107,13 @@ function encodeActorSession(target: ZLinkRemoteBoundSessionTarget | undefined):
|
|
|
6101
6107
|
spotId: String(target.spotId),
|
|
6102
6108
|
sessionNodeRid:
|
|
6103
6109
|
target.sessionNodeRid === undefined ? undefined : String(target.sessionNodeRid),
|
|
6110
|
+
sessionNodeRidHex:
|
|
6111
|
+
target.sessionNodeRid === undefined
|
|
6112
|
+
? undefined
|
|
6113
|
+
: encodeRoutingIdStorageHex(target.sessionNodeRid),
|
|
6104
6114
|
sessionRid: target.sessionRid === undefined ? undefined : String(target.sessionRid),
|
|
6115
|
+
sessionRidHex:
|
|
6116
|
+
target.sessionRid === undefined ? undefined : encodeRoutingIdStorageHex(target.sessionRid),
|
|
6105
6117
|
sessionOwnerNodeGeneration: target.sessionOwnerNodeGeneration?.toString(),
|
|
6106
6118
|
sessionOwnerId: target.sessionOwnerId,
|
|
6107
6119
|
sessionOwnerLeaseGeneration: target.sessionOwnerLeaseGeneration?.toString(),
|
|
@@ -6124,12 +6136,18 @@ function encodeActorSession(target: ZLinkRemoteBoundSessionTarget | undefined):
|
|
|
6124
6136
|
expectedAuthorityStoreVersion:
|
|
6125
6137
|
target.serviceWireRelocation.coordinator.expectedAuthorityStoreVersion,
|
|
6126
6138
|
sessionOwnerNodeRid: target.serviceWireRelocation.session.sessionOwnerNodeRid,
|
|
6139
|
+
sessionOwnerNodeRidHex: encodeRoutingIdStorageHex(
|
|
6140
|
+
target.serviceWireRelocation.session.sessionOwnerNodeRid as RoutingId
|
|
6141
|
+
),
|
|
6127
6142
|
sessionOwnerNodeGeneration:
|
|
6128
6143
|
target.serviceWireRelocation.session.sessionOwnerNodeGeneration.toString(),
|
|
6129
6144
|
sessionOwnerId: target.serviceWireRelocation.session.sessionOwnerId,
|
|
6130
6145
|
sessionOwnerLeaseGeneration:
|
|
6131
6146
|
target.serviceWireRelocation.session.sessionOwnerLeaseGeneration.toString(),
|
|
6132
6147
|
sessionRid: target.serviceWireRelocation.session.sessionRid,
|
|
6148
|
+
sessionRidHex: encodeRoutingIdStorageHex(
|
|
6149
|
+
target.serviceWireRelocation.session.sessionRid as RoutingId
|
|
6150
|
+
),
|
|
6133
6151
|
bindingGeneration: target.serviceWireRelocation.session.bindingGeneration.toString()
|
|
6134
6152
|
}
|
|
6135
6153
|
}),
|
|
@@ -6156,9 +6174,11 @@ function decodeActorSession(payload: Uint8Array): ZLinkRemoteBoundSessionTarget
|
|
|
6156
6174
|
targetNodeRid: value.targetNodeRid as RoutingId,
|
|
6157
6175
|
spotId: value.spotId as RoutingId,
|
|
6158
6176
|
...(typeof value.sessionNodeRid === 'string'
|
|
6159
|
-
? { sessionNodeRid: value.sessionNodeRid
|
|
6177
|
+
? { sessionNodeRid: decodeRoutingId(value.sessionNodeRid, value.sessionNodeRidHex) }
|
|
6178
|
+
: {}),
|
|
6179
|
+
...(typeof value.sessionRid === 'string'
|
|
6180
|
+
? { sessionRid: decodeRoutingId(value.sessionRid, value.sessionRidHex) }
|
|
6160
6181
|
: {}),
|
|
6161
|
-
...(typeof value.sessionRid === 'string' ? { sessionRid: value.sessionRid as RoutingId } : {}),
|
|
6162
6182
|
...(optionalBigInt('sessionOwnerNodeGeneration') === undefined
|
|
6163
6183
|
? {}
|
|
6164
6184
|
: { sessionOwnerNodeGeneration: optionalBigInt('sessionOwnerNodeGeneration') }),
|
|
@@ -6227,11 +6247,17 @@ function decodeActorSessionServiceWireFence(
|
|
|
6227
6247
|
expectedAuthorityStoreVersion: text('expectedAuthorityStoreVersion')
|
|
6228
6248
|
},
|
|
6229
6249
|
session: {
|
|
6230
|
-
sessionOwnerNodeRid:
|
|
6250
|
+
sessionOwnerNodeRid: decodeRoutingId(
|
|
6251
|
+
typeof value.sessionOwnerNodeRid === 'string' ? value.sessionOwnerNodeRid : '',
|
|
6252
|
+
value.sessionOwnerNodeRidHex
|
|
6253
|
+
) as string,
|
|
6231
6254
|
sessionOwnerNodeGeneration: positive('sessionOwnerNodeGeneration'),
|
|
6232
6255
|
sessionOwnerId: text('sessionOwnerId'),
|
|
6233
6256
|
sessionOwnerLeaseGeneration: positive('sessionOwnerLeaseGeneration'),
|
|
6234
|
-
sessionRid:
|
|
6257
|
+
sessionRid: decodeRoutingId(
|
|
6258
|
+
typeof value.sessionRid === 'string' ? value.sessionRid : '',
|
|
6259
|
+
value.sessionRidHex
|
|
6260
|
+
) as string,
|
|
6235
6261
|
bindingGeneration: positive('bindingGeneration')
|
|
6236
6262
|
}
|
|
6237
6263
|
};
|