@zlink-systems/framework 0.21.0 → 0.23.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/Common/ZLinkMessage.js +5 -5
- package/dist/contracts/Configuration/CodecContentType.js +5 -7
- package/dist/contracts/Configuration/DiagnosticsValidation.js +1 -6
- package/dist/contracts/Configuration/EndpointNotation.js +4 -8
- package/dist/contracts/Configuration/Registration.js +14 -11
- package/dist/contracts/Configuration/RegistrationBuilders.js +32 -25
- package/dist/contracts/Configuration/RegistrationNormalizers.js +25 -26
- package/dist/contracts/Configuration/RegistrationValidators.js +36 -38
- package/dist/contracts/Configuration/SendTimeoutValidation.js +4 -4
- package/dist/contracts/Configuration/TimerRegistrationValidator.js +7 -7
- package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +1 -0
- package/dist/contracts/Handlers/JsonContract.js +23 -11
- package/dist/contracts/Spots/SpotKind.js +16 -8
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -1
- package/dist/location-store-integration.js +16 -16
- package/dist/nest-integration.js +17 -11
- package/dist/runtime/abort.js +9 -5
- package/dist/runtime/actors/actor-authority-payload-codec.js +12 -16
- package/dist/runtime/actors/actor-authority-publication.js +18 -17
- package/dist/runtime/actors/actor-client.js +83 -63
- package/dist/runtime/actors/actor-context.js +28 -22
- package/dist/runtime/actors/actor-creation.js +4 -3
- package/dist/runtime/actors/actor-handoff.js +89 -92
- package/dist/runtime/actors/actor-join-deferred-scope.d.ts +0 -1
- package/dist/runtime/actors/actor-join-deferred-scope.js +0 -18
- package/dist/runtime/actors/actor-local-native-join.js +18 -19
- package/dist/runtime/actors/actor-mailbox.js +1 -1
- package/dist/runtime/actors/actor-message-follow-context.js +24 -21
- package/dist/runtime/actors/actor-packet-relay-wire.js +1 -3
- package/dist/runtime/actors/actor-remote-joiner.js +20 -17
- package/dist/runtime/actors/actor-remote-wire.js +6 -7
- package/dist/runtime/actors/actor-runtime-state.js +87 -81
- package/dist/runtime/actors/actor-transfer-registry.js +3 -5
- package/dist/runtime/actors/bound-session-wire.js +14 -9
- package/dist/runtime/actors/deferred-join-accepted-journal.js +160 -130
- package/dist/runtime/actors/index.js +2 -5
- package/dist/runtime/actors/post-commit-actor-binder.js +3 -6
- package/dist/runtime/actors/post-commit-actor-location.js +1 -1
- package/dist/runtime/actors/spot-actor-dispatch.js +5 -5
- package/dist/runtime/actors/transferred-actor-rollback.js +4 -4
- package/dist/runtime/admission.js +2 -6
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +2 -6
- package/dist/runtime/application-jobs/receive-flow-controller.js +11 -12
- package/dist/runtime/backend/contracts/index.d.ts +1 -0
- package/dist/runtime/backend/mesh-completion-table.js +1 -3
- package/dist/runtime/backend/mesh-dispatch-pump.js +12 -16
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +1 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +26 -17
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +4 -3
- package/dist/runtime/backend/node/node-raw-binding-port.js +7 -6
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +3 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +134 -118
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +12 -13
- package/dist/runtime/backend/runtime-message.js +3 -3
- package/dist/runtime/backend/runtime-values.d.ts +2 -2
- package/dist/runtime/backend/runtime-values.js +4 -5
- package/dist/runtime/channels/channel-clients.js +27 -24
- package/dist/runtime/channels/channel-dispatch-pipeline.js +12 -20
- package/dist/runtime/channels/channel-dispatch-services.js +7 -4
- package/dist/runtime/channels/channel-dispatchers.js +9 -9
- package/dist/runtime/channels/channel-envelope-inspection.js +16 -13
- package/dist/runtime/channels/channel-envelope.js +83 -47
- package/dist/runtime/channels/channel-outbound-operations.js +8 -8
- package/dist/runtime/channels/channel-receive-loops.js +20 -22
- package/dist/runtime/channels/channel-receive-task-tracker.js +1 -1
- package/dist/runtime/channels/channel-runtime-lifecycle.js +61 -56
- package/dist/runtime/channels/channel-runtime-manager.js +18 -9
- package/dist/runtime/channels/channel-socket-registry.js +126 -123
- package/dist/runtime/channels/channel-transports.js +46 -42
- package/dist/runtime/channels/client-server-location-runtime.js +32 -40
- package/dist/runtime/channels/client-server-service-wire.js +29 -22
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +1 -0
- package/dist/runtime/channels/dispatch-error-reporter.js +9 -39
- package/dist/runtime/channels/fanout-location-runtime.js +34 -47
- package/dist/runtime/channels/fanout-service-wire.js +3 -5
- package/dist/runtime/channels/local-spot-route-transport.js +7 -1
- package/dist/runtime/channels/route-member-snapshot.js +3 -3
- package/dist/runtime/channels/source-spot-router.js +6 -2
- package/dist/runtime/channels/spot-route-bridge-transport.js +5 -2
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +2 -2
- package/dist/runtime/channels/spot-route-target-resolver.js +6 -6
- package/dist/runtime/diagnostics/dispatch-error-details.d.ts +6 -0
- package/dist/runtime/diagnostics/dispatch-error-details.js +55 -0
- package/dist/runtime/diagnostics/flow-context.d.ts +2 -1
- package/dist/runtime/diagnostics/flow-context.js +2 -2
- package/dist/runtime/diagnostics/index.js +38 -10
- package/dist/runtime/diagnostics/message-flow.js +58 -42
- package/dist/runtime/diagnostics/runtime-metrics.js +18 -9
- package/dist/runtime/diagnostics/runtime-observation-queue.js +8 -10
- package/dist/runtime/diagnostics/topology-runtime-projections.js +17 -10
- package/dist/runtime/execution/index.js +7 -6
- package/dist/runtime/execution/serial-execution-queue.js +12 -18
- package/dist/runtime/execution/state-lane.js +2 -2
- package/dist/runtime/foundation/actor-join-recovery-codec.js +31 -27
- package/dist/runtime/foundation/event-loop-resources.js +4 -4
- package/dist/runtime/foundation/message-follow-suppression-registry.js +4 -4
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +4 -2
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +169 -144
- package/dist/runtime/foundation/route-mesh-connection-policy.js +4 -4
- package/dist/runtime/foundation/runtime-state-projections.js +22 -11
- package/dist/runtime/foundation/service-authority-payload-codec.js +13 -15
- package/dist/runtime/foundation/service-discovery-registry.js +35 -33
- package/dist/runtime/foundation/service-instance-activation-recovery-codec.js +20 -22
- package/dist/runtime/foundation/service-liveness-registry.js +16 -12
- package/dist/runtime/foundation/service-maintenance-runtime.js +2 -4
- package/dist/runtime/foundation/service-relocation-aggregate-committer.js +24 -24
- package/dist/runtime/foundation/service-relocation-object-owner.js +6 -6
- package/dist/runtime/foundation/service-relocation-runtime.js +137 -94
- package/dist/runtime/foundation/service-runtime-contracts.js +5 -5
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +1 -0
- package/dist/runtime/foundation/service-stateful-registry.js +24 -23
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -0
- package/dist/runtime/foundation/service-stateful-runtime.js +461 -439
- package/dist/runtime/foundation/service-stateful-wire-codec.js +95 -98
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -0
- package/dist/runtime/foundation/service-topology-registry.js +105 -96
- package/dist/runtime/foundation/service-weighted-selection.js +6 -11
- package/dist/runtime/foundation/service-wire-binary-primitives.js +5 -6
- package/dist/runtime/foundation/service-wire-m6a-codec.js +46 -35
- package/dist/runtime/framework-errors-internal.js +7 -10
- package/dist/runtime/handlers/handler-instance-scope.js +4 -5
- package/dist/runtime/handlers/index.js +3 -1
- package/dist/runtime/host/actor-packet-relay.js +74 -70
- package/dist/runtime/host/actor-placement-coordinator.js +29 -31
- package/dist/runtime/host/actor-runtime-options-factory.js +12 -14
- package/dist/runtime/host/actor-transfer-authority-runtime.js +7 -9
- package/dist/runtime/host/actor-transfer-runtime.js +176 -153
- package/dist/runtime/host/application-job-queue.js +18 -22
- package/dist/runtime/host/bound-session-relay.js +3 -1
- package/dist/runtime/host/channel-runtime-options-factory.js +31 -14
- package/dist/runtime/host/host-capacity-status.js +8 -4
- package/dist/runtime/host/index.js +245 -228
- package/dist/runtime/host/instance-activation-authority.js +93 -96
- package/dist/runtime/host/location-runtime-owner.js +16 -14
- package/dist/runtime/host/mesh-router-resolver.js +11 -13
- package/dist/runtime/host/relocation-direct-transfer.js +10 -9
- package/dist/runtime/host/remote-actor-join-receiver.js +20 -15
- package/dist/runtime/host/remote-actor-packet-target-store.js +18 -22
- package/dist/runtime/host/remote-bound-session-relay.js +97 -73
- package/dist/runtime/host/route-mesh-runtime.js +64 -69
- package/dist/runtime/host/runtime-shutdown.js +1 -2
- package/dist/runtime/host/service-relocation-host-runtime.js +586 -511
- package/dist/runtime/host/spot-address-transport.js +69 -71
- package/dist/runtime/host/spot-runtime-options-factory.js +30 -29
- package/dist/runtime/host/stateful-authority-route-runtime.js +65 -68
- package/dist/runtime/host/user-spot-creation-coordinator.js +61 -67
- package/dist/runtime/locations/actor-location-claims.js +26 -20
- package/dist/runtime/locations/aggregate-inventory-store.js +72 -75
- package/dist/runtime/locations/authority-key-codec.js +7 -7
- package/dist/runtime/locations/auto-connect-loop.js +3 -3
- package/dist/runtime/locations/auto-connect-planner.js +25 -19
- package/dist/runtime/locations/auto-connect-reconciler.js +51 -31
- package/dist/runtime/locations/in-memory-authority-store.js +128 -118
- package/dist/runtime/locations/in-memory-location-store.js +195 -168
- package/dist/runtime/locations/in-memory-provider-location-store.js +8 -10
- package/dist/runtime/locations/key-codec.js +1 -1
- package/dist/runtime/locations/lease-tracker.js +23 -21
- package/dist/runtime/locations/lifecycle.js +4 -5
- package/dist/runtime/locations/location-store-repository.js +368 -324
- package/dist/runtime/locations/opaque-record-key.js +2 -2
- package/dist/runtime/locations/resolvers.js +73 -82
- package/dist/runtime/locations/runtime.js +68 -63
- package/dist/runtime/locations/spot-location-claims.js +39 -35
- package/dist/runtime/messaging/framework-json-v1.js +7 -7
- package/dist/runtime/messaging/packet-name.js +7 -6
- package/dist/runtime/messaging/payload-codec.js +21 -18
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +30 -2
- package/dist/runtime/protocol/service_wire_codec.generated.js +1671 -234
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +20 -18
- package/dist/runtime/routing-id.js +3 -5
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +35 -31
- package/dist/runtime/spots/formal-remote-actor-transfer-registry.js +1 -2
- package/dist/runtime/spots/index.js +209 -220
- package/dist/runtime/spots/spot-activation-registry.js +15 -14
- package/dist/runtime/spots/spot-activation-state.js +17 -15
- package/dist/runtime/spots/spot-activation.js +33 -16
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +18 -15
- package/dist/runtime/spots/spot-actor-membership.js +1 -3
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +29 -21
- package/dist/runtime/spots/spot-actor-packet-drain.js +14 -10
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +10 -6
- package/dist/runtime/spots/spot-closing.js +3 -7
- package/dist/runtime/spots/spot-context.js +2 -2
- package/dist/runtime/spots/spot-entry-activation.js +13 -14
- package/dist/runtime/spots/spot-handle.js +6 -3
- package/dist/runtime/spots/spot-handler-registry.js +12 -12
- package/dist/runtime/spots/spot-manager-public.js +5 -6
- package/dist/runtime/spots/spot-native-actor-join-admission.js +4 -3
- package/dist/runtime/spots/spot-node-autoconnect.js +15 -18
- package/dist/runtime/spots/spot-node-runtime-manager.js +79 -86
- package/dist/runtime/spots/spot-outbound.js +10 -14
- package/dist/runtime/spots/spot-remote-codec.js +22 -26
- package/dist/runtime/spots/spot-remote-route-codec.js +5 -7
- package/dist/runtime/spots/spot-route-packet-dispatch.js +17 -15
- package/dist/runtime/spots/spot-route-replies.js +4 -6
- package/dist/runtime/spots/spot-routed-actor-admission.js +9 -7
- package/dist/runtime/spots/spot-routed-bound-session-dispatch.js +2 -3
- package/dist/runtime/spots/spot-routed-frame-dispatch.js +5 -5
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +14 -10
- package/dist/runtime/spots/spot-serial-executor.js +5 -8
- package/dist/runtime/spots/spot-serial-turn-executor.js +4 -6
- package/dist/runtime/spots/spot-subscription-dispatch.js +6 -6
- package/dist/runtime/spots/spot-timer.js +26 -30
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +21 -8
- package/dist/runtime/streams/actor-session-binding-registry.js +168 -148
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +1 -0
- package/dist/runtime/streams/actor-session-lifecycle-coordinator.js +3 -1
- package/dist/runtime/streams/bound-actor-relay-sender.js +20 -17
- package/dist/runtime/streams/bound-session-response-target.js +8 -1
- package/dist/runtime/streams/bound-session-service.d.ts +1 -0
- package/dist/runtime/streams/bound-session-service.js +14 -12
- package/dist/runtime/streams/index.js +28 -20
- package/dist/runtime/streams/managed-stream.d.ts +3 -0
- package/dist/runtime/streams/managed-stream.js +52 -31
- package/dist/runtime/streams/native-fallback-bound-session.js +21 -17
- package/dist/runtime/streams/protocol.d.ts +5 -1
- package/dist/runtime/streams/protocol.js +68 -20
- package/dist/runtime/streams/session-actor-coordinator.js +37 -41
- package/dist/runtime/streams/session-context.d.ts +9 -2
- package/dist/runtime/streams/session-context.js +50 -32
- package/dist/runtime/streams/session-local-actors.d.ts +3 -1
- package/dist/runtime/streams/session-local-actors.js +17 -2
- package/dist/runtime/streams/session-provider.js +2 -2
- package/dist/runtime/streams/session-serial-executor.js +1 -2
- package/dist/runtime/streams/stream-frame-factory.d.ts +1 -1
- package/dist/runtime/streams/stream-frame-factory.js +14 -7
- package/dist/runtime/streams/stream-session-runtime.js +112 -78
- package/dist/runtime/workers/index.js +15 -4
- package/package.json +3 -3
- package/src/contracts/Channels/RouteCalls.ts +6 -1
- package/src/contracts/Common/ZLinkMessage.ts +5 -5
- package/src/contracts/Common/ZLinkMessageMetadata.ts +4 -3
- package/src/contracts/Configuration/Builders.ts +14 -14
- package/src/contracts/Configuration/CodecContentType.ts +8 -10
- package/src/contracts/Configuration/DiagnosticsValidation.ts +1 -6
- package/src/contracts/Configuration/EndpointNotation.ts +11 -11
- package/src/contracts/Configuration/ObjectRoles.ts +1 -3
- package/src/contracts/Configuration/Registration.ts +46 -17
- package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +10 -8
- package/src/contracts/Configuration/RegistrationBuilders.ts +107 -96
- package/src/contracts/Configuration/RegistrationCodecRegistry.ts +9 -3
- package/src/contracts/Configuration/RegistrationNormalizers.ts +116 -84
- package/src/contracts/Configuration/RegistrationTypes.ts +21 -25
- package/src/contracts/Configuration/RegistrationValidators.ts +122 -73
- package/src/contracts/Configuration/RouteChannelInternalState.ts +1 -4
- package/src/contracts/Configuration/RuntimeEndpointConnections.ts +4 -1
- package/src/contracts/Configuration/SendTimeoutValidation.ts +6 -4
- package/src/contracts/Configuration/TimerRegistrationValidator.ts +8 -13
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -6
- package/src/contracts/Errors/index.ts +1 -4
- package/src/contracts/Handlers/Attributes.ts +15 -9
- package/src/contracts/Handlers/IZLinkChannelHandlers.ts +24 -4
- package/src/contracts/Handlers/JsonContract.ts +53 -19
- package/src/contracts/Locations/ActorTransfer.ts +1 -5
- package/src/contracts/Locations/Authority.ts +4 -11
- package/src/contracts/Locations/Keys.ts +6 -1
- package/src/contracts/Locations/Options.ts +3 -2
- package/src/contracts/Locations/RelocationStore.ts +1 -4
- package/src/contracts/Locations/Resolvers.ts +5 -5
- package/src/contracts/Locations/RuntimeQuery.ts +6 -2
- package/src/contracts/Locations/Stores.ts +1 -2
- package/src/contracts/Locations/index.ts +2 -8
- package/src/contracts/RouteMesh/Contracts.ts +1 -7
- package/src/contracts/RouteMesh/RuntimeTopology.ts +1 -4
- package/src/contracts/Spots/Contracts.ts +2 -8
- package/src/contracts/Spots/SpotKind.ts +16 -8
- package/src/contracts/Spots/ZLinkSpot.ts +8 -11
- package/src/contracts/Streams/IZLinkSession.ts +2 -2
- package/src/contracts/Streams/IZLinkSessionActor.ts +5 -1
- package/src/contracts/Streams/IZLinkSessionPacketHandler.ts +5 -1
- package/src/internal.ts +5 -4
- package/src/location-store-integration.ts +24 -16
- package/src/nest-integration.ts +40 -25
- package/src/runtime/abort.ts +10 -4
- package/src/runtime/actors/actor-authority-payload-codec.ts +20 -29
- package/src/runtime/actors/actor-authority-publication.ts +92 -77
- package/src/runtime/actors/actor-client.ts +162 -133
- package/src/runtime/actors/actor-context.ts +142 -134
- package/src/runtime/actors/actor-creation.ts +47 -44
- package/src/runtime/actors/actor-execution-context.ts +6 -4
- package/src/runtime/actors/actor-handoff.ts +269 -293
- package/src/runtime/actors/actor-join-deferred-scope.ts +1 -32
- package/src/runtime/actors/actor-lifecycle-snapshot.ts +5 -8
- package/src/runtime/actors/actor-local-native-join.ts +131 -159
- package/src/runtime/actors/actor-mailbox.ts +16 -19
- package/src/runtime/actors/actor-message-follow-context.ts +46 -36
- package/src/runtime/actors/actor-packet-relay-wire.ts +32 -21
- package/src/runtime/actors/actor-remote-joiner.ts +50 -54
- package/src/runtime/actors/actor-remote-wire.ts +9 -13
- package/src/runtime/actors/actor-routed-join-transport.ts +10 -2
- package/src/runtime/actors/actor-runtime-contracts.ts +2 -5
- package/src/runtime/actors/actor-runtime-state.ts +127 -124
- package/src/runtime/actors/actor-transfer-registry.ts +9 -14
- package/src/runtime/actors/actor-transport-delivery-gate.ts +4 -6
- package/src/runtime/actors/bound-session-wire.ts +37 -17
- package/src/runtime/actors/deferred-join-accepted-journal.ts +353 -326
- package/src/runtime/actors/index.ts +43 -86
- package/src/runtime/actors/post-commit-actor-binder.ts +10 -10
- package/src/runtime/actors/post-commit-actor-location.ts +30 -23
- package/src/runtime/actors/spot-actor-dispatch.ts +78 -53
- package/src/runtime/actors/transferred-actor-rollback.ts +18 -13
- package/src/runtime/admission.ts +9 -9
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +5 -15
- package/src/runtime/application-jobs/application-job-queue-handler-start-gate.ts +3 -2
- package/src/runtime/application-jobs/receive-flow-controller.ts +17 -14
- package/src/runtime/backend/contracts/index.ts +77 -52
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +4 -14
- package/src/runtime/backend/mesh-completion-table.ts +6 -9
- package/src/runtime/backend/mesh-dispatch-pump.ts +38 -30
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +23 -21
- package/src/runtime/backend/node/node-backend-adapter-support.ts +36 -22
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +59 -58
- package/src/runtime/backend/node/node-event-loop-poller.ts +2 -10
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +12 -5
- package/src/runtime/backend/node/node-monitor-backend-adapter.ts +4 -3
- package/src/runtime/backend/node/node-raw-binding-port.ts +29 -29
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +370 -390
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +101 -54
- package/src/runtime/backend/runtime-message.ts +5 -3
- package/src/runtime/backend/runtime-values.ts +10 -7
- package/src/runtime/channels/channel-autoconnect.ts +1 -4
- package/src/runtime/channels/channel-clients.ts +93 -73
- package/src/runtime/channels/channel-dispatch-pipeline.ts +44 -44
- package/src/runtime/channels/channel-dispatch-services.ts +51 -49
- package/src/runtime/channels/channel-dispatchers.ts +152 -96
- package/src/runtime/channels/channel-envelope-inspection.ts +20 -16
- package/src/runtime/channels/channel-envelope.ts +256 -150
- package/src/runtime/channels/channel-multipart.ts +13 -5
- package/src/runtime/channels/channel-outbound-operations.ts +37 -41
- package/src/runtime/channels/channel-receive-loops.ts +102 -98
- package/src/runtime/channels/channel-receive-task-tracker.ts +1 -1
- package/src/runtime/channels/channel-runtime-lifecycle.ts +248 -190
- package/src/runtime/channels/channel-runtime-manager.ts +63 -37
- package/src/runtime/channels/channel-socket-options.ts +3 -10
- package/src/runtime/channels/channel-socket-registry.ts +331 -273
- package/src/runtime/channels/channel-transports.ts +218 -206
- package/src/runtime/channels/client-server-location-runtime.ts +116 -100
- package/src/runtime/channels/client-server-service-wire.ts +37 -36
- package/src/runtime/channels/dispatch-error-reporter.ts +12 -47
- package/src/runtime/channels/fanout-location-runtime.ts +91 -94
- package/src/runtime/channels/fanout-service-wire.ts +5 -12
- package/src/runtime/channels/handler-filter-scope.ts +1 -4
- package/src/runtime/channels/index.ts +1 -4
- package/src/runtime/channels/local-spot-route-transport.ts +20 -5
- package/src/runtime/channels/route-member-snapshot.ts +11 -5
- package/src/runtime/channels/router-socket-spot-route-transport.ts +1 -7
- package/src/runtime/channels/source-spot-router.ts +26 -22
- package/src/runtime/channels/spot-direct-envelope.ts +10 -8
- package/src/runtime/channels/spot-node-route-transport.ts +13 -16
- package/src/runtime/channels/spot-route-bridge-transport.ts +26 -9
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +40 -13
- package/src/runtime/channels/spot-route-target-resolver.ts +18 -9
- package/src/runtime/codecs/index.ts +3 -2
- package/src/runtime/diagnostics/dispatch-error-details.ts +62 -0
- package/src/runtime/diagnostics/flow-context.ts +18 -7
- package/src/runtime/diagnostics/index.ts +96 -61
- package/src/runtime/diagnostics/internal-event-contracts.ts +87 -33
- package/src/runtime/diagnostics/message-flow.ts +107 -79
- package/src/runtime/diagnostics/runtime-metrics.ts +46 -24
- package/src/runtime/diagnostics/runtime-observation-queue.ts +17 -28
- package/src/runtime/diagnostics/topology-runtime-projections.ts +62 -43
- package/src/runtime/execution/index.ts +18 -26
- package/src/runtime/execution/serial-execution-queue.ts +31 -40
- package/src/runtime/execution/state-lane.ts +2 -2
- package/src/runtime/foundation/actor-join-recovery-codec.ts +69 -55
- package/src/runtime/foundation/event-loop-resources.ts +8 -4
- package/src/runtime/foundation/message-follow-suppression-registry.ts +7 -14
- package/src/runtime/foundation/operation-identity.ts +1 -2
- package/src/runtime/foundation/operation-registry.ts +8 -2
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +364 -396
- package/src/runtime/foundation/route-mesh-connection-policy.ts +7 -8
- package/src/runtime/foundation/runtime-state-projections.ts +24 -23
- package/src/runtime/foundation/service-authority-payload-codec.ts +54 -57
- package/src/runtime/foundation/service-discovery-registry.ts +67 -59
- package/src/runtime/foundation/service-instance-activation-recovery-codec.ts +28 -29
- package/src/runtime/foundation/service-liveness-registry.ts +18 -13
- package/src/runtime/foundation/service-mailbox.ts +14 -14
- package/src/runtime/foundation/service-maintenance-runtime.ts +22 -21
- package/src/runtime/foundation/service-metadata-codec.ts +2 -9
- package/src/runtime/foundation/service-relocation-aggregate-committer.ts +39 -36
- package/src/runtime/foundation/service-relocation-coordinator.ts +1 -4
- package/src/runtime/foundation/service-relocation-object-owner.ts +40 -58
- package/src/runtime/foundation/service-relocation-runtime.ts +292 -216
- package/src/runtime/foundation/service-runtime-contracts.ts +8 -8
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -4
- package/src/runtime/foundation/service-stateful-registry.ts +69 -59
- package/src/runtime/foundation/service-stateful-runtime.ts +1233 -1112
- package/src/runtime/foundation/service-stateful-wire-codec.ts +318 -270
- package/src/runtime/foundation/service-topology-registry.ts +170 -159
- package/src/runtime/foundation/service-weighted-selection.ts +9 -15
- package/src/runtime/foundation/service-wire-binary-primitives.ts +6 -12
- package/src/runtime/foundation/service-wire-m6a-codec.ts +69 -47
- package/src/runtime/framework-errors-internal.ts +31 -30
- package/src/runtime/handlers/handler-instance-scope.ts +18 -29
- package/src/runtime/handlers/index.ts +18 -8
- package/src/runtime/host/actor-packet-relay.ts +290 -261
- package/src/runtime/host/actor-placement-coordinator.ts +165 -150
- package/src/runtime/host/actor-runtime-options-factory.ts +89 -87
- package/src/runtime/host/actor-transfer-authority-runtime.ts +46 -38
- package/src/runtime/host/actor-transfer-runtime.ts +391 -395
- package/src/runtime/host/application-job-queue.ts +32 -48
- package/src/runtime/host/bound-session-relay.ts +7 -9
- package/src/runtime/host/channel-runtime-options-factory.ts +75 -35
- package/src/runtime/host/host-capacity-status.ts +10 -9
- package/src/runtime/host/index.ts +861 -789
- package/src/runtime/host/instance-activation-authority.ts +125 -143
- package/src/runtime/host/location-runtime-owner.ts +38 -26
- package/src/runtime/host/mesh-router-resolver.ts +30 -23
- package/src/runtime/host/relocation-direct-transfer.ts +15 -15
- package/src/runtime/host/relocation-integrity-fault-gate.ts +3 -2
- package/src/runtime/host/remote-actor-join-receiver.ts +43 -34
- package/src/runtime/host/remote-actor-packet-target-store.ts +54 -52
- package/src/runtime/host/remote-bound-session-relay.ts +274 -247
- package/src/runtime/host/route-mesh-runtime-options.ts +1 -3
- package/src/runtime/host/route-mesh-runtime.ts +227 -181
- package/src/runtime/host/runtime-shutdown.ts +4 -3
- package/src/runtime/host/service-relocation-control.ts +14 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +1388 -1165
- package/src/runtime/host/spot-address-transport.ts +284 -237
- package/src/runtime/host/spot-node-runtime-options-factory.ts +14 -8
- package/src/runtime/host/spot-runtime-options-factory.ts +71 -62
- package/src/runtime/host/stateful-authority-route-runtime.ts +117 -116
- package/src/runtime/host/user-spot-creation-coordinator.ts +225 -220
- package/src/runtime/locations/actor-location-claims.ts +61 -49
- package/src/runtime/locations/actor-session-route-claims.ts +1 -4
- package/src/runtime/locations/aggregate-inventory-store.ts +105 -134
- package/src/runtime/locations/authority-key-codec.ts +13 -10
- package/src/runtime/locations/auto-connect-loop.ts +14 -11
- package/src/runtime/locations/auto-connect-planner.ts +42 -31
- package/src/runtime/locations/auto-connect-reconciler.ts +106 -63
- package/src/runtime/locations/canonical-codec.ts +3 -1
- package/src/runtime/locations/creation-operation-id.ts +4 -3
- package/src/runtime/locations/domain-store-contract.ts +13 -7
- package/src/runtime/locations/in-memory-authority-store.ts +232 -199
- package/src/runtime/locations/in-memory-location-store.ts +432 -250
- package/src/runtime/locations/in-memory-provider-location-store.ts +16 -17
- package/src/runtime/locations/internal-store-contracts.ts +95 -38
- package/src/runtime/locations/key-codec.ts +3 -4
- package/src/runtime/locations/lease-tracker.ts +36 -27
- package/src/runtime/locations/lifecycle-runtime.ts +15 -3
- package/src/runtime/locations/lifecycle.ts +33 -28
- package/src/runtime/locations/location-store-repository.ts +1329 -1185
- package/src/runtime/locations/opaque-record-key.ts +4 -9
- package/src/runtime/locations/resolvers.ts +201 -178
- package/src/runtime/locations/runtime.ts +251 -159
- package/src/runtime/locations/spot-location-claims.ts +110 -112
- package/src/runtime/messaging/creation-payload-codec.ts +4 -1
- package/src/runtime/messaging/framework-json-v1.ts +34 -15
- package/src/runtime/messaging/packet-name.ts +8 -6
- package/src/runtime/messaging/payload-codec.ts +70 -50
- package/src/runtime/messaging/submission-result.ts +6 -9
- package/src/runtime/protocol/service_wire_codec.generated.ts +1376 -159
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +19 -18
- package/src/runtime/routing-id.ts +10 -7
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +56 -62
- package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +23 -20
- package/src/runtime/spots/index.ts +595 -564
- package/src/runtime/spots/spot-activation-registry.ts +38 -34
- package/src/runtime/spots/spot-activation-state.ts +43 -51
- package/src/runtime/spots/spot-activation.ts +179 -116
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +110 -78
- package/src/runtime/spots/spot-actor-join-dispatch.ts +57 -41
- package/src/runtime/spots/spot-actor-lifecycle-drain.ts +5 -7
- package/src/runtime/spots/spot-actor-membership.ts +25 -27
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +196 -148
- package/src/runtime/spots/spot-actor-packet-drain.ts +56 -42
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +37 -39
- package/src/runtime/spots/spot-closing.ts +11 -12
- package/src/runtime/spots/spot-context.ts +46 -26
- package/src/runtime/spots/spot-entry-activation.ts +84 -65
- package/src/runtime/spots/spot-handle.ts +17 -15
- package/src/runtime/spots/spot-handler-registry.ts +44 -31
- package/src/runtime/spots/spot-location-claim.ts +5 -4
- package/src/runtime/spots/spot-manager-public.ts +62 -82
- package/src/runtime/spots/spot-native-actor-join-admission.ts +20 -16
- package/src/runtime/spots/spot-node-autoconnect.ts +54 -61
- package/src/runtime/spots/spot-node-runtime-manager.ts +235 -222
- package/src/runtime/spots/spot-outbound.ts +47 -59
- package/src/runtime/spots/spot-publisher-transport.ts +5 -4
- package/src/runtime/spots/spot-remote-codec.ts +66 -65
- package/src/runtime/spots/spot-remote-route-codec.ts +61 -41
- package/src/runtime/spots/spot-route-packet-dispatch.ts +129 -95
- package/src/runtime/spots/spot-route-replies.ts +23 -24
- package/src/runtime/spots/spot-route-reply-wire.ts +3 -2
- package/src/runtime/spots/spot-routed-actor-admission.ts +37 -27
- package/src/runtime/spots/spot-routed-bound-session-dispatch.ts +13 -18
- package/src/runtime/spots/spot-routed-frame-dispatch.ts +18 -15
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +35 -26
- package/src/runtime/spots/spot-routing-internal.ts +1 -4
- package/src/runtime/spots/spot-runtime-ports.ts +5 -5
- package/src/runtime/spots/spot-serial-executor.ts +5 -9
- package/src/runtime/spots/spot-serial-turn-executor.ts +19 -26
- package/src/runtime/spots/spot-subscription-dispatch.ts +58 -47
- package/src/runtime/spots/spot-timer.ts +103 -91
- package/src/runtime/streams/actor-session-binding-registry.ts +421 -292
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +8 -4
- package/src/runtime/streams/actor-session-lifecycle-coordinator.ts +3 -1
- package/src/runtime/streams/bound-actor-relay-sender.ts +60 -50
- package/src/runtime/streams/bound-session-response-target.ts +39 -9
- package/src/runtime/streams/bound-session-service.ts +52 -42
- package/src/runtime/streams/index.ts +183 -100
- package/src/runtime/streams/managed-stream.ts +123 -90
- package/src/runtime/streams/native-fallback-bound-session.ts +57 -52
- package/src/runtime/streams/protocol.ts +115 -46
- package/src/runtime/streams/session-actor-coordinator.ts +109 -93
- package/src/runtime/streams/session-calls.ts +2 -8
- package/src/runtime/streams/session-context.ts +96 -51
- package/src/runtime/streams/session-local-actors.ts +19 -3
- package/src/runtime/streams/session-provider.ts +5 -7
- package/src/runtime/streams/session-serial-executor.ts +7 -6
- package/src/runtime/streams/stream-binding-runtime-ports.ts +79 -29
- package/src/runtime/streams/stream-frame-factory.ts +59 -40
- package/src/runtime/streams/stream-session-runtime.ts +317 -214
- package/src/runtime/workers/index.ts +68 -29
|
@@ -99,12 +99,12 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
99
99
|
throw new Error(`Actor '${input.state.actorId}' has no source authority identity.`);
|
|
100
100
|
}
|
|
101
101
|
const descriptors = await this.options.liveDescriptors(input.meshName, input.signal);
|
|
102
|
-
const target = descriptors.find(value => (0, routing_id_1.routingIdsEqual)(value.rid, input.target.targetNodeRid));
|
|
102
|
+
const target = descriptors.find((value) => (0, routing_id_1.routingIdsEqual)(value.rid, input.target.targetNodeRid));
|
|
103
103
|
if (target === undefined) {
|
|
104
104
|
throw new Error(`Actor '${input.state.actorId}' Join target '${String(input.target.targetNodeRid)}' is not live.`);
|
|
105
105
|
}
|
|
106
|
-
if (input.target.targetNodeGeneration !== undefined
|
|
107
|
-
|
|
106
|
+
if (input.target.targetNodeGeneration !== undefined &&
|
|
107
|
+
target.lifecycleGeneration !== input.target.targetNodeGeneration) {
|
|
108
108
|
throw new Error(`Actor '${input.state.actorId}' Join target generation changed after admission.`);
|
|
109
109
|
}
|
|
110
110
|
this.reserveExactRelocationId(input.relocationId);
|
|
@@ -119,7 +119,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
119
119
|
sourceSpotId: input.state.spotId,
|
|
120
120
|
targetSpotId: input.target.spotId,
|
|
121
121
|
targetNodeRid: input.target.targetNodeRid,
|
|
122
|
-
relocationContentType: this.actorRegistration(input.state.meshName ?? input.meshName, input.state.actorType ?? '')
|
|
122
|
+
relocationContentType: this.actorRegistration(input.state.meshName ?? input.meshName, input.state.actorType ?? '')
|
|
123
|
+
.relocation.kind === 'snapshot'
|
|
123
124
|
? 'application/vnd.zlink.actor-relocation.snapshot'
|
|
124
125
|
: 'application/vnd.zlink.actor-relocation.recreate',
|
|
125
126
|
completionOperationId: input.completionOperationId,
|
|
@@ -127,9 +128,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
127
128
|
ready,
|
|
128
129
|
resolveReady
|
|
129
130
|
});
|
|
130
|
-
const membershipEpoch = input.state.spotMembershipEpoch > 0n
|
|
131
|
-
? input.state.spotMembershipEpoch
|
|
132
|
-
: 1n;
|
|
131
|
+
const membershipEpoch = input.state.spotMembershipEpoch > 0n ? input.state.spotMembershipEpoch : 1n;
|
|
133
132
|
const spotGeneration = input.target.targetSpotGeneration ?? target.lifecycleGeneration;
|
|
134
133
|
try {
|
|
135
134
|
await this.relocateStandaloneActor(input.meshName, input.state, target, target.applicationVersion, input.signal, {
|
|
@@ -224,10 +223,14 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
224
223
|
continue;
|
|
225
224
|
this.sourceActorJoinProfiles.delete(relocationId);
|
|
226
225
|
this.terminalActorJoinSourceLeaves.remember(relocationId, actorId);
|
|
227
|
-
void profile.ready
|
|
226
|
+
void profile.ready
|
|
227
|
+
.then(async () => {
|
|
228
228
|
await this.options.actorTransfer.completeRelocationSourceLeave(profile.actor, profile.sourceSpotId);
|
|
229
|
-
await this.options
|
|
230
|
-
|
|
229
|
+
await this.options
|
|
230
|
+
.actorManager()
|
|
231
|
+
?.completeRelocationSource(actorId, profile.sourceActorRef);
|
|
232
|
+
})
|
|
233
|
+
.catch((error) => {
|
|
231
234
|
console.error('[zlink.runtime.relocation.source_cleanup_failed]', error);
|
|
232
235
|
});
|
|
233
236
|
}
|
|
@@ -246,11 +249,13 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
246
249
|
const kind = this.spotKind(meshName, activation);
|
|
247
250
|
if (kind === undefined)
|
|
248
251
|
continue;
|
|
249
|
-
const states = actorManager
|
|
252
|
+
const states = actorManager
|
|
253
|
+
.snapshotStates()
|
|
254
|
+
.filter((state) => state.actor !== undefined && String(state.spotId) === String(activation.spotId));
|
|
250
255
|
for (const state of states)
|
|
251
256
|
groupedActorIds.add(state.actorId);
|
|
252
|
-
if (kind === 'user_spot'
|
|
253
|
-
|
|
257
|
+
if (kind === 'user_spot' &&
|
|
258
|
+
activation.executionMode === contracts_1.ZLinkUserSpotExecutionMode.PerActor) {
|
|
254
259
|
let shellRelocation;
|
|
255
260
|
const relocateShell = (relocationSignal) => {
|
|
256
261
|
shellRelocation ??= this.relocatePerActorSpotShell(meshName, activation, undefined, targetApplicationVersion, relocationSignal);
|
|
@@ -277,7 +282,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
277
282
|
}
|
|
278
283
|
work.push({
|
|
279
284
|
id: `spot:${String(activation.spotId)}`,
|
|
280
|
-
relocate: relocationSignal => this.relocateSpotAggregate(meshName, activation, kind, states, undefined, targetApplicationVersion, relocationSignal)
|
|
285
|
+
relocate: (relocationSignal) => this.relocateSpotAggregate(meshName, activation, kind, states, undefined, targetApplicationVersion, relocationSignal)
|
|
281
286
|
});
|
|
282
287
|
}
|
|
283
288
|
for (const state of actorManager.snapshotStates()) {
|
|
@@ -287,7 +292,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
287
292
|
continue;
|
|
288
293
|
work.push({
|
|
289
294
|
id: `actor:${state.actorId}`,
|
|
290
|
-
relocate: relocationSignal => this.relocateStandaloneActor(meshName, state, undefined, targetApplicationVersion, relocationSignal)
|
|
295
|
+
relocate: (relocationSignal) => this.relocateStandaloneActor(meshName, state, undefined, targetApplicationVersion, relocationSignal)
|
|
291
296
|
});
|
|
292
297
|
}
|
|
293
298
|
if (work.length === 0)
|
|
@@ -316,12 +321,12 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
316
321
|
return false;
|
|
317
322
|
const payload = record.parts[0].data();
|
|
318
323
|
if (isServiceWireCommand(payload, service_stateful_wire_codec_1.M6bServiceWireCommand.replyRelay)) {
|
|
319
|
-
await this.handleReplyRelay(meshName, (0, service_stateful_wire_codec_1.decodeMaintenanceReplyRelay)(record.parts.map(part => part.data())), record.sourceNodeRid, signal);
|
|
324
|
+
await this.handleReplyRelay(meshName, (0, service_stateful_wire_codec_1.decodeMaintenanceReplyRelay)(record.parts.map((part) => part.data())), record.sourceNodeRid, signal);
|
|
320
325
|
return true;
|
|
321
326
|
}
|
|
322
327
|
const sideband = record.parts.length === 1
|
|
323
328
|
? undefined
|
|
324
|
-
: decodePrepareSideband(record.parts.slice(1).map(part => part.data()));
|
|
329
|
+
: decodePrepareSideband(record.parts.slice(1).map((part) => part.data()));
|
|
325
330
|
if (record.parts.length > 1 && sideband === undefined)
|
|
326
331
|
return false;
|
|
327
332
|
if (record.kind === service_runtime_contracts_1.ReceiveKind.NodeSend) {
|
|
@@ -411,11 +416,13 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
411
416
|
const promise = this.handlePrepareControl(meshName, operationKey, request, record.sourceNodeRid, signal);
|
|
412
417
|
operation = { fingerprint, promise };
|
|
413
418
|
this.targetPrepareOperations.set(operationKey, operation);
|
|
414
|
-
void promise
|
|
419
|
+
void promise
|
|
420
|
+
.finally(() => {
|
|
415
421
|
if (this.targetPrepareOperations.get(operationKey) === operation) {
|
|
416
422
|
this.targetPrepareOperations.delete(operationKey);
|
|
417
423
|
}
|
|
418
|
-
})
|
|
424
|
+
})
|
|
425
|
+
.catch(() => undefined);
|
|
419
426
|
}
|
|
420
427
|
void this.deliverTargetReady(meshName, operationKey, request, record, operation.promise);
|
|
421
428
|
return true;
|
|
@@ -480,7 +487,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
480
487
|
if (stage === undefined)
|
|
481
488
|
return;
|
|
482
489
|
this.targetStages.delete(operationKey);
|
|
483
|
-
void this.abortTargetStage(stage).catch(error => {
|
|
490
|
+
void this.abortTargetStage(stage).catch((error) => {
|
|
484
491
|
console.error('[zlink.runtime.relocation.ready_expired_abort_failed]', operationKey, error);
|
|
485
492
|
});
|
|
486
493
|
}
|
|
@@ -510,12 +517,12 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
510
517
|
acceptRelocationStateChunk(request, sourceNodeRid) {
|
|
511
518
|
const operationKey = relocationStagingId(request);
|
|
512
519
|
const pending = this.targetAssemblies.get(operationKey);
|
|
513
|
-
if (pending === undefined
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
520
|
+
if (pending === undefined ||
|
|
521
|
+
sourceNodeRid === null ||
|
|
522
|
+
String(sourceNodeRid) !== pending.authenticatedSourceNodeRid ||
|
|
523
|
+
request.senderRole !== 'source' ||
|
|
524
|
+
!sameCoordinator(request.coordinator, pending.prepare.coordinator) ||
|
|
525
|
+
stringifyWire(request.object) !== stringifyWire(pending.prepare.object)) {
|
|
519
526
|
// Spec 28 §4.3 — a chunk with a different exact identity is never
|
|
520
527
|
// attached to an in-progress assembly; it is discarded.
|
|
521
528
|
console.warn('[zlink.runtime.relocation.stale_state_chunk]', operationKey);
|
|
@@ -598,16 +605,16 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
598
605
|
const expectedTarget = String(targetNodeRid);
|
|
599
606
|
const terminal = this.terminalSessionRelocations.get(key);
|
|
600
607
|
if (terminal !== undefined) {
|
|
601
|
-
if (terminal.targetNodeRid !== expectedTarget
|
|
602
|
-
|
|
608
|
+
if (terminal.targetNodeRid !== expectedTarget ||
|
|
609
|
+
terminal.requestFingerprint !== requestFingerprint) {
|
|
603
610
|
return Promise.reject(new service_wire_m6a_codec_1.ServiceWireProtocolError(`Session relocation control '${key}' repeated with different bytes or target.`));
|
|
604
611
|
}
|
|
605
612
|
this.terminalSessionRelocations.touch(key);
|
|
606
613
|
}
|
|
607
614
|
const existing = this.pendingSessionRelocations.get(key);
|
|
608
615
|
if (existing !== undefined) {
|
|
609
|
-
if (existing.targetNodeRid !== expectedTarget
|
|
610
|
-
|
|
616
|
+
if (existing.targetNodeRid !== expectedTarget ||
|
|
617
|
+
existing.requestFingerprint !== requestFingerprint) {
|
|
611
618
|
return Promise.reject(new service_wire_m6a_codec_1.ServiceWireProtocolError(`Session relocation control '${key}' repeated with different bytes or target.`));
|
|
612
619
|
}
|
|
613
620
|
return existing.promise;
|
|
@@ -649,9 +656,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
649
656
|
const registration = Object.hasOwn(this.options, 'registration')
|
|
650
657
|
? this.options.registration
|
|
651
658
|
: undefined;
|
|
652
|
-
const sealTimeoutMs = registration?.locations.options
|
|
653
|
-
.sessionRelocationSealTimeoutMs
|
|
654
|
-
?? Options_1.zlinkRuntimeDefaultLocationOptions.sessionRelocationSealTimeoutMs;
|
|
659
|
+
const sealTimeoutMs = registration?.locations.options.sessionRelocationSealTimeoutMs ??
|
|
660
|
+
Options_1.zlinkRuntimeDefaultLocationOptions.sessionRelocationSealTimeoutMs;
|
|
655
661
|
const resendDeadline = performance.now() + sealTimeoutMs;
|
|
656
662
|
const send = async () => {
|
|
657
663
|
if (signal?.aborted === true) {
|
|
@@ -695,7 +701,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
695
701
|
request,
|
|
696
702
|
requestFingerprint,
|
|
697
703
|
promise,
|
|
698
|
-
resolve: response => finish(() => {
|
|
704
|
+
resolve: (response) => finish(() => {
|
|
699
705
|
this.terminalSessionRelocations.remember(key, {
|
|
700
706
|
targetNodeRid: expectedTarget,
|
|
701
707
|
request,
|
|
@@ -704,12 +710,13 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
704
710
|
});
|
|
705
711
|
resolvePromise(response);
|
|
706
712
|
}),
|
|
707
|
-
reject: error => finish(() => rejectPromise(error))
|
|
713
|
+
reject: (error) => finish(() => rejectPromise(error))
|
|
708
714
|
};
|
|
709
715
|
this.pendingSessionRelocations.set(key, pending);
|
|
710
716
|
pending.deadlineTimer = setTimeout(() => pending.reject((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.DeadlineExceeded, `Session relocation seal '${key}' was not acknowledged within the relocation seal timeout.`, true)), Math.max(0, resendDeadline - performance.now()));
|
|
711
717
|
pending.deadlineTimer.unref();
|
|
712
|
-
abortListener = () => pending.reject(signal?.reason ??
|
|
718
|
+
abortListener = () => pending.reject(signal?.reason ??
|
|
719
|
+
(0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.DeadlineExceeded, `Session relocation seal '${key}' was cancelled.`, true));
|
|
713
720
|
if (signal?.aborted === true) {
|
|
714
721
|
abortListener();
|
|
715
722
|
return promise;
|
|
@@ -758,19 +765,21 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
758
765
|
if (String(status.routingId) === String(sourceNodeRid)) {
|
|
759
766
|
return status.lifecycleGeneration;
|
|
760
767
|
}
|
|
761
|
-
return node
|
|
762
|
-
|
|
768
|
+
return node
|
|
769
|
+
.peers()
|
|
770
|
+
.find((peer) => peer.routingId !== null && String(peer.routingId) === String(sourceNodeRid))
|
|
771
|
+
?.lifecycleGeneration;
|
|
763
772
|
}
|
|
764
773
|
async handleSessionRelocationSeal(meshName, request, sourceNodeRid, signal) {
|
|
765
|
-
if (sourceNodeRid === null
|
|
766
|
-
|
|
767
|
-
|
|
774
|
+
if (sourceNodeRid === null ||
|
|
775
|
+
String(sourceNodeRid) !== request.coordinator.nodeRid ||
|
|
776
|
+
String(sourceNodeRid) !== request.actor.actor.nodeRid) {
|
|
768
777
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Session relocation seal source does not match its coordinator and Actor fence.');
|
|
769
778
|
}
|
|
770
779
|
this.validateSessionOwnerFence(meshName, request.session);
|
|
771
780
|
const sealSourceGeneration = this.sourceLifecycleGeneration(meshName, sourceNodeRid);
|
|
772
|
-
if (sealSourceGeneration !== request.actor.targetNodeGeneration
|
|
773
|
-
|
|
781
|
+
if (sealSourceGeneration !== request.actor.targetNodeGeneration ||
|
|
782
|
+
sealSourceGeneration !== request.coordinator.nodeGeneration) {
|
|
774
783
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Session relocation seal source lifecycle generation is stale.');
|
|
775
784
|
}
|
|
776
785
|
const handler = this.options.boundSessionRelocation?.receiveSeal;
|
|
@@ -781,9 +790,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
781
790
|
}
|
|
782
791
|
async handleSessionRelocationRoute(meshName, request, sourceNodeRid, _signal) {
|
|
783
792
|
this.validateSessionOwnerFence(meshName, request.session);
|
|
784
|
-
const expectedSource = request.route.action === 'commit'
|
|
785
|
-
? request.route.targetNodeRid
|
|
786
|
-
: request.coordinator.nodeRid;
|
|
793
|
+
const expectedSource = request.route.action === 'commit' ? request.route.targetNodeRid : request.coordinator.nodeRid;
|
|
787
794
|
if (sourceNodeRid === null || String(sourceNodeRid) !== expectedSource) {
|
|
788
795
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Session relocation route source does not match its action fence.');
|
|
789
796
|
}
|
|
@@ -803,10 +810,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
803
810
|
validateSessionOwnerFence(meshName, session) {
|
|
804
811
|
const status = this.requireMeshNode(meshName).status();
|
|
805
812
|
const owner = this.options.currentOwner();
|
|
806
|
-
if (String(status.routingId) !== session.sessionOwnerNodeRid
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
813
|
+
if (String(status.routingId) !== session.sessionOwnerNodeRid ||
|
|
814
|
+
status.lifecycleGeneration !== session.sessionOwnerNodeGeneration ||
|
|
815
|
+
owner?.ownerId !== session.sessionOwnerId ||
|
|
816
|
+
owner.leaseGeneration !== session.sessionOwnerLeaseGeneration) {
|
|
810
817
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Session relocation command does not match the local Session owner fence.');
|
|
811
818
|
}
|
|
812
819
|
}
|
|
@@ -841,7 +848,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
841
848
|
policy: spotRegistration.relocation.kind,
|
|
842
849
|
count: 1
|
|
843
850
|
},
|
|
844
|
-
...actorStates.map(state => {
|
|
851
|
+
...actorStates.map((state) => {
|
|
845
852
|
const actorAuthority = actorAuthorities.get(state.actorId);
|
|
846
853
|
return {
|
|
847
854
|
objectKind: 'actor',
|
|
@@ -870,7 +877,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
870
877
|
actor: state.actor,
|
|
871
878
|
prepared: await this.options.actorTransfer.prepareMaintenanceSession(state.actor, state, captureSignal, false, relocationWireId(aggregateId))
|
|
872
879
|
})));
|
|
873
|
-
const preparedSessionsOutcome = preparedSessions.then(value => ({ value }), error => ({ error }));
|
|
880
|
+
const preparedSessionsOutcome = preparedSessions.then((value) => ({ value }), (error) => ({ error }));
|
|
874
881
|
spotCapture = await spotCaptureOperation;
|
|
875
882
|
const preparation = await preparedSessionsOutcome;
|
|
876
883
|
if ('error' in preparation)
|
|
@@ -882,10 +889,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
882
889
|
timers: spotCapture.timers.map(toServiceTimer)
|
|
883
890
|
};
|
|
884
891
|
},
|
|
885
|
-
captureApplicationState: captureSignal => this.captureApplication(spotRegistration.relocation, activation.spot, captureSignal),
|
|
892
|
+
captureApplicationState: (captureSignal) => this.captureApplication(spotRegistration.relocation, activation.spot, captureSignal),
|
|
886
893
|
commitSeal: async () => {
|
|
887
894
|
if (!spotSealCommitted) {
|
|
888
|
-
if (spotCapture === undefined || !await activation.commitRelocation(spotCapture)) {
|
|
895
|
+
if (spotCapture === undefined || !(await activation.commitRelocation(spotCapture))) {
|
|
889
896
|
throw new Error(`Spot '${String(activation.spotId)}' relocation seal became stale.`);
|
|
890
897
|
}
|
|
891
898
|
spotSealCommitted = true;
|
|
@@ -905,9 +912,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
905
912
|
routerChannelId: meshName,
|
|
906
913
|
targetNodeRid: target.rid,
|
|
907
914
|
spotId: activation.spotId,
|
|
908
|
-
spotKind: kind === 'user_spot'
|
|
909
|
-
? contracts_1.ZLinkSpotKind.User
|
|
910
|
-
: contracts_1.ZLinkSpotKind.Instance,
|
|
915
|
+
spotKind: kind === 'user_spot' ? contracts_1.ZLinkSpotKind.User : contracts_1.ZLinkSpotKind.Instance,
|
|
911
916
|
authorityOwnerGeneration: committedAuthority.authorityOwnerGeneration
|
|
912
917
|
}, targetActorRef, (0, actor_transfer_runtime_1.committedActorOwnerFence)(session.state.actorId, targetActorRef, committedAuthority));
|
|
913
918
|
activation.commitActorDeparture(session.state.actorId);
|
|
@@ -950,8 +955,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
950
955
|
}
|
|
951
956
|
}
|
|
952
957
|
};
|
|
953
|
-
const actorUnits = actorStates.map(state => this.actorCaptureUnit(state, actorAuthorities.get(state.actorId), sessions, false, undefined, undefined, undefined, undefined, false));
|
|
954
|
-
const memberships = actorStates.map(state => ({
|
|
958
|
+
const actorUnits = actorStates.map((state) => this.actorCaptureUnit(state, actorAuthorities.get(state.actorId), sessions, false, undefined, undefined, undefined, undefined, false));
|
|
959
|
+
const memberships = actorStates.map((state) => ({
|
|
955
960
|
actorKey: (0, authority_key_codec_1.encodeAuthorityKey)('actor', state.actorId).value,
|
|
956
961
|
spotKey: spotKey.value,
|
|
957
962
|
spotObjectGeneration: spotAuthority.objectGeneration,
|
|
@@ -960,9 +965,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
960
965
|
let outcome = 'completed';
|
|
961
966
|
try {
|
|
962
967
|
const waitForRelocationBoundary = activation.waitForRelocationBoundary;
|
|
963
|
-
readinessBoundaryConsumed =
|
|
964
|
-
|
|
965
|
-
|
|
968
|
+
readinessBoundaryConsumed =
|
|
969
|
+
waitForRelocationBoundary === undefined
|
|
970
|
+
? false
|
|
971
|
+
: await waitForRelocationBoundary.call(activation, signal);
|
|
966
972
|
// A full in-flight payload budget delays this unit before its seal, so
|
|
967
973
|
// the Spot and its Actors keep processing messages while waiting.
|
|
968
974
|
await this.waitForRelocationBudgetHeadroom(String(target.rid), signal);
|
|
@@ -970,16 +976,20 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
970
976
|
const captured = kind === 'user_spot'
|
|
971
977
|
? await captureOwner.captureUserSpotAggregate(aggregateId, 1n, spotUnit, actorUnits, memberships, signal)
|
|
972
978
|
: await captureOwner.captureInstanceSpotAggregate(aggregateId, 1n, spotUnit, actorUnits, memberships, signal);
|
|
973
|
-
await this.runCoordinator(meshName, target, spotAuthority, captured, new Map([
|
|
979
|
+
await this.runCoordinator(meshName, target, spotAuthority, captured, new Map([
|
|
980
|
+
[spotKey.value, spotAuthority],
|
|
981
|
+
...actorStates.map((state) => [
|
|
974
982
|
(0, authority_key_codec_1.encodeAuthorityKey)('actor', state.actorId).value,
|
|
975
983
|
actorAuthorities.get(state.actorId)
|
|
976
|
-
])
|
|
984
|
+
])
|
|
985
|
+
]), signal, sessions);
|
|
977
986
|
}
|
|
978
987
|
catch (error) {
|
|
979
988
|
outcome = 'failed';
|
|
980
|
-
if (readinessBoundaryConsumed
|
|
981
|
-
|
|
982
|
-
|
|
989
|
+
if (readinessBoundaryConsumed && !(error instanceof service_relocation_coordinator_1.ServiceRelocationPostCommitError)) {
|
|
990
|
+
await activation
|
|
991
|
+
.completeConsumedRelocationBoundary(contracts_1.ZLinkSpotRelocationReadyOutcome.Continued)
|
|
992
|
+
.catch(() => undefined);
|
|
983
993
|
}
|
|
984
994
|
throw error;
|
|
985
995
|
}
|
|
@@ -995,15 +1005,16 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
995
1005
|
advertisedReceiveChunkLimitBytes) {
|
|
996
1006
|
relocationDebug('standalone_actor.begin', { actorId: state.actorId });
|
|
997
1007
|
const authority = await requireAuthority(this.requireLocationStore(), (0, authority_key_codec_1.encodeAuthorityKey)('actor', state.actorId), signal);
|
|
998
|
-
target ??= await this.selectTarget(meshName, String(this.requireMeshNode(meshName).status().routingId), targetApplicationVersion, [
|
|
1008
|
+
target ??= await this.selectTarget(meshName, String(this.requireMeshNode(meshName).status().routingId), targetApplicationVersion, [
|
|
1009
|
+
{
|
|
999
1010
|
objectKind: 'actor',
|
|
1000
1011
|
stableType: authority.allocation.stableType,
|
|
1001
1012
|
policy: this.actorRegistration(state.meshName ?? meshName, authority.allocation.stableType).relocation.kind,
|
|
1002
1013
|
count: 1
|
|
1003
|
-
}
|
|
1014
|
+
}
|
|
1015
|
+
], signal);
|
|
1004
1016
|
const sessions = [];
|
|
1005
|
-
const membershipSpotId = targetMembership?.spotId
|
|
1006
|
-
?? (target.entrySpotId ?? String(target.rid));
|
|
1017
|
+
const membershipSpotId = targetMembership?.spotId ?? (target.entrySpotId ?? String(target.rid));
|
|
1007
1018
|
const aggregateId = aggregateIdOverride ?? this.reserveRelocationId();
|
|
1008
1019
|
const unit = this.actorCaptureUnit(state, authority, sessions, true, target, meshName, {
|
|
1009
1020
|
spotId: membershipSpotId,
|
|
@@ -1025,7 +1036,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1025
1036
|
};
|
|
1026
1037
|
let outcome = 'completed';
|
|
1027
1038
|
try {
|
|
1028
|
-
relocationDebug('standalone_actor.wait_budget', {
|
|
1039
|
+
relocationDebug('standalone_actor.wait_budget', {
|
|
1040
|
+
actorId: state.actorId,
|
|
1041
|
+
targetRid: String(target.rid)
|
|
1042
|
+
});
|
|
1029
1043
|
await this.waitForRelocationBudgetHeadroom(String(target.rid), signal);
|
|
1030
1044
|
relocationDebug('standalone_actor.capture_begin', { actorId: state.actorId });
|
|
1031
1045
|
const captured = await new service_relocation_object_owner_1.ServiceRelocationObjectCaptureOwner().captureStandaloneActor(aggregateId, 1n, measuredUnit, membership, signal);
|
|
@@ -1047,12 +1061,14 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1047
1061
|
const spotKey = (0, authority_key_codec_1.encodeAuthorityKey)('user_spot', String(activation.spotId));
|
|
1048
1062
|
const spotAuthority = await requireAuthority(this.requireLocationStore(), spotKey, signal);
|
|
1049
1063
|
const spotRegistration = this.spotRegistration(meshName, 'user_spot', spotAuthority.allocation.stableType);
|
|
1050
|
-
target ??= await this.selectTarget(meshName, String(this.requireMeshNode(meshName).status().routingId), targetApplicationVersion, [
|
|
1064
|
+
target ??= await this.selectTarget(meshName, String(this.requireMeshNode(meshName).status().routingId), targetApplicationVersion, [
|
|
1065
|
+
{
|
|
1051
1066
|
objectKind: 'user_spot',
|
|
1052
1067
|
stableType: spotAuthority.allocation.stableType,
|
|
1053
1068
|
policy: spotRegistration.relocation.kind,
|
|
1054
1069
|
count: 1
|
|
1055
|
-
}
|
|
1070
|
+
}
|
|
1071
|
+
], signal);
|
|
1056
1072
|
let spotCapture;
|
|
1057
1073
|
let spotMessageFollowSeal;
|
|
1058
1074
|
let sealCommitted = false;
|
|
@@ -1078,7 +1094,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1078
1094
|
captureApplicationState: async () => Buffer.alloc(0),
|
|
1079
1095
|
commitSeal: async () => {
|
|
1080
1096
|
if (!sealCommitted) {
|
|
1081
|
-
if (spotCapture === undefined || !await activation.commitRelocation(spotCapture)) {
|
|
1097
|
+
if (spotCapture === undefined || !(await activation.commitRelocation(spotCapture))) {
|
|
1082
1098
|
throw new Error(`PerActor Spot '${String(activation.spotId)}' relocation seal became stale.`);
|
|
1083
1099
|
}
|
|
1084
1100
|
sealCommitted = true;
|
|
@@ -1136,7 +1152,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1136
1152
|
};
|
|
1137
1153
|
sessions.push(ownSession);
|
|
1138
1154
|
}
|
|
1139
|
-
const prepared = standalone ? ownSession : sessions.find(value => value.state === state);
|
|
1155
|
+
const prepared = standalone ? ownSession : sessions.find((value) => value.state === state);
|
|
1140
1156
|
return {
|
|
1141
1157
|
boundSessionState: encodeActorSession(prepared?.prepared.target),
|
|
1142
1158
|
queuedMessages: encodeHandoffQueuedMessages(prepared?.prepared.handoffBacklog ?? []),
|
|
@@ -1146,12 +1162,14 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1146
1162
|
// The canonical participant body (discriminator 1) is raw application
|
|
1147
1163
|
// state. The sealed bound-session target remains in sealed work and is
|
|
1148
1164
|
// transported only by Prepare's NODE-INTERNAL sideband frames.
|
|
1149
|
-
captureApplicationState: signal => this.captureApplication(registration.relocation, state.actor, signal),
|
|
1165
|
+
captureApplicationState: (signal) => this.captureApplication(registration.relocation, state.actor, signal),
|
|
1150
1166
|
commitSeal: async () => {
|
|
1151
|
-
if (!standalone ||
|
|
1167
|
+
if (!standalone ||
|
|
1168
|
+
ownSession === undefined ||
|
|
1169
|
+
target === undefined ||
|
|
1170
|
+
meshName === undefined)
|
|
1152
1171
|
return;
|
|
1153
|
-
const membershipSpotId = targetMembership?.spotId
|
|
1154
|
-
?? (target.entrySpotId ?? String(target.rid));
|
|
1172
|
+
const membershipSpotId = targetMembership?.spotId ?? (target.entrySpotId ?? String(target.rid));
|
|
1155
1173
|
const committedAuthority = await requireAuthority(this.requireLocationStore(), (0, authority_key_codec_1.encodeAuthorityKey)('actor', state.actorId));
|
|
1156
1174
|
const targetActorRef = {
|
|
1157
1175
|
actorId: state.actorId,
|
|
@@ -1177,12 +1195,12 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1177
1195
|
};
|
|
1178
1196
|
}
|
|
1179
1197
|
reserveRelocationId() {
|
|
1180
|
-
const id = createServiceRelocationId(candidate => {
|
|
1198
|
+
const id = createServiceRelocationId((candidate) => {
|
|
1181
1199
|
if (this.sourceRelocationIds.has(candidate))
|
|
1182
1200
|
return true;
|
|
1183
1201
|
const wire = relocationWireId(candidate);
|
|
1184
1202
|
const prefix = `${wire.high}:${wire.low}:`;
|
|
1185
|
-
return [...this.targetStages.keys()].some(key => key.startsWith(prefix));
|
|
1203
|
+
return [...this.targetStages.keys()].some((key) => key.startsWith(prefix));
|
|
1186
1204
|
});
|
|
1187
1205
|
this.sourceRelocationIds.add(id);
|
|
1188
1206
|
return id;
|
|
@@ -1190,8 +1208,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1190
1208
|
reserveExactRelocationId(id) {
|
|
1191
1209
|
const wire = relocationWireId(id);
|
|
1192
1210
|
const prefix = `${wire.high}:${wire.low}:`;
|
|
1193
|
-
if (this.sourceRelocationIds.has(id)
|
|
1194
|
-
|
|
1211
|
+
if (this.sourceRelocationIds.has(id) ||
|
|
1212
|
+
[...this.targetStages.keys()].some((key) => key.startsWith(prefix))) {
|
|
1195
1213
|
throw new Error(`Actor Join relocation '${id}' is already active.`);
|
|
1196
1214
|
}
|
|
1197
1215
|
this.sourceRelocationIds.add(id);
|
|
@@ -1199,11 +1217,12 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1199
1217
|
async runCoordinator(meshName, target, primary, captured, _authorities, signal, sessions = [],
|
|
1200
1218
|
/** Target's advertised relocation state chunk cap (Actor Join only; spec 15 §4.2). */
|
|
1201
1219
|
advertisedReceiveChunkLimitBytes) {
|
|
1202
|
-
relocationDebug('coordinator.begin', {
|
|
1220
|
+
relocationDebug('coordinator.begin', {
|
|
1221
|
+
aggregateId: captured.envelope.aggregateId,
|
|
1222
|
+
targetRid: String(target.rid)
|
|
1223
|
+
});
|
|
1203
1224
|
const localStatus = this.requireMeshNode(meshName).status();
|
|
1204
|
-
const controlDeadlineAtMs = signal === undefined
|
|
1205
|
-
? performance.now() + 30_000
|
|
1206
|
-
: Number.MAX_SAFE_INTEGER;
|
|
1225
|
+
const controlDeadlineAtMs = signal === undefined ? performance.now() + 30_000 : Number.MAX_SAFE_INTEGER;
|
|
1207
1226
|
const coordinator = {
|
|
1208
1227
|
ownerId: primary.ownerId,
|
|
1209
1228
|
leaseGeneration: primary.ownerLeaseGeneration,
|
|
@@ -1272,7 +1291,9 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1272
1291
|
// the target assembled, verified, and restored the payload.
|
|
1273
1292
|
const readyOperation = this.sendControl(meshName, target.rid, prepare, signal, controlDeadlineAtMs, encodePrepareSideband(captured.envelope));
|
|
1274
1293
|
try {
|
|
1275
|
-
relocationDebug('coordinator.state_transfer_begin', {
|
|
1294
|
+
relocationDebug('coordinator.state_transfer_begin', {
|
|
1295
|
+
aggregateId: captured.envelope.aggregateId
|
|
1296
|
+
});
|
|
1276
1297
|
await this.sendRelocationStateChunks(meshName, target, prepare, encoded, plan, signal);
|
|
1277
1298
|
}
|
|
1278
1299
|
catch (chunkError) {
|
|
@@ -1289,9 +1310,9 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1289
1310
|
readyReceived = true;
|
|
1290
1311
|
const boundaryBatch = [];
|
|
1291
1312
|
for (const session of sessions) {
|
|
1292
|
-
const participant = captured.envelope.participants.find(value => value.objectKind === 'actor'
|
|
1293
|
-
|
|
1294
|
-
|
|
1313
|
+
const participant = captured.envelope.participants.find((value) => value.objectKind === 'actor' &&
|
|
1314
|
+
(0, authority_key_codec_1.decodeAuthorityKey)({ value: value.key }).globalId ===
|
|
1315
|
+
session.state.actorId);
|
|
1295
1316
|
if (participant === undefined) {
|
|
1296
1317
|
throw new Error(`Relocation Actor '${session.state.actorId}' is missing from its envelope.`);
|
|
1297
1318
|
}
|
|
@@ -1320,7 +1341,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1320
1341
|
senderRole: 'source',
|
|
1321
1342
|
object,
|
|
1322
1343
|
boundaryRecordCount: BigInt(boundaryBatch.length),
|
|
1323
|
-
boundaryChecksumCrc32c: (0, service_relocation_runtime_1.crc32c)(Buffer.concat(boundaryBatch.map(value => value.canonicalBytes)))
|
|
1344
|
+
boundaryChecksumCrc32c: (0, service_relocation_runtime_1.crc32c)(Buffer.concat(boundaryBatch.map((value) => value.canonicalBytes)))
|
|
1324
1345
|
});
|
|
1325
1346
|
// The one-way cutover submit reaches a terminal result exactly once;
|
|
1326
1347
|
// success and failure both end source dispatch permanently. The batch
|
|
@@ -1336,9 +1357,11 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1336
1357
|
submitFailure = error;
|
|
1337
1358
|
console.warn('[zlink.runtime.relocation.cutover_submit_failed]', relayAuthorityId, error);
|
|
1338
1359
|
}
|
|
1339
|
-
this.beginSourceCutoverWindow(meshName, target.rid, relayAuthorityId, [...boundaryBatch.map(value => value.frame), cutoverFrame], submitFailure !== undefined, limits);
|
|
1360
|
+
this.beginSourceCutoverWindow(meshName, target.rid, relayAuthorityId, [...boundaryBatch.map((value) => value.frame), cutoverFrame], submitFailure !== undefined, limits);
|
|
1340
1361
|
await this.waitForTargetAuthorities(captured.envelope, targetFence, convergenceDeadlineAtMs, signal);
|
|
1341
|
-
relocationDebug('coordinator.target_authorities_observed', {
|
|
1362
|
+
relocationDebug('coordinator.target_authorities_observed', {
|
|
1363
|
+
aggregateId: captured.envelope.aggregateId
|
|
1364
|
+
});
|
|
1342
1365
|
for (const session of sessions)
|
|
1343
1366
|
session.prepared.setReplayResults([]);
|
|
1344
1367
|
await captured.commitSource();
|
|
@@ -1535,20 +1558,20 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1535
1558
|
const targetStatus = this.requireMeshNode(meshName).status();
|
|
1536
1559
|
const targetOwner = this.options.currentOwner();
|
|
1537
1560
|
const targetDescriptor = this.options.localDescriptor?.(meshName);
|
|
1538
|
-
if (targetOwner === undefined
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1561
|
+
if (targetOwner === undefined ||
|
|
1562
|
+
String(targetStatus.routingId) !== request.target.nodeRid ||
|
|
1563
|
+
targetStatus.lifecycleGeneration !== request.target.nodeGeneration ||
|
|
1564
|
+
targetOwner.ownerId !== request.target.ownerId ||
|
|
1565
|
+
targetOwner.leaseGeneration !== request.target.ownerLeaseGeneration ||
|
|
1566
|
+
(targetDescriptor !== undefined &&
|
|
1567
|
+
targetDescriptor.applicationVersion !== request.applicationVersion)) {
|
|
1545
1568
|
throw new Error('Relocation prepare target fence does not match the target owner.');
|
|
1546
1569
|
}
|
|
1547
1570
|
const fingerprint = stringifyWire(request);
|
|
1548
1571
|
const existing = this.targetStages.get(stagingId);
|
|
1549
1572
|
if (existing !== undefined) {
|
|
1550
|
-
if (existing.offer.authenticatedSourceNodeRid !== String(sourceNodeRid)
|
|
1551
|
-
|
|
1573
|
+
if (existing.offer.authenticatedSourceNodeRid !== String(sourceNodeRid) ||
|
|
1574
|
+
existing.offer.prepareFingerprint !== fingerprint) {
|
|
1552
1575
|
throw new Error('Relocation prepare retry source node changed.');
|
|
1553
1576
|
}
|
|
1554
1577
|
return relocationReady(request);
|
|
@@ -1581,7 +1604,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1581
1604
|
if (this.disposed)
|
|
1582
1605
|
throw error;
|
|
1583
1606
|
const message = error !== null && typeof error === 'object' && 'message' in error
|
|
1584
|
-
? error.message ?? error
|
|
1607
|
+
? (error.message ?? error)
|
|
1585
1608
|
: error;
|
|
1586
1609
|
throw new ServiceRelocationDataLostError(String(message));
|
|
1587
1610
|
}
|
|
@@ -1632,8 +1655,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1632
1655
|
if (stage === undefined || stage.fallback !== undefined || stage.finalize !== undefined)
|
|
1633
1656
|
return;
|
|
1634
1657
|
stage.fallback = setTimeout(() => {
|
|
1635
|
-
void this.beginTargetFinalize(meshName, stagingId, stage, true)
|
|
1636
|
-
.catch(error => console.error('[zlink.runtime.relocation.location_update_failed]', error));
|
|
1658
|
+
void this.beginTargetFinalize(meshName, stagingId, stage, true).catch((error) => console.error('[zlink.runtime.relocation.location_update_failed]', error));
|
|
1637
1659
|
}, this.relocationLimits().relocationCutoverWaitTimeoutMs);
|
|
1638
1660
|
stage.fallback.unref();
|
|
1639
1661
|
}
|
|
@@ -1685,9 +1707,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1685
1707
|
}
|
|
1686
1708
|
const expectedCount = Number(request.boundaryRecordCount);
|
|
1687
1709
|
const staged = stage.boundaryRelay;
|
|
1688
|
-
const checksumOf = (records) => (0, service_relocation_runtime_1.crc32c)(Buffer.concat(records.map(value => value.frozenRecord.canonicalBytes)));
|
|
1689
|
-
if (staged.length === expectedCount
|
|
1690
|
-
&& checksumOf(staged) === request.boundaryChecksumCrc32c) {
|
|
1710
|
+
const checksumOf = (records) => (0, service_relocation_runtime_1.crc32c)(Buffer.concat(records.map((value) => value.frozenRecord.canonicalBytes)));
|
|
1711
|
+
if (staged.length === expectedCount && checksumOf(staged) === request.boundaryChecksumCrc32c) {
|
|
1691
1712
|
return;
|
|
1692
1713
|
}
|
|
1693
1714
|
if (staged.length > expectedCount) {
|
|
@@ -1700,8 +1721,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1700
1721
|
}
|
|
1701
1722
|
// Spec 28 §4.4 — on an ordered connection this comparison always holds on
|
|
1702
1723
|
// the normal path; a mismatch signals an implementation defect.
|
|
1703
|
-
throw new Error(`Relocation cutover boundary confirmation mismatch for '${stagingId}' `
|
|
1704
|
-
|
|
1724
|
+
throw new Error(`Relocation cutover boundary confirmation mismatch for '${stagingId}' ` +
|
|
1725
|
+
`(staged=${staged.length} declared=${expectedCount}).`);
|
|
1705
1726
|
}
|
|
1706
1727
|
beginTargetFinalize(meshName, stagingId, stage, fallback, signal) {
|
|
1707
1728
|
if (stage.finalize !== undefined)
|
|
@@ -1793,25 +1814,23 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1793
1814
|
const target = frozen.target;
|
|
1794
1815
|
const payload = frozen.applicationPayload;
|
|
1795
1816
|
const preparedTarget = stage.offer.prepare.target;
|
|
1796
|
-
if (request.object.kind !== 'actor'
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|| target.ownerLeaseGeneration !== preparedTarget.ownerLeaseGeneration) {
|
|
1817
|
+
if (request.object.kind !== 'actor' ||
|
|
1818
|
+
target?.kind !== 'actor' ||
|
|
1819
|
+
payload === undefined ||
|
|
1820
|
+
payload.packetName !== '__zlink.actor.handoff.accepted' ||
|
|
1821
|
+
target.actorId !== request.object.actorId ||
|
|
1822
|
+
target.generation !== request.object.objectGeneration ||
|
|
1823
|
+
target.targetNodeRid !== preparedTarget.nodeRid ||
|
|
1824
|
+
target.targetNodeGeneration !== preparedTarget.nodeGeneration ||
|
|
1825
|
+
target.authorityOwnerGeneration !== request.object.expectedAuthorityOwnerGeneration + 1n ||
|
|
1826
|
+
target.ownerLeaseGeneration !== preparedTarget.ownerLeaseGeneration) {
|
|
1807
1827
|
throw new Error('Relocation data does not target the exact temporary Actor queue.');
|
|
1808
1828
|
}
|
|
1809
1829
|
const key = (0, authority_key_codec_1.encodeAuthorityKey)('actor', request.object.actorId).value;
|
|
1810
|
-
const participant = stage.staging.envelope.participants.find(value => value.key === key);
|
|
1811
|
-
if (participant === undefined
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
!== request.object.expectedAuthorityOwnerGeneration) {
|
|
1830
|
+
const participant = stage.staging.envelope.participants.find((value) => value.key === key);
|
|
1831
|
+
if (participant === undefined ||
|
|
1832
|
+
participant.objectGeneration !== request.object.objectGeneration ||
|
|
1833
|
+
participant.authorityOwnerGeneration !== request.object.expectedAuthorityOwnerGeneration) {
|
|
1815
1834
|
throw new Error('Relocation data Actor is not part of the prepared unit.');
|
|
1816
1835
|
}
|
|
1817
1836
|
}
|
|
@@ -1831,7 +1850,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1831
1850
|
if (nativeRef === undefined) {
|
|
1832
1851
|
throw new Error(`Actor '${hidden.actor.context.actorId}' relocation target has no native identity.`);
|
|
1833
1852
|
}
|
|
1834
|
-
await manager.finalizeActorJoinRelocation(meshName, actorJoinAdmissionIdentity(stage.staging.envelope), hidden.actor, (0, actor_runtime_state_1.toFrameworkActorRef)(nativeRef, meshName), sourceNodeRid => this.submitActorJoinSourceLeave(meshName, sourceNodeRid, stage.staging.envelope.aggregateId, hidden.actor.context.actorId), signal);
|
|
1853
|
+
await manager.finalizeActorJoinRelocation(meshName, actorJoinAdmissionIdentity(stage.staging.envelope), hidden.actor, (0, actor_runtime_state_1.toFrameworkActorRef)(nativeRef, meshName), (sourceNodeRid) => this.submitActorJoinSourceLeave(meshName, sourceNodeRid, stage.staging.envelope.aggregateId, hidden.actor.context.actorId), signal);
|
|
1835
1854
|
}
|
|
1836
1855
|
}
|
|
1837
1856
|
async submitActorJoinSourceLeave(meshName, sourceNodeRid, relocationId, actorId) {
|
|
@@ -1867,10 +1886,14 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1867
1886
|
}
|
|
1868
1887
|
this.sourceActorJoinProfiles.delete(input.transferId);
|
|
1869
1888
|
this.terminalActorJoinSourceLeaves.remember(input.transferId, input.actorId);
|
|
1870
|
-
void profile.ready
|
|
1889
|
+
void profile.ready
|
|
1890
|
+
.then(async () => {
|
|
1871
1891
|
await this.options.actorTransfer.completeRelocationSourceLeave(profile.actor, profile.sourceSpotId);
|
|
1872
|
-
await this.options
|
|
1873
|
-
|
|
1892
|
+
await this.options
|
|
1893
|
+
.actorManager()
|
|
1894
|
+
?.completeRelocationSource(input.actorId, profile.sourceActorRef);
|
|
1895
|
+
})
|
|
1896
|
+
.catch((error) => {
|
|
1874
1897
|
console.error('[zlink.runtime.relocation.source_leave_failed]', error);
|
|
1875
1898
|
});
|
|
1876
1899
|
return true;
|
|
@@ -1890,13 +1913,13 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1890
1913
|
let exact = true;
|
|
1891
1914
|
for (const participant of envelope.participants) {
|
|
1892
1915
|
const current = await this.requireLocationStore().readAuthority({ value: participant.key }, signal);
|
|
1893
|
-
if (current.kind !== 'snapshot'
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1916
|
+
if (current.kind !== 'snapshot' ||
|
|
1917
|
+
current.objectGeneration !== participant.objectGeneration ||
|
|
1918
|
+
current.ownerId !== target.ownerId ||
|
|
1919
|
+
current.ownerLeaseGeneration !== target.ownerLeaseGeneration ||
|
|
1920
|
+
current.authorityOwnerGeneration <= participant.authorityOwnerGeneration ||
|
|
1921
|
+
String(current.allocation.descriptor.rid) !== target.nodeRid ||
|
|
1922
|
+
current.allocation.descriptorLifecycleGeneration !== target.nodeGeneration) {
|
|
1900
1923
|
exact = false;
|
|
1901
1924
|
break;
|
|
1902
1925
|
}
|
|
@@ -1906,7 +1929,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1906
1929
|
if (performance.now() >= deadlineAtMs) {
|
|
1907
1930
|
throw new Error('Relocation target owner was not confirmed before its original deadline.');
|
|
1908
1931
|
}
|
|
1909
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
1932
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
1910
1933
|
}
|
|
1911
1934
|
}
|
|
1912
1935
|
async clearTargetRelocationPublication(stage, primary, signal) {
|
|
@@ -1948,27 +1971,26 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1948
1971
|
throw new Error('Relocation reply relay has no registered durable authority.');
|
|
1949
1972
|
}
|
|
1950
1973
|
const authority = await requireAuthority(this.requireLocationStore(), { value: authorityKey }, signal);
|
|
1951
|
-
if (authority.storeVersion.value !== relay.coordinator.expectedAuthorityStoreVersion
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
!== relay.coordinator.nodeGeneration) {
|
|
1974
|
+
if (authority.storeVersion.value !== relay.coordinator.expectedAuthorityStoreVersion ||
|
|
1975
|
+
authority.ownerId !== relay.coordinator.ownerId ||
|
|
1976
|
+
authority.ownerLeaseGeneration !== relay.coordinator.leaseGeneration ||
|
|
1977
|
+
String(authority.allocation.descriptor.rid) !== relay.coordinator.nodeRid ||
|
|
1978
|
+
authority.allocation.descriptorLifecycleGeneration !== relay.coordinator.nodeGeneration) {
|
|
1957
1979
|
throw new Error('Relocation reply relay coordinator authority fence is stale.');
|
|
1958
1980
|
}
|
|
1959
1981
|
const accepted = this.options.actorTransfer.relayCanonicalMaintenanceTerminal(wireIdText(relay.operation), relay.replyRouteId.toString(), handoffResultFromRelay(relay), sourceNodeRid);
|
|
1960
|
-
if (accepted.status !== 'terminalReceived' && accepted.status !== 'alreadyTerminal'
|
|
1961
|
-
|
|
1982
|
+
if ((accepted.status !== 'terminalReceived' && accepted.status !== 'alreadyTerminal') ||
|
|
1983
|
+
accepted.source === undefined) {
|
|
1962
1984
|
throw new Error('Canonical relocation reply relay collided with another source route.');
|
|
1963
1985
|
}
|
|
1964
1986
|
const requestSource = handoffSourceFence(accepted.source);
|
|
1965
1987
|
const localStatus = this.requireMeshNode(meshName).status();
|
|
1966
1988
|
const localOwner = this.options.currentOwner();
|
|
1967
|
-
if (localOwner === undefined
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1989
|
+
if (localOwner === undefined ||
|
|
1990
|
+
requestSource.ownerId !== localOwner.ownerId ||
|
|
1991
|
+
requestSource.leaseGeneration !== localOwner.leaseGeneration ||
|
|
1992
|
+
!(0, routing_id_1.routingIdsEqual)(requestSource.nodeRid, localStatus.routingId) ||
|
|
1993
|
+
requestSource.nodeGeneration !== localStatus.lifecycleGeneration) {
|
|
1972
1994
|
throw new Error('Relocation reply relay request-source fence changed after capture.');
|
|
1973
1995
|
}
|
|
1974
1996
|
const ack = {
|
|
@@ -1979,7 +2001,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
1979
2001
|
requestSource,
|
|
1980
2002
|
status: accepted.status
|
|
1981
2003
|
};
|
|
1982
|
-
if (await this.sendInfrastructureControl(meshName, sourceNodeRid, (0, service_stateful_wire_codec_1.encodeMaintenanceReplyRelayAck)(ack)) !== runtime_values_1.SubmitResult.Ok) {
|
|
2004
|
+
if ((await this.sendInfrastructureControl(meshName, sourceNodeRid, (0, service_stateful_wire_codec_1.encodeMaintenanceReplyRelayAck)(ack))) !== runtime_values_1.SubmitResult.Ok) {
|
|
1983
2005
|
throw new Error('Relocation reply relay ACK send was rejected.');
|
|
1984
2006
|
}
|
|
1985
2007
|
}
|
|
@@ -2004,8 +2026,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2004
2026
|
identityKey,
|
|
2005
2027
|
request,
|
|
2006
2028
|
expectedRequestSource,
|
|
2007
|
-
resolve: delivery => finish(() => resolve(delivery)),
|
|
2008
|
-
reject: error => finish(() => reject(error))
|
|
2029
|
+
resolve: (delivery) => finish(() => resolve(delivery)),
|
|
2030
|
+
reject: (error) => finish(() => reject(error))
|
|
2009
2031
|
};
|
|
2010
2032
|
const send = async () => {
|
|
2011
2033
|
try {
|
|
@@ -2036,22 +2058,20 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2036
2058
|
}
|
|
2037
2059
|
async acceptReplyRelayAck(meshName, ack, sourceNodeRid, signal) {
|
|
2038
2060
|
const identityKey = replyRelayIdentityKey(ack);
|
|
2039
|
-
const exactKey = sourceNodeRid === null
|
|
2040
|
-
? undefined
|
|
2041
|
-
: replyRelayPendingKey(String(sourceNodeRid), ack);
|
|
2061
|
+
const exactKey = sourceNodeRid === null ? undefined : replyRelayPendingKey(String(sourceNodeRid), ack);
|
|
2042
2062
|
const pending = exactKey === undefined ? undefined : this.pendingReplyRelays.get(exactKey);
|
|
2043
2063
|
if (pending === undefined) {
|
|
2044
|
-
const collision = [...this.pendingReplyRelays.values()].find(value => value.identityKey === identityKey);
|
|
2064
|
+
const collision = [...this.pendingReplyRelays.values()].find((value) => value.identityKey === identityKey);
|
|
2045
2065
|
collision?.reject(new Error('Relocation reply relay ACK target source collided.'));
|
|
2046
2066
|
return;
|
|
2047
2067
|
}
|
|
2048
2068
|
try {
|
|
2049
2069
|
await this.requireAdmittedPeer(meshName, pending.ackTargetNodeRid, pending.expectedRequestSource, signal);
|
|
2050
|
-
if (!sameWireId(ack.relocation, pending.request.relocation)
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2070
|
+
if (!sameWireId(ack.relocation, pending.request.relocation) ||
|
|
2071
|
+
!sameWireId(ack.operation, pending.request.operation) ||
|
|
2072
|
+
ack.replyRouteId !== pending.request.replyRouteId ||
|
|
2073
|
+
!sameCoordinator(ack.coordinator, pending.request.coordinator) ||
|
|
2074
|
+
!sameRequestSource(ack.requestSource, pending.expectedRequestSource)) {
|
|
2055
2075
|
throw new Error('Relocation reply relay ACK does not match its durable source fence.');
|
|
2056
2076
|
}
|
|
2057
2077
|
pending.resolve(ack.status);
|
|
@@ -2061,12 +2081,13 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2061
2081
|
}
|
|
2062
2082
|
}
|
|
2063
2083
|
async requireAdmittedPeer(meshName, authenticatedRid, expected, signal) {
|
|
2064
|
-
const descriptor = (await this.options.liveDescriptors(meshName, signal)).find(value => String(value.rid) === authenticatedRid && value.state === 1);
|
|
2065
|
-
if (descriptor === undefined
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2084
|
+
const descriptor = (await this.options.liveDescriptors(meshName, signal)).find((value) => String(value.rid) === authenticatedRid && value.state === 1);
|
|
2085
|
+
if (descriptor === undefined ||
|
|
2086
|
+
(expected !== undefined &&
|
|
2087
|
+
(descriptor.ownerId !== expected.ownerId ||
|
|
2088
|
+
descriptor.leaseGeneration !== expected.leaseGeneration ||
|
|
2089
|
+
String(descriptor.rid) !== expected.nodeRid ||
|
|
2090
|
+
descriptor.lifecycleGeneration !== expected.nodeGeneration))) {
|
|
2070
2091
|
throw new Error('Relocation reply relay peer is not the exact admitted source fence.');
|
|
2071
2092
|
}
|
|
2072
2093
|
}
|
|
@@ -2074,11 +2095,11 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2074
2095
|
const status = this.requireMeshNode(meshName).status();
|
|
2075
2096
|
const owner = this.options.currentOwner();
|
|
2076
2097
|
const target = stage.offer.prepare.target;
|
|
2077
|
-
if (owner === undefined
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2098
|
+
if (owner === undefined ||
|
|
2099
|
+
owner.ownerId !== target.ownerId ||
|
|
2100
|
+
owner.leaseGeneration !== target.ownerLeaseGeneration ||
|
|
2101
|
+
String(status.routingId) !== target.nodeRid ||
|
|
2102
|
+
status.lifecycleGeneration !== target.nodeGeneration) {
|
|
2082
2103
|
throw new Error('Relocation reply relay target coordinator fence is stale.');
|
|
2083
2104
|
}
|
|
2084
2105
|
return {
|
|
@@ -2113,10 +2134,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2113
2134
|
}
|
|
2114
2135
|
async exactSourceLeaseExpired(source, signal) {
|
|
2115
2136
|
const lease = await this.requireLocationStore().readOwnerLease(source.ownerId, signal);
|
|
2116
|
-
return lease.kind === 'missing'
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2137
|
+
return (lease.kind === 'missing' ||
|
|
2138
|
+
lease.token.ownerId !== source.ownerId ||
|
|
2139
|
+
lease.token.leaseGeneration !== source.leaseGeneration ||
|
|
2140
|
+
lease.leaseExpiresAt.getTime() <= lease.storeNow.getTime());
|
|
2120
2141
|
}
|
|
2121
2142
|
async publishSessionRoutes(staging) {
|
|
2122
2143
|
for (const hidden of staging.hidden.values()) {
|
|
@@ -2153,8 +2174,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2153
2174
|
return response;
|
|
2154
2175
|
}
|
|
2155
2176
|
catch (error) {
|
|
2156
|
-
if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError
|
|
2157
|
-
|| error instanceof contracts_1.ZLinkFrameworkException) {
|
|
2177
|
+
if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError || error instanceof contracts_1.ZLinkFrameworkException) {
|
|
2158
2178
|
throw error;
|
|
2159
2179
|
}
|
|
2160
2180
|
lastRequestError = error;
|
|
@@ -2172,24 +2192,23 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2172
2192
|
}
|
|
2173
2193
|
async selectTarget(meshName, localRid, targetApplicationVersion, requirements = [], signal) {
|
|
2174
2194
|
const descriptors = await this.options.liveDescriptors(meshName, signal);
|
|
2175
|
-
const local = this.options.localDescriptor?.(meshName)
|
|
2176
|
-
|
|
2195
|
+
const local = this.options.localDescriptor?.(meshName) ??
|
|
2196
|
+
descriptors.find((descriptor) => String(descriptor.rid) === localRid);
|
|
2177
2197
|
const requiredVersion = targetApplicationVersion ?? local?.applicationVersion;
|
|
2178
2198
|
const peers = this.requireMeshNode(meshName).peers();
|
|
2179
2199
|
const candidates = descriptors
|
|
2180
|
-
.filter(descriptor => String(descriptor.rid) !== localRid
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
&& relocationTargetSupports(descriptor, requirements))
|
|
2200
|
+
.filter((descriptor) => String(descriptor.rid) !== localRid &&
|
|
2201
|
+
descriptor.state === contracts_1.ZLinkFrameworkRuntimeState.Serving &&
|
|
2202
|
+
descriptor.objectRole === contracts_1.ZLinkObjectRole.Server &&
|
|
2203
|
+
descriptor.placementWeight > 0 &&
|
|
2204
|
+
(requiredVersion === undefined || descriptor.applicationVersion === requiredVersion) &&
|
|
2205
|
+
(local?.maintenanceWave === undefined ||
|
|
2206
|
+
descriptor.maintenanceWave !== local.maintenanceWave) &&
|
|
2207
|
+
peers.some((peer) => peer.routingId !== null &&
|
|
2208
|
+
String(peer.routingId) === String(descriptor.rid) &&
|
|
2209
|
+
peer.lifecycleGeneration === descriptor.lifecycleGeneration &&
|
|
2210
|
+
peer.state === 3) &&
|
|
2211
|
+
relocationTargetSupports(descriptor, requirements))
|
|
2193
2212
|
.sort((left, right) => String(left.rid).localeCompare(String(right.rid)));
|
|
2194
2213
|
const target = selectWeightedRelocationTarget(candidates);
|
|
2195
2214
|
if (target === undefined) {
|
|
@@ -2204,11 +2223,11 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2204
2223
|
const authorities = new Map();
|
|
2205
2224
|
for (const participant of envelope.participants) {
|
|
2206
2225
|
const current = await requireAuthority(this.requireLocationStore(), { value: participant.key }, signal);
|
|
2207
|
-
if (current.objectGeneration !== participant.objectGeneration
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2226
|
+
if (current.objectGeneration !== participant.objectGeneration ||
|
|
2227
|
+
current.authorityOwnerGeneration !== participant.authorityOwnerGeneration ||
|
|
2228
|
+
current.allocation.objectKind !== participant.objectKind ||
|
|
2229
|
+
current.allocation.stableType !== participant.stableType ||
|
|
2230
|
+
current.allocation.state !== 'active') {
|
|
2212
2231
|
throw new Error(`Relocation participant '${participant.key}' authority changed before reservation.`);
|
|
2213
2232
|
}
|
|
2214
2233
|
authorities.set(participant.key, current);
|
|
@@ -2233,31 +2252,30 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2233
2252
|
continue;
|
|
2234
2253
|
}
|
|
2235
2254
|
const current = this.codec.read(authorities.get(participant.key).payload);
|
|
2236
|
-
if (participant.objectKind === 'actor'
|
|
2237
|
-
|
|
2238
|
-
|
|
2255
|
+
if (participant.objectKind === 'actor' &&
|
|
2256
|
+
current?.canonical === true &&
|
|
2257
|
+
(await this.options.actorTransfer.isDeferredJoinAcceptedRootPublication(current.reference, current.checksumCrc32c, {
|
|
2239
2258
|
authorityKey: participant.key,
|
|
2240
2259
|
objectKind: 'actor',
|
|
2241
2260
|
objectGeneration: participant.objectGeneration,
|
|
2242
2261
|
aggregateId: current.aggregateId,
|
|
2243
2262
|
aggregateGeneration: current.aggregateGeneration
|
|
2244
|
-
}, signal)) {
|
|
2263
|
+
}, signal))) {
|
|
2245
2264
|
retainedDeferredJoinRoots.set(participant.key, {
|
|
2246
2265
|
reference: current.reference,
|
|
2247
2266
|
checksumCrc32c: current.checksumCrc32c
|
|
2248
2267
|
});
|
|
2249
2268
|
}
|
|
2250
2269
|
}
|
|
2251
|
-
const participants = envelope.participants.map(participant => {
|
|
2270
|
+
const participants = envelope.participants.map((participant) => {
|
|
2252
2271
|
const expected = authorities.get(participant.key);
|
|
2253
2272
|
const membership = actorMembershipTarget(envelope, participant.key);
|
|
2254
|
-
const entrySpotId = expected.allocation.objectKind === 'actor'
|
|
2255
|
-
&& membership === undefined
|
|
2273
|
+
const entrySpotId = expected.allocation.objectKind === 'actor' && membership === undefined
|
|
2256
2274
|
? this.options.spotManager()?.entrySpotIdForMesh(meshName)
|
|
2257
2275
|
: undefined;
|
|
2258
|
-
if (expected.allocation.objectKind === 'actor'
|
|
2259
|
-
|
|
2260
|
-
|
|
2276
|
+
if (expected.allocation.objectKind === 'actor' &&
|
|
2277
|
+
membership === undefined &&
|
|
2278
|
+
entrySpotId === undefined) {
|
|
2261
2279
|
throw new Error(`Relocation target RouteMesh '${meshName}' has no Entry Spot.`);
|
|
2262
2280
|
}
|
|
2263
2281
|
const retainedDeferredJoinRoot = retainedDeferredJoinRoots.get(participant.key);
|
|
@@ -2311,24 +2329,20 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2311
2329
|
}
|
|
2312
2330
|
};
|
|
2313
2331
|
return {
|
|
2314
|
-
prepared: await new service_relocation_aggregate_committer_1.ServiceRelocationAggregateCommitter(this.requireLocationStore())
|
|
2315
|
-
.prepare(plan, signal)
|
|
2332
|
+
prepared: await new service_relocation_aggregate_committer_1.ServiceRelocationAggregateCommitter(this.requireLocationStore()).prepare(plan, signal)
|
|
2316
2333
|
};
|
|
2317
2334
|
}
|
|
2318
2335
|
authorityPayloadForPublication(payload, publication, target, replacesDeferredJoinRoot = false) {
|
|
2319
2336
|
const existing = this.codec.read(payload);
|
|
2320
2337
|
const canonicalIdentity = (0, service_relocation_runtime_1.serviceRelocationAuthoritySlotIdentity)(payload);
|
|
2321
|
-
const replacesCanonicalJournal = replacesDeferredJoinRoot
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
&& (existing.aggregateId === publication.aggregateId
|
|
2327
|
-
|| replacesCanonicalJournal))) {
|
|
2338
|
+
const replacesCanonicalJournal = replacesDeferredJoinRoot && existing?.canonical === true;
|
|
2339
|
+
if (canonicalIdentity !== undefined &&
|
|
2340
|
+
(existing === undefined ||
|
|
2341
|
+
(existing.canonical === true &&
|
|
2342
|
+
(existing.aggregateId === publication.aggregateId || replacesCanonicalJournal)))) {
|
|
2328
2343
|
const published = existing === undefined
|
|
2329
2344
|
? this.codec.publish(payload, publication)
|
|
2330
|
-
: replacesCanonicalJournal
|
|
2331
|
-
&& existing.aggregateId !== publication.aggregateId
|
|
2345
|
+
: replacesCanonicalJournal && existing.aggregateId !== publication.aggregateId
|
|
2332
2346
|
? this.codec.publish(this.codec.clear(payload, existing.reference), publication)
|
|
2333
2347
|
: payload;
|
|
2334
2348
|
if (target === undefined)
|
|
@@ -2359,25 +2373,23 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2359
2373
|
}
|
|
2360
2374
|
return this.codec.publish(rewriteAuthorityApplicationRoute(payload, target), publication);
|
|
2361
2375
|
}
|
|
2362
|
-
if (existing.reference !== publication.reference
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
+ `/${publication.reference}).`);
|
|
2376
|
+
if (existing.reference !== publication.reference ||
|
|
2377
|
+
existing.checksumCrc32c !== publication.checksumCrc32c ||
|
|
2378
|
+
existing.aggregateId !== publication.aggregateId ||
|
|
2379
|
+
existing.aggregateGeneration !== publication.aggregateGeneration ||
|
|
2380
|
+
existing.inventoryDigest !== publication.inventoryDigest ||
|
|
2381
|
+
existing.targetOwnerId !== publication.targetOwnerId ||
|
|
2382
|
+
existing.targetOwnerLeaseGeneration !== publication.targetOwnerLeaseGeneration) {
|
|
2383
|
+
throw new Error('Relocation authority contains another published root ' +
|
|
2384
|
+
`(current=${existing.aggregateId}/${existing.aggregateGeneration}` +
|
|
2385
|
+
`/${existing.reference}/canonical=${existing.canonical === true}, ` +
|
|
2386
|
+
`requested=${publication.aggregateId}/${publication.aggregateGeneration}` +
|
|
2387
|
+
`/${publication.reference}).`);
|
|
2375
2388
|
}
|
|
2376
2389
|
return payload;
|
|
2377
2390
|
}
|
|
2378
2391
|
async abortTargetReservation(reservation, signal) {
|
|
2379
|
-
await new service_relocation_aggregate_committer_1.ServiceRelocationAggregateCommitter(this.requireLocationStore())
|
|
2380
|
-
.abort(reservation.prepared, signal);
|
|
2392
|
+
await new service_relocation_aggregate_committer_1.ServiceRelocationAggregateCommitter(this.requireLocationStore()).abort(reservation.prepared, signal);
|
|
2381
2393
|
}
|
|
2382
2394
|
async abortTargetStage(stage, signal) {
|
|
2383
2395
|
if (stage.fallback !== undefined)
|
|
@@ -2467,13 +2479,11 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2467
2479
|
if (committed === prepared.plan.participants.length) {
|
|
2468
2480
|
return { kind: 'committed', authorities };
|
|
2469
2481
|
}
|
|
2470
|
-
return source === prepared.plan.participants.length
|
|
2471
|
-
? { kind: 'source' }
|
|
2472
|
-
: { kind: 'stale' };
|
|
2482
|
+
return source === prepared.plan.participants.length ? { kind: 'source' } : { kind: 'stale' };
|
|
2473
2483
|
}
|
|
2474
2484
|
async materializeTargetEnvelope(meshName, envelope, signal) {
|
|
2475
2485
|
const target = new LocalTargetPort(this.options, meshName, envelope);
|
|
2476
|
-
const owner = new service_relocation_object_owner_1.ServiceRelocationObjectRestoreOwner(target, value => ({ value }));
|
|
2486
|
+
const owner = new service_relocation_object_owner_1.ServiceRelocationObjectRestoreOwner(target, (value) => ({ value }));
|
|
2477
2487
|
const staging = await owner.prepare(envelope, signal);
|
|
2478
2488
|
if (staging.id !== `${envelope.aggregateId}:${envelope.aggregateGeneration}`) {
|
|
2479
2489
|
throw new Error('Relocation materialization returned a different staging identity.');
|
|
@@ -2482,7 +2492,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2482
2492
|
}
|
|
2483
2493
|
/** Maps schema ordinals to the authoritative Location Store inventory. */
|
|
2484
2494
|
async resolveTargetParticipantInventory(request, envelope, signal) {
|
|
2485
|
-
if (!envelope.participants.some(value => value.rootSpotId !== undefined)) {
|
|
2495
|
+
if (!envelope.participants.some((value) => value.rootSpotId !== undefined)) {
|
|
2486
2496
|
return envelope;
|
|
2487
2497
|
}
|
|
2488
2498
|
const store = this.requireLocationStore();
|
|
@@ -2491,9 +2501,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2491
2501
|
? (0, authority_key_codec_1.encodeAuthorityKey)('actor', request.object.actorId)
|
|
2492
2502
|
: (0, authority_key_codec_1.encodeAuthorityKey)(request.object.kind === 'userSpot' ? 'user_spot' : 'instance_spot', request.object.spotId);
|
|
2493
2503
|
const primary = await requireAuthority(store, primaryKey, signal);
|
|
2494
|
-
const entries = [
|
|
2495
|
-
{ key: primaryKey, snapshot: primary }
|
|
2496
|
-
];
|
|
2504
|
+
const entries = [{ key: primaryKey, snapshot: primary }];
|
|
2497
2505
|
if (request.object.kind === 'userSpot' || request.object.kind === 'instanceSpot') {
|
|
2498
2506
|
let cursor;
|
|
2499
2507
|
for (;;) {
|
|
@@ -2502,8 +2510,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2502
2510
|
throw new Error('Location Store authority scan expired during relocation.');
|
|
2503
2511
|
}
|
|
2504
2512
|
for (const candidate of page.items) {
|
|
2505
|
-
if (candidate.key.value === primaryKey.value
|
|
2506
|
-
|
|
2513
|
+
if (candidate.key.value === primaryKey.value ||
|
|
2514
|
+
(0, authority_key_codec_1.decodeAuthorityKey)(candidate.key).kind !== 'actor')
|
|
2507
2515
|
continue;
|
|
2508
2516
|
const actor = (0, actor_authority_publication_1.decodeRelocatingActorAuthorityIdentity)(candidate.snapshot.payload, candidate.snapshot.objectGeneration);
|
|
2509
2517
|
if (actor?.spotId === request.object.spotId) {
|
|
@@ -2516,22 +2524,20 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2516
2524
|
}
|
|
2517
2525
|
}
|
|
2518
2526
|
entries.sort((left, right) => Buffer.compare(Buffer.from(left.key.value, 'utf8'), Buffer.from(right.key.value, 'utf8')));
|
|
2519
|
-
if (new Set(entries.map(entry => entry.key.value)).size !== entries.length) {
|
|
2527
|
+
if (new Set(entries.map((entry) => entry.key.value)).size !== entries.length) {
|
|
2520
2528
|
throw new Error('Location Store relocation inventory has duplicate authority keys.');
|
|
2521
2529
|
}
|
|
2522
|
-
const root = envelope.participants.find(value => value.rootSpotId !== undefined);
|
|
2523
|
-
const expectedRootId = request.object.kind === 'actor'
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|| root.rootObjectKind !== 'instance_spot'
|
|
2531
|
-
&& root.rootOwnerGeneration !== primary.authorityOwnerGeneration) {
|
|
2530
|
+
const root = envelope.participants.find((value) => value.rootSpotId !== undefined);
|
|
2531
|
+
const expectedRootId = request.object.kind === 'actor' ? request.object.actorId : request.object.spotId;
|
|
2532
|
+
if (root === undefined ||
|
|
2533
|
+
root.rootSpotId !== expectedRootId ||
|
|
2534
|
+
root.rootObjectKind !== primary.allocation.objectKind ||
|
|
2535
|
+
root.rootSpotGeneration !== primary.objectGeneration ||
|
|
2536
|
+
(root.rootObjectKind !== 'instance_spot' &&
|
|
2537
|
+
root.rootOwnerGeneration !== primary.authorityOwnerGeneration)) {
|
|
2532
2538
|
throw new Error('Relocation root object projection does not match Location Store.');
|
|
2533
2539
|
}
|
|
2534
|
-
const transferred = new Map(envelope.participants.map(participant => [participant.participantId, participant]));
|
|
2540
|
+
const transferred = new Map(envelope.participants.map((participant) => [participant.participantId, participant]));
|
|
2535
2541
|
if (transferred.size !== envelope.participants.length || transferred.size !== entries.length) {
|
|
2536
2542
|
throw new Error('Relocation payload participant inventory does not match Location Store.');
|
|
2537
2543
|
}
|
|
@@ -2558,8 +2564,8 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2558
2564
|
const memberships = request.object.kind === 'actor'
|
|
2559
2565
|
? actorJoinTargetMembership(manager, envelope.aggregateId, participants)
|
|
2560
2566
|
: entries
|
|
2561
|
-
.filter(entry => entry.snapshot.allocation.objectKind === 'actor')
|
|
2562
|
-
.map(entry => ({
|
|
2567
|
+
.filter((entry) => entry.snapshot.allocation.objectKind === 'actor')
|
|
2568
|
+
.map((entry) => ({
|
|
2563
2569
|
actorKey: entry.key.value,
|
|
2564
2570
|
spotKey: primaryKey.value,
|
|
2565
2571
|
spotObjectGeneration: primary.objectGeneration,
|
|
@@ -2576,9 +2582,10 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2576
2582
|
const registrations = activation.domain.kind === 'user'
|
|
2577
2583
|
? node?.spotFactoryRegistrations
|
|
2578
2584
|
: node?.instanceSpotFactoryRegistrations;
|
|
2579
|
-
return Object.values(registrations ?? {})
|
|
2580
|
-
|
|
2581
|
-
|
|
2585
|
+
return Object.values(registrations ?? {}).some((value) => value.implementation === activation.spotType)
|
|
2586
|
+
? activation.domain.kind === 'user'
|
|
2587
|
+
? 'user_spot'
|
|
2588
|
+
: 'instance_spot'
|
|
2582
2589
|
: undefined;
|
|
2583
2590
|
}
|
|
2584
2591
|
spotRegistration(meshName, kind, stableType) {
|
|
@@ -2591,8 +2598,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2591
2598
|
return value;
|
|
2592
2599
|
}
|
|
2593
2600
|
actorRegistration(meshName, stableType) {
|
|
2594
|
-
const value = this.options.registration.spotNodes.get(meshName)
|
|
2595
|
-
?.actorFactoryRegistrations?.[stableType];
|
|
2601
|
+
const value = this.options.registration.spotNodes.get(meshName)?.actorFactoryRegistrations?.[stableType];
|
|
2596
2602
|
if (value === undefined)
|
|
2597
2603
|
throw new Error(`Relocation Actor type '${stableType}' is not registered.`);
|
|
2598
2604
|
return value;
|
|
@@ -2611,7 +2617,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2611
2617
|
return captured;
|
|
2612
2618
|
}
|
|
2613
2619
|
async createRelocationAdapter(adapterType) {
|
|
2614
|
-
return await (0, spot_provider_1.createProviderInstance)(adapterType, this.options.providerResolver);
|
|
2620
|
+
return (await (0, spot_provider_1.createProviderInstance)(adapterType, this.options.providerResolver));
|
|
2615
2621
|
}
|
|
2616
2622
|
recordRelocationInterruption(meshName, unitKind, executionMode, startedAt, outcome) {
|
|
2617
2623
|
const seconds = Math.max(0, performance.now() - startedAt) / 1000;
|
|
@@ -2623,9 +2629,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2623
2629
|
this.options.metrics?.count('zlink.relocation.completed', 1, {
|
|
2624
2630
|
mesh_name: meshName,
|
|
2625
2631
|
object_kind: unitKind,
|
|
2626
|
-
policy: unitKind === 'user_spot' && executionMode === 'per_actor'
|
|
2627
|
-
? 'recreate'
|
|
2628
|
-
: 'configured',
|
|
2632
|
+
policy: unitKind === 'user_spot' && executionMode === 'per_actor' ? 'recreate' : 'configured',
|
|
2629
2633
|
outcome
|
|
2630
2634
|
});
|
|
2631
2635
|
if (seconds <= 1)
|
|
@@ -2733,7 +2737,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2733
2737
|
// their framing nor turns a missing send into an immediate terminal:
|
|
2734
2738
|
// command 42 still owns its configured deadline while admission waits.
|
|
2735
2739
|
if (Array.isArray(record)) {
|
|
2736
|
-
return await node.sendToNode(targetNodeRid, record.map(frame => Buffer.from(frame)));
|
|
2740
|
+
return await node.sendToNode(targetNodeRid, record.map((frame) => Buffer.from(frame)));
|
|
2737
2741
|
}
|
|
2738
2742
|
return await node.sendToNode(targetNodeRid, Buffer.from(record));
|
|
2739
2743
|
}
|
|
@@ -2760,7 +2764,7 @@ class ZLinkHostServiceRelocationRuntime {
|
|
|
2760
2764
|
}
|
|
2761
2765
|
exports.ZLinkHostServiceRelocationRuntime = ZLinkHostServiceRelocationRuntime;
|
|
2762
2766
|
function canonicalActorJoinRecovery(participants) {
|
|
2763
|
-
const matches = participants.flatMap(participant => participant.queuedMessages.flatMap(message => {
|
|
2767
|
+
const matches = participants.flatMap((participant) => participant.queuedMessages.flatMap((message) => {
|
|
2764
2768
|
const recovery = (0, actor_join_recovery_codec_1.decodeCanonicalActorJoinRecoverySavedWork)(message.payload);
|
|
2765
2769
|
return recovery === undefined ? [] : [recovery];
|
|
2766
2770
|
}));
|
|
@@ -2770,23 +2774,24 @@ function canonicalActorJoinRecovery(participants) {
|
|
|
2770
2774
|
return matches[0];
|
|
2771
2775
|
}
|
|
2772
2776
|
function actorJoinAdmissionIdentity(envelope) {
|
|
2773
|
-
return canonicalActorJoinRecovery(envelope.participants)?.request.handoffId
|
|
2774
|
-
?? envelope.aggregateId;
|
|
2777
|
+
return (canonicalActorJoinRecovery(envelope.participants)?.request.handoffId ?? envelope.aggregateId);
|
|
2775
2778
|
}
|
|
2776
2779
|
function actorJoinTargetMembership(manager, relocationId, participants) {
|
|
2777
2780
|
const recovery = canonicalActorJoinRecovery(participants);
|
|
2778
2781
|
const admissionId = recovery?.request.handoffId ?? relocationId;
|
|
2779
2782
|
const admission = manager?.formalRemoteActorAdmissions?.get(admissionId);
|
|
2780
|
-
const actor = participants.find(value => value.objectKind === 'actor');
|
|
2783
|
+
const actor = participants.find((value) => value.objectKind === 'actor');
|
|
2781
2784
|
if (admission === undefined || actor === undefined) {
|
|
2782
2785
|
throw new Error(`Actor relocation '${relocationId}' has no accepted target membership.`);
|
|
2783
2786
|
}
|
|
2784
|
-
return [
|
|
2787
|
+
return [
|
|
2788
|
+
{
|
|
2785
2789
|
actorKey: actor.key,
|
|
2786
2790
|
spotKey: (0, authority_key_codec_1.encodeAuthorityKey)('user_spot', String(admission.admission.spotId)).value,
|
|
2787
2791
|
spotObjectGeneration: admission.admission.targetSpotGeneration,
|
|
2788
2792
|
membershipEpoch: admission.admission.expectedMembershipEpoch
|
|
2789
|
-
}
|
|
2793
|
+
}
|
|
2794
|
+
];
|
|
2790
2795
|
}
|
|
2791
2796
|
function relocationDebug(marker, detail) {
|
|
2792
2797
|
if (process.env.ZLINK_DEBUG_FRAMEWORK_RELOCATION !== '1')
|
|
@@ -2806,10 +2811,12 @@ class LocalTargetPort {
|
|
|
2806
2811
|
async createHidden(participant, signal) {
|
|
2807
2812
|
const identity = (0, authority_key_codec_1.decodeAuthorityKey)({ value: participant.key }).globalId;
|
|
2808
2813
|
if (participant.objectKind === 'actor') {
|
|
2809
|
-
const membership = this.envelope.memberships.find(value => value.actorKey === participant.key);
|
|
2814
|
+
const membership = this.envelope.memberships.find((value) => value.actorKey === participant.key);
|
|
2810
2815
|
if (membership === undefined)
|
|
2811
2816
|
throw new Error(`Actor '${identity}' relocation membership is missing.`);
|
|
2812
|
-
const spotIdentity = (0, authority_key_codec_1.decodeAuthorityKey)({
|
|
2817
|
+
const spotIdentity = (0, authority_key_codec_1.decodeAuthorityKey)({
|
|
2818
|
+
value: membership.spotKey
|
|
2819
|
+
}).globalId;
|
|
2813
2820
|
const localDescriptor = this.options.localDescriptor?.(this.meshName);
|
|
2814
2821
|
const nativeEntrySpot = localDescriptor?.entrySpotId === spotIdentity;
|
|
2815
2822
|
const actor = await this.requireActorManager().prepareRelocationActor(identity, participant.stableType, participant.objectGeneration, participant.authorityOwnerGeneration + 1n, (nativeEntrySpot ? localDescriptor.rid : spotIdentity), nativeEntrySpot ? localDescriptor.lifecycleGeneration : membership.spotObjectGeneration, membership.membershipEpoch, signal);
|
|
@@ -2845,16 +2852,18 @@ class LocalTargetPort {
|
|
|
2845
2852
|
if (registration.relocation.kind !== 'snapshot') {
|
|
2846
2853
|
throw new Error(`Relocation is disabled for '${hidden.participant.stableType}'.`);
|
|
2847
2854
|
}
|
|
2848
|
-
const adapter = await (0, spot_provider_1.createProviderInstance)(registration.relocation.adapterType, this.options.providerResolver);
|
|
2855
|
+
const adapter = (await (0, spot_provider_1.createProviderInstance)(registration.relocation.adapterType, this.options.providerResolver));
|
|
2849
2856
|
const instance = (hidden.actor ?? hidden.activation?.spot);
|
|
2850
2857
|
await (0, relocation_state_adapter_1.restoreRelocationAdapterState)(adapter, instance, payload, signal ?? new AbortController().signal);
|
|
2851
2858
|
}
|
|
2852
2859
|
async restoreMemberships(hidden, memberships) {
|
|
2853
2860
|
for (const membership of memberships) {
|
|
2854
2861
|
const actor = hidden.get(membership.actorKey)?.actor;
|
|
2855
|
-
const spotIdentity = (0, authority_key_codec_1.decodeAuthorityKey)({
|
|
2856
|
-
|
|
2857
|
-
|
|
2862
|
+
const spotIdentity = (0, authority_key_codec_1.decodeAuthorityKey)({
|
|
2863
|
+
value: membership.spotKey
|
|
2864
|
+
}).globalId;
|
|
2865
|
+
const spot = hidden.get(membership.spotKey)?.activation ??
|
|
2866
|
+
this.requireSpotManager().resolveRelocationActivation(this.meshName, spotIdentity);
|
|
2858
2867
|
if (actor === undefined)
|
|
2859
2868
|
throw new Error('Relocation membership Actor staging is missing.');
|
|
2860
2869
|
const state = this.requireActorManager().getState(actor.context.actorId);
|
|
@@ -2877,7 +2886,9 @@ class LocalTargetPort {
|
|
|
2877
2886
|
async publish(hidden, authority) {
|
|
2878
2887
|
if (hidden.actor !== undefined) {
|
|
2879
2888
|
const store = this.requireLocationStore();
|
|
2880
|
-
const current = await requireAuthority(store, {
|
|
2889
|
+
const current = await requireAuthority(store, {
|
|
2890
|
+
value: hidden.authorityKey
|
|
2891
|
+
});
|
|
2881
2892
|
const actorId = hidden.actor.context.actorId;
|
|
2882
2893
|
const node = this.options.meshNode(this.meshName);
|
|
2883
2894
|
const restore = node?.restoreActorAuthority;
|
|
@@ -2891,12 +2902,10 @@ class LocalTargetPort {
|
|
|
2891
2902
|
}
|
|
2892
2903
|
else if (hidden.activation !== undefined) {
|
|
2893
2904
|
const registration = this.registration(hidden.participant.objectKind, hidden.participant.stableType);
|
|
2894
|
-
const applicationSignaled = hidden.participant.objectKind === 'user_spot'
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
await this.requireSpotManager().publishRelocationSpot(hidden.activation, applicationSignaled
|
|
2898
|
-
? () => hidden.activation.notifyRelocatedBoundary()
|
|
2899
|
-
: undefined);
|
|
2905
|
+
const applicationSignaled = hidden.participant.objectKind === 'user_spot' &&
|
|
2906
|
+
registration.options?.relocationCoordinationMode ===
|
|
2907
|
+
contracts_1.ZLinkSpotRelocationCoordinationMode.ApplicationSignaled;
|
|
2908
|
+
await this.requireSpotManager().publishRelocationSpot(hidden.activation, applicationSignaled ? () => hidden.activation.notifyRelocatedBoundary() : undefined);
|
|
2900
2909
|
this.options.meshNode(this.meshName)?.rememberSpotRoute?.({
|
|
2901
2910
|
spot: {
|
|
2902
2911
|
spotId: String(hidden.activation.spotId),
|
|
@@ -2988,7 +2997,7 @@ class LocalTargetPort {
|
|
|
2988
2997
|
hidden.restoredTimers.push(timer);
|
|
2989
2998
|
if (hidden.restoredTimers.length !== hidden.participant.timers.length)
|
|
2990
2999
|
return;
|
|
2991
|
-
hidden.activation.timers.restoreRelocation(hidden.restoredTimers.map(value => ({
|
|
3000
|
+
hidden.activation.timers.restoreRelocation(hidden.restoredTimers.map((value) => ({
|
|
2992
3001
|
name: value.timerId,
|
|
2993
3002
|
handlerType: value.handlerType,
|
|
2994
3003
|
periodMs: value.intervalMs,
|
|
@@ -3058,11 +3067,10 @@ function rewriteAuthorityApplicationRoute(payload, target) {
|
|
|
3058
3067
|
nodeRid: target.nodeRid
|
|
3059
3068
|
}, target.actorSpotId ?? actor.spotId, target.actorSpotGeneration ?? actor.spotGeneration, target.actorSpotKind ?? actor.spotKind, target.nodeGeneration, target.owner);
|
|
3060
3069
|
}
|
|
3061
|
-
return (0, service_authority_payload_codec_1.rewriteServiceAuthorityRoute)(applicationPayload, target.owner, target)
|
|
3062
|
-
?? applicationPayload;
|
|
3070
|
+
return ((0, service_authority_payload_codec_1.rewriteServiceAuthorityRoute)(applicationPayload, target.owner, target) ?? applicationPayload);
|
|
3063
3071
|
}
|
|
3064
3072
|
function actorMembershipTarget(envelope, actorKey) {
|
|
3065
|
-
const membership = envelope.memberships.find(value => value.actorKey === actorKey);
|
|
3073
|
+
const membership = envelope.memberships.find((value) => value.actorKey === actorKey);
|
|
3066
3074
|
if (membership === undefined)
|
|
3067
3075
|
return undefined;
|
|
3068
3076
|
return {
|
|
@@ -3071,52 +3079,52 @@ function actorMembershipTarget(envelope, actorKey) {
|
|
|
3071
3079
|
};
|
|
3072
3080
|
}
|
|
3073
3081
|
function primaryKey(envelope) {
|
|
3074
|
-
return envelope.participants.find(value => value.objectKind !== 'actor')?.key
|
|
3075
|
-
|
|
3082
|
+
return (envelope.participants.find((value) => value.objectKind !== 'actor')?.key ??
|
|
3083
|
+
envelope.participants[0].key);
|
|
3076
3084
|
}
|
|
3077
3085
|
function relocationTargetRequirements(values) {
|
|
3078
3086
|
const grouped = new Map();
|
|
3079
3087
|
for (const value of values) {
|
|
3080
3088
|
const key = `${value.objectKind}\0${value.stableType}\0${value.policy}`;
|
|
3081
3089
|
const existing = grouped.get(key);
|
|
3082
|
-
grouped.set(key, existing === undefined
|
|
3083
|
-
? value
|
|
3084
|
-
: { ...existing, count: existing.count + value.count });
|
|
3090
|
+
grouped.set(key, existing === undefined ? value : { ...existing, count: existing.count + value.count });
|
|
3085
3091
|
}
|
|
3086
3092
|
return [...grouped.values()];
|
|
3087
3093
|
}
|
|
3088
3094
|
function relocationTargetSupports(descriptor, requirements) {
|
|
3089
|
-
if (descriptor.activationConcurrency.limit !== 0
|
|
3090
|
-
|
|
3095
|
+
if (descriptor.activationConcurrency.limit !== 0 &&
|
|
3096
|
+
descriptor.activationConcurrency.active >= descriptor.activationConcurrency.limit) {
|
|
3091
3097
|
return false;
|
|
3092
3098
|
}
|
|
3093
3099
|
const actorCount = requirements
|
|
3094
|
-
.filter(value => value.objectKind === 'actor')
|
|
3100
|
+
.filter((value) => value.objectKind === 'actor')
|
|
3095
3101
|
.reduce((sum, value) => sum + value.count, 0);
|
|
3096
3102
|
const spotCount = requirements
|
|
3097
|
-
.filter(value => value.objectKind !== 'actor')
|
|
3103
|
+
.filter((value) => value.objectKind !== 'actor')
|
|
3098
3104
|
.reduce((sum, value) => sum + value.count, 0);
|
|
3099
|
-
if ((descriptor.populationCapacity.actors.limit !== 0
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3105
|
+
if ((descriptor.populationCapacity.actors.limit !== 0 &&
|
|
3106
|
+
descriptor.populationCapacity.actors.active +
|
|
3107
|
+
descriptor.populationCapacity.actors.reserved +
|
|
3108
|
+
actorCount >
|
|
3109
|
+
descriptor.populationCapacity.actors.limit) ||
|
|
3110
|
+
(descriptor.populationCapacity.spots.limit !== 0 &&
|
|
3111
|
+
descriptor.populationCapacity.spots.active +
|
|
3112
|
+
descriptor.populationCapacity.spots.reserved +
|
|
3113
|
+
spotCount >
|
|
3114
|
+
descriptor.populationCapacity.spots.limit)) {
|
|
3106
3115
|
return false;
|
|
3107
3116
|
}
|
|
3108
3117
|
for (const requirement of requirements) {
|
|
3109
|
-
if (!descriptor.objectCapabilities.some(capability => capability.objectKind === requirement.objectKind
|
|
3110
|
-
|
|
3111
|
-
|
|
3118
|
+
if (!descriptor.objectCapabilities.some((capability) => capability.objectKind === requirement.objectKind &&
|
|
3119
|
+
capability.stableType === requirement.stableType &&
|
|
3120
|
+
capability.policy === requirement.policy)) {
|
|
3112
3121
|
return false;
|
|
3113
3122
|
}
|
|
3114
3123
|
if (requirement.objectKind !== 'actor') {
|
|
3115
|
-
const capacity = descriptor.populationCapacity.spotTypes.find(value => value.objectKind === requirement.objectKind
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
&& capacity.active + capacity.reserved + requirement.count > capacity.limit)) {
|
|
3124
|
+
const capacity = descriptor.populationCapacity.spotTypes.find((value) => value.objectKind === requirement.objectKind && value.stableType === requirement.stableType);
|
|
3125
|
+
if (capacity === undefined ||
|
|
3126
|
+
(capacity.limit !== 0 &&
|
|
3127
|
+
capacity.active + capacity.reserved + requirement.count > capacity.limit)) {
|
|
3120
3128
|
return false;
|
|
3121
3129
|
}
|
|
3122
3130
|
}
|
|
@@ -3146,11 +3154,13 @@ function decodeQueuedHandoffPacket(message) {
|
|
|
3146
3154
|
throw new TypeError('Relocation Actor packet index is invalid.');
|
|
3147
3155
|
}
|
|
3148
3156
|
const messageFollowOrigin = decodeQueuedMessageFollowOrigin(value.messageFollowOrigin);
|
|
3149
|
-
const decoded = (0, spot_remote_codec_1.decodeHandoffBacklog)([
|
|
3157
|
+
const decoded = (0, spot_remote_codec_1.decodeHandoffBacklog)([
|
|
3158
|
+
{
|
|
3150
3159
|
...value,
|
|
3151
3160
|
index: 0,
|
|
3152
3161
|
...(messageFollowOrigin === undefined ? {} : { messageFollowOrigin })
|
|
3153
|
-
}
|
|
3162
|
+
}
|
|
3163
|
+
])[0];
|
|
3154
3164
|
return { ...decoded, index: index };
|
|
3155
3165
|
}
|
|
3156
3166
|
/**
|
|
@@ -3162,13 +3172,14 @@ function decodeQueuedHandoffPacket(message) {
|
|
|
3162
3172
|
function canonicalizeCapturedHandoffBacklog(envelope, coordinator, target) {
|
|
3163
3173
|
return {
|
|
3164
3174
|
...envelope,
|
|
3165
|
-
participants: envelope.participants.map(participant => participant.objectKind !== 'actor'
|
|
3175
|
+
participants: envelope.participants.map((participant) => participant.objectKind !== 'actor'
|
|
3166
3176
|
? participant
|
|
3167
3177
|
: {
|
|
3168
3178
|
...participant,
|
|
3169
|
-
queuedMessages: participant.queuedMessages.map(message => ({
|
|
3179
|
+
queuedMessages: participant.queuedMessages.map((message) => ({
|
|
3170
3180
|
...message,
|
|
3171
|
-
payload: canonicalQueuedFrozenRecord(participant, message, coordinator, target)
|
|
3181
|
+
payload: canonicalQueuedFrozenRecord(participant, message, coordinator, target)
|
|
3182
|
+
.canonicalBytes
|
|
3172
3183
|
}))
|
|
3173
3184
|
})
|
|
3174
3185
|
};
|
|
@@ -3177,20 +3188,20 @@ function appendCanonicalActorJoinRecovery(envelope, profile, coordinator, source
|
|
|
3177
3188
|
const recovery = profile.canonicalRecovery;
|
|
3178
3189
|
const actorType = profile.state.actorType;
|
|
3179
3190
|
const sourceAuthority = (0, actor_authority_publication_1.decodeRelocatingActorAuthorityIdentity)(sourceAuthoritySnapshot.payload, sourceAuthoritySnapshot.objectGeneration);
|
|
3180
|
-
if (actorType === undefined
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3191
|
+
if (actorType === undefined ||
|
|
3192
|
+
sourceAuthority === undefined ||
|
|
3193
|
+
sourceAuthority.actor.actorId !== profile.state.actorId ||
|
|
3194
|
+
sourceAuthority.actor.objectGeneration !== profile.sourceActorRef.generation ||
|
|
3195
|
+
!(0, routing_id_1.routingIdsEqual)(sourceAuthority.actor.nodeRid, profile.sourceActorRef.nodeRid) ||
|
|
3196
|
+
sourceAuthority.ownerNodeGeneration !== recovery.actorNodeGeneration ||
|
|
3197
|
+
sourceAuthoritySnapshot.authorityOwnerGeneration !== profile.state.locationGeneration) {
|
|
3187
3198
|
throw new Error(`Actor '${profile.state.actorId}' canonical Join recovery identity is incomplete.`);
|
|
3188
3199
|
}
|
|
3189
3200
|
const attachment = { attached: false };
|
|
3190
|
-
const participants = envelope.participants.map(participant => {
|
|
3191
|
-
if (participant.objectKind !== 'actor'
|
|
3192
|
-
|
|
3193
|
-
|
|
3201
|
+
const participants = envelope.participants.map((participant) => {
|
|
3202
|
+
if (participant.objectKind !== 'actor' ||
|
|
3203
|
+
(0, authority_key_codec_1.decodeAuthorityKey)({ value: participant.key }).globalId !==
|
|
3204
|
+
profile.state.actorId) {
|
|
3194
3205
|
return participant;
|
|
3195
3206
|
}
|
|
3196
3207
|
if (attachment.attached)
|
|
@@ -3236,7 +3247,7 @@ function appendCanonicalActorJoinRecovery(envelope, profile, coordinator, source
|
|
|
3236
3247
|
...participant,
|
|
3237
3248
|
queuedMessages: [
|
|
3238
3249
|
{ sequence: 1n, payload: encoded },
|
|
3239
|
-
...participant.queuedMessages.map(message => ({
|
|
3250
|
+
...participant.queuedMessages.map((message) => ({
|
|
3240
3251
|
...message,
|
|
3241
3252
|
sequence: message.sequence + 1n
|
|
3242
3253
|
}))
|
|
@@ -3286,8 +3297,8 @@ function createServiceRelocationId(isInUse, entropy = node_crypto_1.randomBytes)
|
|
|
3286
3297
|
if (!nonZero)
|
|
3287
3298
|
continue;
|
|
3288
3299
|
const hex = Buffer.from(bytes).toString('hex');
|
|
3289
|
-
const candidate = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-`
|
|
3290
|
-
|
|
3300
|
+
const candidate = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-` +
|
|
3301
|
+
`${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
3291
3302
|
if (!isInUse(candidate))
|
|
3292
3303
|
return candidate;
|
|
3293
3304
|
}
|
|
@@ -3306,34 +3317,33 @@ function sameWireId(left, right) {
|
|
|
3306
3317
|
return left.high === right.high && left.low === right.low;
|
|
3307
3318
|
}
|
|
3308
3319
|
function sameCoordinator(left, right) {
|
|
3309
|
-
return left.ownerId === right.ownerId
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3320
|
+
return (left.ownerId === right.ownerId &&
|
|
3321
|
+
left.leaseGeneration === right.leaseGeneration &&
|
|
3322
|
+
left.nodeRid === right.nodeRid &&
|
|
3323
|
+
left.nodeGeneration === right.nodeGeneration &&
|
|
3324
|
+
left.expectedAuthorityStoreVersion === right.expectedAuthorityStoreVersion);
|
|
3314
3325
|
}
|
|
3315
3326
|
function isExactSourceAuthority(current, expected) {
|
|
3316
|
-
return current.storeVersion.value === expected.storeVersion.value
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
=== expected.allocation.descriptorLifecycleGeneration;
|
|
3327
|
+
return (current.storeVersion.value === expected.storeVersion.value &&
|
|
3328
|
+
current.objectGeneration === expected.objectGeneration &&
|
|
3329
|
+
current.authorityOwnerGeneration === expected.authorityOwnerGeneration &&
|
|
3330
|
+
current.ownerId === expected.ownerId &&
|
|
3331
|
+
current.ownerLeaseGeneration === expected.ownerLeaseGeneration &&
|
|
3332
|
+
current.allocation.state === expected.allocation.state &&
|
|
3333
|
+
current.allocation.objectKind === expected.allocation.objectKind &&
|
|
3334
|
+
current.allocation.stableType === expected.allocation.stableType &&
|
|
3335
|
+
String(current.allocation.descriptor.rid) === String(expected.allocation.descriptor.rid) &&
|
|
3336
|
+
current.allocation.descriptorLifecycleGeneration ===
|
|
3337
|
+
expected.allocation.descriptorLifecycleGeneration);
|
|
3328
3338
|
}
|
|
3329
3339
|
function isExactCommittedTarget(current, expected, target, payload) {
|
|
3330
|
-
return current.objectGeneration === expected.objectGeneration
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3340
|
+
return (current.objectGeneration === expected.objectGeneration &&
|
|
3341
|
+
current.authorityOwnerGeneration > expected.authorityOwnerGeneration &&
|
|
3342
|
+
current.ownerId === target.ownerId &&
|
|
3343
|
+
current.ownerLeaseGeneration === target.ownerLeaseGeneration &&
|
|
3344
|
+
String(current.allocation.descriptor.rid) === target.nodeRid &&
|
|
3345
|
+
current.allocation.descriptorLifecycleGeneration === target.nodeGeneration &&
|
|
3346
|
+
Buffer.from(current.payload).equals(Buffer.from(payload)));
|
|
3337
3347
|
}
|
|
3338
3348
|
async function waitForLocationRetry(deadlineAtMs, signal, cause) {
|
|
3339
3349
|
signal?.throwIfAborted();
|
|
@@ -3373,10 +3383,10 @@ async function waitForRelocationRetry(delayMs, signal) {
|
|
|
3373
3383
|
});
|
|
3374
3384
|
}
|
|
3375
3385
|
function sameRequestSource(left, right) {
|
|
3376
|
-
return left.ownerId === right.ownerId
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3386
|
+
return (left.ownerId === right.ownerId &&
|
|
3387
|
+
left.leaseGeneration === right.leaseGeneration &&
|
|
3388
|
+
left.nodeRid === right.nodeRid &&
|
|
3389
|
+
left.nodeGeneration === right.nodeGeneration);
|
|
3380
3390
|
}
|
|
3381
3391
|
function handoffSourceFence(value) {
|
|
3382
3392
|
return {
|
|
@@ -3398,11 +3408,15 @@ function maintenanceReplyRelay(stage, coordinator, participantId, completion) {
|
|
|
3398
3408
|
sequence: BigInt(completion.index + 1),
|
|
3399
3409
|
terminalResult: completion.result.ok ? 0 : 105,
|
|
3400
3410
|
failureCode: completion.result.ok ? 0 : 17,
|
|
3401
|
-
...(value === undefined
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3411
|
+
...(value === undefined
|
|
3412
|
+
? {}
|
|
3413
|
+
: {
|
|
3414
|
+
payload: {
|
|
3415
|
+
packetName: 'zlink.relocation.reply',
|
|
3416
|
+
contentType: 'application/json',
|
|
3417
|
+
bytes: Buffer.from(JSON.stringify(value), 'utf8')
|
|
3418
|
+
}
|
|
3419
|
+
})
|
|
3406
3420
|
};
|
|
3407
3421
|
}
|
|
3408
3422
|
function handoffResultFromRelay(relay) {
|
|
@@ -3411,9 +3425,9 @@ function handoffResultFromRelay(relay) {
|
|
|
3411
3425
|
}
|
|
3412
3426
|
let value;
|
|
3413
3427
|
if (relay.payload !== undefined) {
|
|
3414
|
-
if (relay.terminalResult !== 0
|
|
3415
|
-
|
|
3416
|
-
|
|
3428
|
+
if (relay.terminalResult !== 0 ||
|
|
3429
|
+
relay.payload.packetName !== 'zlink.relocation.reply' ||
|
|
3430
|
+
relay.payload.contentType !== 'application/json') {
|
|
3417
3431
|
throw new TypeError('Relocation terminal payload boundary is invalid.');
|
|
3418
3432
|
}
|
|
3419
3433
|
value = JSON.parse(Buffer.from(relay.payload.bytes).toString('utf8'));
|
|
@@ -3506,23 +3520,39 @@ function relocationStagingId(value) {
|
|
|
3506
3520
|
return `${value.relocation.high}:${value.relocation.low}:${value.targetAttemptGeneration}`;
|
|
3507
3521
|
}
|
|
3508
3522
|
function coordinatorSource(value) {
|
|
3509
|
-
return {
|
|
3510
|
-
|
|
3523
|
+
return {
|
|
3524
|
+
ownerId: value.ownerId,
|
|
3525
|
+
leaseGeneration: value.leaseGeneration,
|
|
3526
|
+
nodeRid: value.nodeRid,
|
|
3527
|
+
nodeGeneration: value.nodeGeneration
|
|
3528
|
+
};
|
|
3511
3529
|
}
|
|
3512
3530
|
function relocationObject(envelope) {
|
|
3513
|
-
const participant = envelope.participants.find(value => value.objectKind !== 'actor')
|
|
3514
|
-
|
|
3531
|
+
const participant = envelope.participants.find((value) => value.objectKind !== 'actor') ??
|
|
3532
|
+
envelope.participants[0];
|
|
3515
3533
|
const identity = (0, authority_key_codec_1.decodeAuthorityKey)({ value: participant.key }).globalId;
|
|
3516
3534
|
if (participant.objectKind === 'actor') {
|
|
3517
|
-
return {
|
|
3518
|
-
|
|
3535
|
+
return {
|
|
3536
|
+
kind: 'actor',
|
|
3537
|
+
actorId: identity,
|
|
3538
|
+
objectGeneration: participant.objectGeneration,
|
|
3539
|
+
expectedAuthorityOwnerGeneration: participant.authorityOwnerGeneration
|
|
3540
|
+
};
|
|
3519
3541
|
}
|
|
3520
3542
|
if (participant.objectKind === 'user_spot') {
|
|
3521
|
-
return {
|
|
3522
|
-
|
|
3543
|
+
return {
|
|
3544
|
+
kind: 'userSpot',
|
|
3545
|
+
spotId: identity,
|
|
3546
|
+
objectGeneration: participant.objectGeneration,
|
|
3547
|
+
expectedAuthorityOwnerGeneration: participant.authorityOwnerGeneration
|
|
3548
|
+
};
|
|
3523
3549
|
}
|
|
3524
|
-
return {
|
|
3525
|
-
|
|
3550
|
+
return {
|
|
3551
|
+
kind: 'instanceSpot',
|
|
3552
|
+
stableType: participant.stableType,
|
|
3553
|
+
spotId: identity,
|
|
3554
|
+
objectGeneration: participant.objectGeneration
|
|
3555
|
+
};
|
|
3526
3556
|
}
|
|
3527
3557
|
function relocationObjectForParticipant(participant) {
|
|
3528
3558
|
const identity = (0, authority_key_codec_1.decodeAuthorityKey)({ value: participant.key }).globalId;
|
|
@@ -3573,23 +3603,24 @@ function relocationFailed(request, failureCode) {
|
|
|
3573
3603
|
};
|
|
3574
3604
|
}
|
|
3575
3605
|
function validatePrepareEnvelope(request, envelope) {
|
|
3576
|
-
if (!sameWireId(request.relocation, relocationWireId(envelope.aggregateId))
|
|
3577
|
-
|
|
3578
|
-
|
|
3606
|
+
if (!sameWireId(request.relocation, relocationWireId(envelope.aggregateId)) ||
|
|
3607
|
+
request.applicationVersion !== envelope.applicationVersion ||
|
|
3608
|
+
stringifyWire(request.object) !== stringifyWire(relocationObject(envelope))) {
|
|
3579
3609
|
throw new Error('Relocation Prepare does not match its immutable root identity.');
|
|
3580
3610
|
}
|
|
3581
3611
|
}
|
|
3582
3612
|
function validateTargetOneWayControl(stage, request, sourceNodeRid) {
|
|
3583
3613
|
const prepare = stage.offer.prepare;
|
|
3584
|
-
if (String(sourceNodeRid) !== stage.offer.authenticatedSourceNodeRid
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3614
|
+
if (String(sourceNodeRid) !== stage.offer.authenticatedSourceNodeRid ||
|
|
3615
|
+
!sameWireId(request.relocation, prepare.relocation) ||
|
|
3616
|
+
request.targetAttemptGeneration !== prepare.targetAttemptGeneration ||
|
|
3617
|
+
!sameCoordinator(request.coordinator, prepare.coordinator) ||
|
|
3618
|
+
stringifyWire(request.object) !==
|
|
3619
|
+
stringifyWire(request.kind === 'data' ? request.object : prepare.object)) {
|
|
3589
3620
|
throw new Error('Relocation one-way control changed its exact Prepare fence.');
|
|
3590
3621
|
}
|
|
3591
|
-
if (request.kind === 'cutover'
|
|
3592
|
-
|
|
3622
|
+
if (request.kind === 'cutover' &&
|
|
3623
|
+
stringifyWire(request.object) !== stringifyWire(prepare.object)) {
|
|
3593
3624
|
throw new Error('Relocation Cutover changed its prepared object.');
|
|
3594
3625
|
}
|
|
3595
3626
|
}
|
|
@@ -3625,10 +3656,10 @@ function raceAbort(operation, signal) {
|
|
|
3625
3656
|
return new Promise((resolve, reject) => {
|
|
3626
3657
|
const aborted = () => reject(signal.reason);
|
|
3627
3658
|
signal.addEventListener('abort', aborted, { once: true });
|
|
3628
|
-
operation.then(value => {
|
|
3659
|
+
operation.then((value) => {
|
|
3629
3660
|
signal.removeEventListener('abort', aborted);
|
|
3630
3661
|
resolve(value);
|
|
3631
|
-
}, error => {
|
|
3662
|
+
}, (error) => {
|
|
3632
3663
|
signal.removeEventListener('abort', aborted);
|
|
3633
3664
|
reject(error);
|
|
3634
3665
|
});
|
|
@@ -3652,8 +3683,9 @@ function canonicalQueuedFrozenRecord(participant, message, coordinator, target)
|
|
|
3652
3683
|
if (packet.returnResponse && packet.source === undefined) {
|
|
3653
3684
|
throw new Error('Captured Actor request has no exact request-source fence.');
|
|
3654
3685
|
}
|
|
3655
|
-
if (!packet.returnResponse &&
|
|
3656
|
-
|
|
3686
|
+
if (!packet.returnResponse &&
|
|
3687
|
+
packet.source === undefined &&
|
|
3688
|
+
packet.remoteBoundSessionTarget !== undefined) {
|
|
3657
3689
|
// A durable frozen record is permitted only for a lease-backed source.
|
|
3658
3690
|
// Work tied to a Session connection's lifetime drains before Captured,
|
|
3659
3691
|
// so freezing it under the coordinator's fence is a protocol error.
|
|
@@ -3692,17 +3724,17 @@ function parseHandoffOperationId(value) {
|
|
|
3692
3724
|
return operation;
|
|
3693
3725
|
}
|
|
3694
3726
|
function stringifyWire(value) {
|
|
3695
|
-
return JSON.stringify(value, (_key, item) => typeof item === 'bigint' ? item.toString() : item);
|
|
3727
|
+
return JSON.stringify(value, (_key, item) => (typeof item === 'bigint' ? item.toString() : item));
|
|
3696
3728
|
}
|
|
3697
3729
|
function validateControlResponse(request, response) {
|
|
3698
|
-
if (request.kind !== 'prepare'
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3730
|
+
if (request.kind !== 'prepare' ||
|
|
3731
|
+
response.kind !== 'ready' ||
|
|
3732
|
+
!sameWireId(response.relocation, request.relocation) ||
|
|
3733
|
+
response.targetAttemptGeneration !== request.targetAttemptGeneration ||
|
|
3734
|
+
!sameCoordinator(response.coordinator, request.coordinator) ||
|
|
3735
|
+
stringifyWire(response.target) !== stringifyWire(request.target) ||
|
|
3736
|
+
stringifyWire(response.object) !== stringifyWire(request.object) ||
|
|
3737
|
+
response.senderRole !== 'target') {
|
|
3706
3738
|
throw new Error('Relocation control response does not match the request fence.');
|
|
3707
3739
|
}
|
|
3708
3740
|
}
|
|
@@ -3713,14 +3745,14 @@ function validateControlResponse(request, response) {
|
|
|
3713
3745
|
* pending Prepare's ACK.
|
|
3714
3746
|
*/
|
|
3715
3747
|
function validateControlFailureResponse(request, response) {
|
|
3716
|
-
if (request.kind !== 'prepare'
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3748
|
+
if (request.kind !== 'prepare' ||
|
|
3749
|
+
response.kind !== 'failed' ||
|
|
3750
|
+
!sameWireId(response.relocation, request.relocation) ||
|
|
3751
|
+
response.targetAttemptGeneration !== request.targetAttemptGeneration ||
|
|
3752
|
+
!sameCoordinator(response.coordinator, request.coordinator) ||
|
|
3753
|
+
stringifyWire(response.target) !== stringifyWire(request.target) ||
|
|
3754
|
+
stringifyWire(response.object) !== stringifyWire(request.object) ||
|
|
3755
|
+
response.senderRole !== 'target') {
|
|
3724
3756
|
throw new Error('Relocation control response does not match the request fence.');
|
|
3725
3757
|
}
|
|
3726
3758
|
}
|
|
@@ -3734,30 +3766,54 @@ function validateControlFailureResponse(request, response) {
|
|
|
3734
3766
|
*/
|
|
3735
3767
|
function relocationFailureCodeKind(failureCode) {
|
|
3736
3768
|
switch (failureCode) {
|
|
3737
|
-
case 1:
|
|
3738
|
-
|
|
3739
|
-
case
|
|
3740
|
-
|
|
3741
|
-
case
|
|
3742
|
-
|
|
3743
|
-
case
|
|
3744
|
-
|
|
3745
|
-
case
|
|
3746
|
-
|
|
3747
|
-
case
|
|
3748
|
-
|
|
3749
|
-
case
|
|
3750
|
-
|
|
3751
|
-
case
|
|
3752
|
-
|
|
3753
|
-
case
|
|
3754
|
-
|
|
3755
|
-
case
|
|
3756
|
-
|
|
3757
|
-
case
|
|
3758
|
-
|
|
3759
|
-
case
|
|
3760
|
-
|
|
3769
|
+
case 1:
|
|
3770
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorRouteNotFound;
|
|
3771
|
+
case 2:
|
|
3772
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorCreateFailed;
|
|
3773
|
+
case 3:
|
|
3774
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorAlreadyExists;
|
|
3775
|
+
case 4:
|
|
3776
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorTypeMismatch;
|
|
3777
|
+
case 5:
|
|
3778
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotCreateFailed;
|
|
3779
|
+
case 6:
|
|
3780
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotRouteNotFound;
|
|
3781
|
+
case 7:
|
|
3782
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotTypeMismatch;
|
|
3783
|
+
case 8:
|
|
3784
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound;
|
|
3785
|
+
case 9:
|
|
3786
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.HandlerNotFound;
|
|
3787
|
+
case 10:
|
|
3788
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteHandlerNotFound;
|
|
3789
|
+
case 11:
|
|
3790
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorDispatchHandlerNotFound;
|
|
3791
|
+
case 12:
|
|
3792
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.PayloadDecodeFailed;
|
|
3793
|
+
case 13:
|
|
3794
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected;
|
|
3795
|
+
case 14:
|
|
3796
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestTargetNotFound;
|
|
3797
|
+
case 15:
|
|
3798
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestRejected;
|
|
3799
|
+
case 16:
|
|
3800
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestProtocolError;
|
|
3801
|
+
case 18:
|
|
3802
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.WorkerQueueFull;
|
|
3803
|
+
case 19:
|
|
3804
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.WorkerTimedOut;
|
|
3805
|
+
case 20:
|
|
3806
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.WorkerFailed;
|
|
3807
|
+
case 21:
|
|
3808
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale;
|
|
3809
|
+
case 22:
|
|
3810
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorCreateRejected;
|
|
3811
|
+
case 33:
|
|
3812
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotGenerationStale;
|
|
3813
|
+
case 34:
|
|
3814
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving;
|
|
3815
|
+
case 35:
|
|
3816
|
+
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RelocationDataLost;
|
|
3761
3817
|
case 17:
|
|
3762
3818
|
default:
|
|
3763
3819
|
return framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RequestFailed;
|
|
@@ -3765,15 +3821,15 @@ function relocationFailureCodeKind(failureCode) {
|
|
|
3765
3821
|
}
|
|
3766
3822
|
/** Builds the typed exception a Prepare waiter rejects with on an explicit Failed(53). */
|
|
3767
3823
|
function relocationFailureException(response) {
|
|
3768
|
-
return (0, framework_errors_internal_1.createInternalFrameworkException)(relocationFailureCodeKind(response.failureCode), `Relocation '${response.relocation.high}:${response.relocation.low}:`
|
|
3769
|
-
|
|
3824
|
+
return (0, framework_errors_internal_1.createInternalFrameworkException)(relocationFailureCodeKind(response.failureCode), `Relocation '${response.relocation.high}:${response.relocation.low}:` +
|
|
3825
|
+
`${response.targetAttemptGeneration}' failed with wire failureCode ${response.failureCode}.`, true);
|
|
3770
3826
|
}
|
|
3771
3827
|
function controlAckKey(request) {
|
|
3772
3828
|
if (request.kind !== 'prepare') {
|
|
3773
3829
|
throw new Error(`Relocation ${request.kind} is one-way and has no response key.`);
|
|
3774
3830
|
}
|
|
3775
|
-
return `relocation:${request.relocation.high}:${request.relocation.low}:`
|
|
3776
|
-
|
|
3831
|
+
return (`relocation:${request.relocation.high}:${request.relocation.low}:` +
|
|
3832
|
+
`${request.targetAttemptGeneration}:ready`);
|
|
3777
3833
|
}
|
|
3778
3834
|
function sessionRelocationPendingKey(request) {
|
|
3779
3835
|
return sessionRelocationIdentityKey(request);
|
|
@@ -3791,32 +3847,30 @@ function sessionRelocationIdentityKey(value) {
|
|
|
3791
3847
|
return `session-relocation:${(0, service_stateful_wire_codec_1.serviceSessionRelocationIdentityKey)(value)}:sealed`;
|
|
3792
3848
|
}
|
|
3793
3849
|
function validateSessionRelocationResponse(request, response) {
|
|
3794
|
-
const sameCoordinator = request.coordinator.ownerId === response.coordinator.ownerId
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
const sameSession = request.session.sessionOwnerNodeRid === response.session.sessionOwnerNodeRid
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|| !sameCoordinator
|
|
3811
|
-
|| !sameSession) {
|
|
3850
|
+
const sameCoordinator = request.coordinator.ownerId === response.coordinator.ownerId &&
|
|
3851
|
+
request.coordinator.leaseGeneration === response.coordinator.leaseGeneration &&
|
|
3852
|
+
request.coordinator.nodeRid === response.coordinator.nodeRid &&
|
|
3853
|
+
request.coordinator.nodeGeneration === response.coordinator.nodeGeneration &&
|
|
3854
|
+
request.coordinator.expectedAuthorityStoreVersion ===
|
|
3855
|
+
response.coordinator.expectedAuthorityStoreVersion;
|
|
3856
|
+
const sameSession = request.session.sessionOwnerNodeRid === response.session.sessionOwnerNodeRid &&
|
|
3857
|
+
request.session.sessionOwnerNodeGeneration === response.session.sessionOwnerNodeGeneration &&
|
|
3858
|
+
request.session.sessionOwnerId === response.session.sessionOwnerId &&
|
|
3859
|
+
request.session.sessionOwnerLeaseGeneration === response.session.sessionOwnerLeaseGeneration &&
|
|
3860
|
+
request.session.sessionRid === response.session.sessionRid &&
|
|
3861
|
+
request.session.bindingGeneration === response.session.bindingGeneration;
|
|
3862
|
+
if (request.relocation.high !== response.relocation.high ||
|
|
3863
|
+
request.relocation.low !== response.relocation.low ||
|
|
3864
|
+
!sameCoordinator ||
|
|
3865
|
+
!sameSession) {
|
|
3812
3866
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Session relocation ACK changed its exact fence.');
|
|
3813
3867
|
}
|
|
3814
|
-
if (request.actor.actor.actorId !== response.actor.actor.actorId
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3868
|
+
if (request.actor.actor.actorId !== response.actor.actor.actorId ||
|
|
3869
|
+
request.actor.actor.generation !== response.actor.actor.generation ||
|
|
3870
|
+
request.actor.actor.nodeRid !== response.actor.actor.nodeRid ||
|
|
3871
|
+
request.actor.targetNodeGeneration !== response.actor.targetNodeGeneration ||
|
|
3872
|
+
request.actor.authorityOwnerGeneration !== response.actor.authorityOwnerGeneration ||
|
|
3873
|
+
request.actor.ownerLeaseGeneration !== response.actor.ownerLeaseGeneration) {
|
|
3820
3874
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError('Command 43 ACK does not echo command 42.');
|
|
3821
3875
|
}
|
|
3822
3876
|
}
|
|
@@ -3838,26 +3892,30 @@ function replyRelayPendingKey(ackTargetNodeRid, value) {
|
|
|
3838
3892
|
return JSON.stringify([ackTargetNodeRid, replyRelayIdentityKey(value)]);
|
|
3839
3893
|
}
|
|
3840
3894
|
function isServiceWireCommand(payload, command) {
|
|
3841
|
-
return payload.byteLength >= 5
|
|
3842
|
-
|
|
3843
|
-
|
|
3895
|
+
return (payload.byteLength >= 5 &&
|
|
3896
|
+
payload[0] === 0x5a &&
|
|
3897
|
+
payload[1] === 0x4d &&
|
|
3898
|
+
payload[2] === 1 &&
|
|
3899
|
+
payload[3] === command);
|
|
3844
3900
|
}
|
|
3845
3901
|
function encodeHandoffQueuedMessages(backlog) {
|
|
3846
|
-
return backlog.map(packet => ({
|
|
3902
|
+
return backlog.map((packet) => ({
|
|
3847
3903
|
sequence: BigInt(packet.index) + 1n,
|
|
3848
3904
|
payload: Buffer.from(JSON.stringify({
|
|
3849
3905
|
...packet,
|
|
3850
|
-
...(packet.messageFollowOrigin === undefined
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3906
|
+
...(packet.messageFollowOrigin === undefined
|
|
3907
|
+
? {}
|
|
3908
|
+
: {
|
|
3909
|
+
messageFollowOrigin: {
|
|
3910
|
+
sourceNodeRid: String(packet.messageFollowOrigin.sourceNodeRid),
|
|
3911
|
+
sourceNodeRidHex: (0, routing_id_1.encodeRoutingIdStorageHex)(packet.messageFollowOrigin.sourceNodeRid),
|
|
3912
|
+
originalOperation: {
|
|
3913
|
+
high: packet.messageFollowOrigin.originalOperation.high.toString(),
|
|
3914
|
+
low: packet.messageFollowOrigin.originalOperation.low.toString()
|
|
3915
|
+
},
|
|
3916
|
+
originalReplyRouteId: packet.messageFollowOrigin.originalReplyRouteId.toString()
|
|
3917
|
+
}
|
|
3918
|
+
})
|
|
3861
3919
|
}), 'utf8')
|
|
3862
3920
|
}));
|
|
3863
3921
|
}
|
|
@@ -3869,10 +3927,10 @@ function decodeQueuedMessageFollowOrigin(value) {
|
|
|
3869
3927
|
}
|
|
3870
3928
|
const origin = value;
|
|
3871
3929
|
const operation = origin.originalOperation;
|
|
3872
|
-
if (typeof origin.sourceNodeRid !== 'string'
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3930
|
+
if (typeof origin.sourceNodeRid !== 'string' ||
|
|
3931
|
+
origin.sourceNodeRid.length === 0 ||
|
|
3932
|
+
typeof operation !== 'object' ||
|
|
3933
|
+
operation === null) {
|
|
3876
3934
|
throw new TypeError('Relocation Actor Message Follow origin is invalid.');
|
|
3877
3935
|
}
|
|
3878
3936
|
const operationRecord = operation;
|
|
@@ -3920,8 +3978,8 @@ function toServiceTimer(value) {
|
|
|
3920
3978
|
*/
|
|
3921
3979
|
function encodePrepareSideband(envelope) {
|
|
3922
3980
|
return envelope.participants
|
|
3923
|
-
.filter(participant => participant.boundSessionState.byteLength !== 0)
|
|
3924
|
-
.map(participant => {
|
|
3981
|
+
.filter((participant) => participant.boundSessionState.byteLength !== 0)
|
|
3982
|
+
.map((participant) => {
|
|
3925
3983
|
const key = Buffer.from(participant.key, 'utf8');
|
|
3926
3984
|
const payload = Buffer.from(participant.boundSessionState);
|
|
3927
3985
|
if (key.byteLength === 0 || key.byteLength > 0xffff || payload.byteLength > 0xffff_ffff) {
|
|
@@ -3940,7 +3998,9 @@ function decodePrepareSideband(frames) {
|
|
|
3940
3998
|
const keys = new Set();
|
|
3941
3999
|
for (const frame of frames) {
|
|
3942
4000
|
const bytes = Buffer.from(frame);
|
|
3943
|
-
if (bytes.byteLength < 11 ||
|
|
4001
|
+
if (bytes.byteLength < 11 ||
|
|
4002
|
+
bytes.subarray(0, 4).toString('ascii') !== 'ZLNI' ||
|
|
4003
|
+
bytes[4] !== 1) {
|
|
3944
4004
|
return undefined;
|
|
3945
4005
|
}
|
|
3946
4006
|
const keyLength = bytes.readUInt16BE(5);
|
|
@@ -3958,8 +4018,8 @@ function decodePrepareSideband(frames) {
|
|
|
3958
4018
|
function attachPrepareBoundSessions(envelope, sideband) {
|
|
3959
4019
|
if (sideband === undefined || sideband.length === 0)
|
|
3960
4020
|
return envelope;
|
|
3961
|
-
const byKey = new Map(sideband.map(value => [value.participantKey, Buffer.from(value.payload)]));
|
|
3962
|
-
const participants = envelope.participants.map(participant => {
|
|
4021
|
+
const byKey = new Map(sideband.map((value) => [value.participantKey, Buffer.from(value.payload)]));
|
|
4022
|
+
const participants = envelope.participants.map((participant) => {
|
|
3963
4023
|
const payload = byKey.get(participant.key);
|
|
3964
4024
|
if (payload === undefined)
|
|
3965
4025
|
return participant;
|
|
@@ -4008,11 +4068,11 @@ function encodeActorSession(target) {
|
|
|
4008
4068
|
}
|
|
4009
4069
|
function decodeActorSession(payload) {
|
|
4010
4070
|
const value = JSON.parse(Buffer.from(payload).toString('utf8'));
|
|
4011
|
-
const optionalBigInt = (field) => typeof value[field] === 'string'
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4071
|
+
const optionalBigInt = (field) => typeof value[field] === 'string' ? BigInt(value[field]) : undefined;
|
|
4072
|
+
if (value.version !== 1 ||
|
|
4073
|
+
typeof value.routerChannelId !== 'string' ||
|
|
4074
|
+
typeof value.targetNodeRid !== 'string' ||
|
|
4075
|
+
typeof value.spotId !== 'string') {
|
|
4016
4076
|
throw new TypeError('Actor relocation Session journal is invalid.');
|
|
4017
4077
|
}
|
|
4018
4078
|
const serviceWire = decodeActorSessionServiceWireFence(value.serviceWireRelocation);
|
|
@@ -4020,12 +4080,22 @@ function decodeActorSession(payload) {
|
|
|
4020
4080
|
routerChannelId: value.routerChannelId,
|
|
4021
4081
|
targetNodeRid: value.targetNodeRid,
|
|
4022
4082
|
spotId: value.spotId,
|
|
4023
|
-
...(typeof value.sessionNodeRid === 'string'
|
|
4083
|
+
...(typeof value.sessionNodeRid === 'string'
|
|
4084
|
+
? { sessionNodeRid: value.sessionNodeRid }
|
|
4085
|
+
: {}),
|
|
4024
4086
|
...(typeof value.sessionRid === 'string' ? { sessionRid: value.sessionRid } : {}),
|
|
4025
|
-
...(optionalBigInt('bindingGeneration') === undefined
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
...(
|
|
4087
|
+
...(optionalBigInt('bindingGeneration') === undefined
|
|
4088
|
+
? {}
|
|
4089
|
+
: { bindingGeneration: optionalBigInt('bindingGeneration') }),
|
|
4090
|
+
...(optionalBigInt('previousAuthorityOwnerGeneration') === undefined
|
|
4091
|
+
? {}
|
|
4092
|
+
: { previousAuthorityOwnerGeneration: optionalBigInt('previousAuthorityOwnerGeneration') }),
|
|
4093
|
+
...(optionalBigInt('previousOwnerLeaseGeneration') === undefined
|
|
4094
|
+
? {}
|
|
4095
|
+
: { previousOwnerLeaseGeneration: optionalBigInt('previousOwnerLeaseGeneration') }),
|
|
4096
|
+
...(typeof value.relocationSealId === 'string'
|
|
4097
|
+
? { relocationSealId: value.relocationSealId }
|
|
4098
|
+
: {}),
|
|
4029
4099
|
...(serviceWire === undefined ? {} : { serviceWireRelocation: serviceWire })
|
|
4030
4100
|
};
|
|
4031
4101
|
}
|
|
@@ -4083,7 +4153,9 @@ function decodeActorSessionServiceWireFence(input) {
|
|
|
4083
4153
|
};
|
|
4084
4154
|
}
|
|
4085
4155
|
function encodeMembershipMutation(memberships, participantKey) {
|
|
4086
|
-
return Buffer.from(JSON.stringify(memberships
|
|
4156
|
+
return Buffer.from(JSON.stringify(memberships
|
|
4157
|
+
.filter((value) => value.actorKey === participantKey || value.spotKey === participantKey)
|
|
4158
|
+
.map((value) => ({
|
|
4087
4159
|
...value,
|
|
4088
4160
|
spotObjectGeneration: value.spotObjectGeneration.toString(),
|
|
4089
4161
|
membershipEpoch: value.membershipEpoch.toString()
|
|
@@ -4091,19 +4163,22 @@ function encodeMembershipMutation(memberships, participantKey) {
|
|
|
4091
4163
|
}
|
|
4092
4164
|
function addCapacity(left, right) {
|
|
4093
4165
|
const spotType = left.spotType ?? right.spotType;
|
|
4094
|
-
if (left.spotType !== undefined &&
|
|
4095
|
-
|
|
4096
|
-
|
|
4166
|
+
if (left.spotType !== undefined &&
|
|
4167
|
+
right.spotType !== undefined &&
|
|
4168
|
+
(left.spotType.objectKind !== right.spotType.objectKind ||
|
|
4169
|
+
left.spotType.stableType !== right.spotType.stableType)) {
|
|
4097
4170
|
throw new Error('Relocation aggregate contains more than one Spot stable type.');
|
|
4098
4171
|
}
|
|
4099
4172
|
return {
|
|
4100
4173
|
actors: left.actors + right.actors,
|
|
4101
4174
|
spots: left.spots + right.spots,
|
|
4102
|
-
...(spotType === undefined
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4175
|
+
...(spotType === undefined
|
|
4176
|
+
? {}
|
|
4177
|
+
: {
|
|
4178
|
+
spotType: {
|
|
4179
|
+
...spotType,
|
|
4180
|
+
count: (left.spotType?.count ?? 0) + (right.spotType?.count ?? 0)
|
|
4181
|
+
}
|
|
4182
|
+
})
|
|
4108
4183
|
};
|
|
4109
4184
|
}
|