@zlink-systems/framework 0.30.1 → 0.30.2
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/ZLinkEncodedPayload.d.ts +6 -0
- package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
- package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
- package/dist/contracts/Common/encoded-payload-storage.js +5 -2
- package/dist/contracts/Configuration/Builders.d.ts +1 -1
- package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
- package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
- package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
- package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
- package/dist/contracts/Locations/Rows.d.ts +2 -0
- package/dist/contracts/Spots/Contracts.d.ts +4 -0
- package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
- package/dist/runtime/abort.d.ts +5 -0
- package/dist/runtime/abort.js +10 -0
- package/dist/runtime/actors/actor-authority-publication.js +3 -2
- package/dist/runtime/actors/actor-client.d.ts +0 -1
- package/dist/runtime/actors/actor-client.js +38 -45
- package/dist/runtime/actors/actor-context.d.ts +2 -0
- package/dist/runtime/actors/actor-context.js +46 -9
- package/dist/runtime/actors/actor-handoff.d.ts +7 -3
- package/dist/runtime/actors/actor-handoff.js +212 -88
- package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
- package/dist/runtime/actors/actor-local-native-join.js +4 -0
- package/dist/runtime/actors/actor-mailbox.js +27 -1
- package/dist/runtime/actors/actor-remote-joiner.js +3 -1
- package/dist/runtime/actors/actor-reply.d.ts +4 -0
- package/dist/runtime/actors/actor-reply.js +29 -0
- package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
- package/dist/runtime/actors/actor-runtime-state.js +2 -20
- package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
- package/dist/runtime/actors/index.d.ts +6 -2
- package/dist/runtime/actors/index.js +37 -21
- package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
- package/dist/runtime/actors/session-disconnected-wire.js +48 -0
- package/dist/runtime/admission.d.ts +9 -1
- package/dist/runtime/admission.js +55 -32
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
- package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
- package/dist/runtime/application-jobs/contracts.d.ts +2 -0
- package/dist/runtime/backend/contracts/index.d.ts +19 -3
- package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
- package/dist/runtime/backend/mesh-completion-table.js +5 -0
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
- package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
- package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
- package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
- package/dist/runtime/channels/channel-clients.d.ts +1 -0
- package/dist/runtime/channels/channel-clients.js +20 -5
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
- package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
- package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
- package/dist/runtime/channels/channel-dispatchers.js +44 -37
- package/dist/runtime/channels/channel-envelope.d.ts +1 -0
- package/dist/runtime/channels/channel-envelope.js +74 -31
- package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
- package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
- package/dist/runtime/channels/channel-runtime-manager.js +4 -4
- package/dist/runtime/channels/channel-transports.d.ts +0 -1
- package/dist/runtime/channels/channel-transports.js +35 -33
- package/dist/runtime/channels/client-server-location-runtime.js +5 -4
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
- package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
- package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
- package/dist/runtime/channels/fanout-location-runtime.js +3 -3
- package/dist/runtime/diagnostics/flow-context.js +19 -7
- package/dist/runtime/diagnostics/index.js +4 -9
- package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
- package/dist/runtime/diagnostics/message-flow.js +35 -5
- package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
- package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
- package/dist/runtime/execution/index.d.ts +4 -2
- package/dist/runtime/execution/index.js +33 -10
- package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
- package/dist/runtime/execution/serial-execution-queue.js +21 -2
- package/dist/runtime/execution/state-lane.d.ts +2 -0
- package/dist/runtime/execution/state-lane.js +5 -0
- package/dist/runtime/foundation/operation-registry.d.ts +25 -1
- package/dist/runtime/foundation/operation-registry.js +86 -18
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
- package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
- package/dist/runtime/foundation/service-liveness-registry.js +38 -0
- package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
- package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
- package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
- package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
- package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
- package/dist/runtime/foundation/service-stateful-registry.js +24 -26
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
- package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
- package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
- package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
- package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
- package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
- package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
- package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
- package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
- package/dist/runtime/host/actor-packet-relay.js +59 -72
- package/dist/runtime/host/actor-placement-coordinator.js +25 -8
- package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
- package/dist/runtime/host/actor-transfer-runtime.js +85 -331
- package/dist/runtime/host/application-job-queue.d.ts +24 -3
- package/dist/runtime/host/application-job-queue.js +28 -41
- package/dist/runtime/host/index.d.ts +5 -1
- package/dist/runtime/host/index.js +171 -97
- package/dist/runtime/host/location-runtime-owner.js +2 -6
- package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
- package/dist/runtime/host/mesh-router-resolver.js +14 -6
- package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
- package/dist/runtime/host/remote-bound-session-relay.js +71 -190
- package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
- package/dist/runtime/host/route-mesh-runtime.js +5 -3
- package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
- package/dist/runtime/host/runtime-shutdown.js +3 -2
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
- package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
- package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
- package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
- package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
- package/dist/runtime/locations/auto-connect-loop.js +22 -14
- package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
- package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
- package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
- package/dist/runtime/locations/descriptor-publication.js +11 -0
- package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
- package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
- package/dist/runtime/locations/in-memory-authority-store.js +56 -19
- package/dist/runtime/locations/in-memory-location-store.js +1 -10
- package/dist/runtime/locations/index.d.ts +1 -0
- package/dist/runtime/locations/index.js +1 -0
- package/dist/runtime/locations/lease-tracker.js +1 -6
- package/dist/runtime/locations/location-store-repository.d.ts +51 -1
- package/dist/runtime/locations/location-store-repository.js +363 -139
- package/dist/runtime/locations/relocation-blob.d.ts +18 -1
- package/dist/runtime/locations/relocation-blob.js +52 -1
- package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
- package/dist/runtime/locations/request-source-resolver.js +80 -0
- package/dist/runtime/locations/resolvers.js +1 -1
- package/dist/runtime/locations/runtime.d.ts +6 -2
- package/dist/runtime/locations/runtime.js +37 -30
- package/dist/runtime/messaging/payload-codec.d.ts +7 -1
- package/dist/runtime/messaging/payload-codec.js +7 -6
- package/dist/runtime/messaging/request-result.js +29 -26
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
- package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
- package/dist/runtime/spots/index.d.ts +18 -11
- package/dist/runtime/spots/index.js +234 -176
- package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
- package/dist/runtime/spots/spot-activation-registry.js +21 -11
- package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
- package/dist/runtime/spots/spot-activation-state.js +7 -7
- package/dist/runtime/spots/spot-activation.d.ts +6 -3
- package/dist/runtime/spots/spot-activation.js +123 -44
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
- package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
- package/dist/runtime/spots/spot-actor-membership.js +0 -8
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
- package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
- package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
- package/dist/runtime/spots/spot-entry-activation.js +14 -9
- package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
- package/dist/runtime/spots/spot-handler-registry.js +6 -2
- package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
- package/dist/runtime/spots/spot-manager-public.js +2 -2
- package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
- package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
- package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
- package/dist/runtime/spots/spot-outbound.js +3 -3
- package/dist/runtime/spots/spot-remote-codec.js +5 -1
- package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
- package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
- package/dist/runtime/spots/spot-serial-executor.js +61 -8
- package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
- package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
- package/dist/runtime/spots/spot-timer.d.ts +57 -5
- package/dist/runtime/spots/spot-timer.js +287 -103
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
- package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
- package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
- package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
- package/dist/runtime/streams/bound-session-service.d.ts +1 -1
- package/dist/runtime/streams/bound-session-service.js +6 -11
- package/dist/runtime/streams/index.d.ts +3 -2
- package/dist/runtime/streams/index.js +6 -4
- package/dist/runtime/streams/managed-stream.js +3 -2
- package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
- package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
- package/dist/runtime/streams/session-actor-coordinator.js +15 -32
- package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
- package/dist/runtime/streams/stream-session-runtime.js +1 -4
- package/dist/runtime/workers/index.js +1 -1
- package/package.json +3 -3
- package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
- package/src/contracts/Common/encoded-payload-storage.ts +6 -3
- package/src/contracts/Configuration/Builders.ts +4 -1
- package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
- package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
- package/src/contracts/Locations/Rows.ts +2 -0
- package/src/contracts/Spots/Contracts.ts +8 -0
- package/src/contracts/Spots/ZLinkSpot.ts +3 -3
- package/src/runtime/abort.ts +12 -0
- package/src/runtime/actors/actor-authority-publication.ts +3 -2
- package/src/runtime/actors/actor-client.ts +61 -70
- package/src/runtime/actors/actor-context.ts +49 -9
- package/src/runtime/actors/actor-handoff.ts +282 -106
- package/src/runtime/actors/actor-join-relocation.ts +2 -0
- package/src/runtime/actors/actor-local-native-join.ts +4 -0
- package/src/runtime/actors/actor-mailbox.ts +40 -2
- package/src/runtime/actors/actor-remote-joiner.ts +6 -1
- package/src/runtime/actors/actor-reply.ts +42 -0
- package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
- package/src/runtime/actors/actor-runtime-state.ts +2 -20
- package/src/runtime/actors/actor-source-transfer.ts +1 -34
- package/src/runtime/actors/index.ts +41 -27
- package/src/runtime/actors/session-disconnected-wire.ts +66 -0
- package/src/runtime/admission.ts +69 -34
- package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
- package/src/runtime/application-jobs/contracts.ts +2 -0
- package/src/runtime/backend/contracts/index.ts +39 -4
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
- package/src/runtime/backend/mesh-completion-table.ts +4 -0
- package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
- package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
- package/src/runtime/channels/channel-clients.ts +49 -24
- package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
- package/src/runtime/channels/channel-dispatchers.ts +116 -72
- package/src/runtime/channels/channel-envelope.ts +105 -36
- package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
- package/src/runtime/channels/channel-runtime-manager.ts +12 -5
- package/src/runtime/channels/channel-transports.ts +49 -58
- package/src/runtime/channels/client-server-location-runtime.ts +11 -10
- package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
- package/src/runtime/channels/fanout-location-runtime.ts +17 -9
- package/src/runtime/diagnostics/flow-context.ts +20 -7
- package/src/runtime/diagnostics/index.ts +1 -7
- package/src/runtime/diagnostics/message-flow.ts +47 -9
- package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
- package/src/runtime/execution/index.ts +40 -14
- package/src/runtime/execution/serial-execution-queue.ts +31 -4
- package/src/runtime/execution/state-lane.ts +7 -0
- package/src/runtime/foundation/operation-registry.ts +98 -20
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
- package/src/runtime/foundation/service-liveness-registry.ts +39 -0
- package/src/runtime/foundation/service-mailbox.ts +8 -0
- package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
- package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
- package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
- package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
- package/src/runtime/foundation/service-stateful-registry.ts +38 -35
- package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
- package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
- package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
- package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
- package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
- package/src/runtime/host/actor-packet-relay.ts +113 -94
- package/src/runtime/host/actor-placement-coordinator.ts +31 -8
- package/src/runtime/host/actor-transfer-runtime.ts +104 -430
- package/src/runtime/host/application-job-queue.ts +29 -44
- package/src/runtime/host/index.ts +286 -129
- package/src/runtime/host/location-runtime-owner.ts +2 -6
- package/src/runtime/host/mesh-router-resolver.ts +13 -5
- package/src/runtime/host/remote-bound-session-relay.ts +86 -248
- package/src/runtime/host/route-mesh-runtime.ts +11 -5
- package/src/runtime/host/runtime-shutdown.ts +15 -4
- package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
- package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
- package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
- package/src/runtime/locations/auto-connect-loop.ts +22 -14
- package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
- package/src/runtime/locations/auto-connect-types.ts +0 -1
- package/src/runtime/locations/descriptor-publication.ts +7 -0
- package/src/runtime/locations/domain-store-contract.ts +5 -0
- package/src/runtime/locations/in-memory-authority-store.ts +85 -23
- package/src/runtime/locations/in-memory-location-store.ts +1 -12
- package/src/runtime/locations/index.ts +1 -0
- package/src/runtime/locations/lease-tracker.ts +2 -9
- package/src/runtime/locations/location-store-repository.ts +628 -152
- package/src/runtime/locations/relocation-blob.ts +75 -1
- package/src/runtime/locations/request-source-resolver.ts +138 -0
- package/src/runtime/locations/resolvers.ts +2 -2
- package/src/runtime/locations/runtime.ts +70 -40
- package/src/runtime/messaging/payload-codec.ts +8 -11
- package/src/runtime/messaging/request-result.ts +33 -29
- package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
- package/src/runtime/spots/index.ts +375 -281
- package/src/runtime/spots/spot-activation-registry.ts +25 -13
- package/src/runtime/spots/spot-activation-state.ts +12 -19
- package/src/runtime/spots/spot-activation.ts +170 -86
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
- package/src/runtime/spots/spot-actor-membership.ts +0 -15
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
- package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
- package/src/runtime/spots/spot-entry-activation.ts +24 -19
- package/src/runtime/spots/spot-handler-registry.ts +15 -4
- package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
- package/src/runtime/spots/spot-manager-public.ts +2 -2
- package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
- package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
- package/src/runtime/spots/spot-outbound.ts +3 -3
- package/src/runtime/spots/spot-remote-codec.ts +9 -2
- package/src/runtime/spots/spot-runtime-ports.ts +0 -1
- package/src/runtime/spots/spot-serial-executor.ts +97 -25
- package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
- package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
- package/src/runtime/spots/spot-timer.ts +413 -157
- package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
- package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
- package/src/runtime/streams/bound-session-service.ts +7 -10
- package/src/runtime/streams/index.ts +12 -6
- package/src/runtime/streams/managed-stream.ts +4 -2
- package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
- package/src/runtime/streams/session-actor-coordinator.ts +39 -88
- package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
- package/src/runtime/streams/stream-session-runtime.ts +1 -5
- package/src/runtime/workers/index.ts +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ActorRef, type RoutingId, ZLinkFrameworkException } from '../../contracts';
|
|
2
2
|
|
|
3
3
|
import type { Message } from '../../contracts/Common/Message';
|
|
4
|
+
import { DEFAULT_REQUEST_TIMEOUT_MS } from '../../contracts/Configuration/Registration';
|
|
4
5
|
import { zlinkDefaultLocationOptions } from '../../contracts/Locations/Options';
|
|
5
6
|
import { releaseApplicationJobPermitForDurableHandoff } from '../application-jobs/application-job-queue-scope';
|
|
6
7
|
import type { ApplicationJobOrigin } from '../application-jobs/contracts';
|
|
@@ -10,12 +11,22 @@ import {
|
|
|
10
11
|
type MessageFollowSuppressionFence
|
|
11
12
|
} from '../foundation/message-follow-suppression-registry';
|
|
12
13
|
import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-contracts';
|
|
14
|
+
import { RELOCATION_REPLY_RETENTION_MS } from '../foundation/service-stateful-registry';
|
|
15
|
+
import type { ServiceActorRouteFence } from '../foundation/service-stateful-wire-codec';
|
|
16
|
+
import { OPERATION_IDENTITY_BYTES } from '../foundation/operation-identity';
|
|
17
|
+
import { UINT64_BYTES } from '@zlink-systems/stream-wire';
|
|
13
18
|
import {
|
|
14
19
|
createInternalFrameworkException,
|
|
15
20
|
internalFrameworkErrorKind,
|
|
16
21
|
ZLinkFrameworkInternalErrorKind
|
|
17
22
|
} from '../framework-errors-internal';
|
|
18
|
-
import {
|
|
23
|
+
import { waitRequestReply } from '../messaging/request-deadline';
|
|
24
|
+
import {
|
|
25
|
+
decodeRoutingId,
|
|
26
|
+
encodeRoutingIdStorageHex,
|
|
27
|
+
routingIdsEqual,
|
|
28
|
+
routingIdWireHex
|
|
29
|
+
} from '../routing-id';
|
|
19
30
|
import type { ZLinkSpotRouteTarget } from '../spots/spot-routing-internal';
|
|
20
31
|
import { decodeActorRequestDeadlineUnixMs, decodeStreamHeader } from '../streams/protocol';
|
|
21
32
|
import {
|
|
@@ -43,7 +54,7 @@ import type { ZLinkRemoteBoundSessionTarget } from './actor-runtime-state';
|
|
|
43
54
|
|
|
44
55
|
export const DEFAULT_MESSAGE_FOLLOW_DURATION_MS =
|
|
45
56
|
zlinkDefaultLocationOptions.messageFollowDurationMs;
|
|
46
|
-
const
|
|
57
|
+
export const RELOCATED_REQUEST_OWNED_BY_REQUESTER = Symbol('relocated request owned by requester');
|
|
47
58
|
|
|
48
59
|
export interface ZLinkActorHandoffPacket {
|
|
49
60
|
readonly index: number;
|
|
@@ -74,6 +85,7 @@ export interface ZLinkActorHandoffRequestSource {
|
|
|
74
85
|
readonly ownerId: string;
|
|
75
86
|
readonly ownerLeaseGeneration: string;
|
|
76
87
|
readonly nodeRid: string;
|
|
88
|
+
readonly nodeRidHex?: string;
|
|
77
89
|
readonly nodeGeneration: string;
|
|
78
90
|
readonly replyRouteId: string;
|
|
79
91
|
}
|
|
@@ -119,6 +131,7 @@ export interface ZLinkActorHandoffPrefixAdmission {
|
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
export interface ZLinkActorHandoffPrefixRecord {
|
|
134
|
+
readonly onWithdrawable?: (withdraw: () => boolean) => void;
|
|
122
135
|
readonly drain: (dispatch: ZLinkActorHandoffDispatch) => Promise<void>;
|
|
123
136
|
readonly preparation?: {
|
|
124
137
|
prepare(signal: AbortSignal): Promise<void>;
|
|
@@ -139,6 +152,7 @@ export type ZLinkActorHandoffPrefixQueue = (
|
|
|
139
152
|
) => ZLinkActorHandoffPrefixAdmission;
|
|
140
153
|
|
|
141
154
|
interface PendingPacket {
|
|
155
|
+
withdraw?: () => boolean;
|
|
142
156
|
readonly origin: ApplicationJobOrigin;
|
|
143
157
|
readonly packet: ZLinkActorHandoffPacket;
|
|
144
158
|
readonly resolve?: (value: unknown) => void;
|
|
@@ -290,7 +304,12 @@ function requireExactTargetOwnerFence(
|
|
|
290
304
|
/** Owns packet ordering from relocation start through Message Follow removal. */
|
|
291
305
|
export class ZLinkActorHandoffCoordinator {
|
|
292
306
|
private readonly active = new Map<string, ActiveHandoff>();
|
|
293
|
-
|
|
307
|
+
// Each route is stored once: Actor -> native fence -> location owner id.
|
|
308
|
+
// Native ingress has the complete fence except the location owner's text id.
|
|
309
|
+
private readonly messageFollowRoutes = new Map<
|
|
310
|
+
string,
|
|
311
|
+
Map<string, Map<string, MessageFollowRoute>>
|
|
312
|
+
>();
|
|
294
313
|
private readonly messageFollowSuppression = new MessageFollowSuppressionRegistry();
|
|
295
314
|
// Relocation preserves ObjectGeneration, so (nodeRid, objectGeneration) alone
|
|
296
315
|
// also matches a tenure that later RETURNS to a previously-visited node. The
|
|
@@ -322,7 +341,10 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
322
341
|
oldGeneration: bigint,
|
|
323
342
|
phase: 'relocating' | 'provisional'
|
|
324
343
|
): void {
|
|
325
|
-
|
|
344
|
+
// A releasing handoff has returned its hold to the Actor FIFO; only its
|
|
345
|
+
// durable prefix drain remains, and the next hold takes over its ingress.
|
|
346
|
+
const previous = this.active.get(actorId);
|
|
347
|
+
if (this.isActive(actorId)) {
|
|
326
348
|
throw new Error(`Actor '${actorId}' already has an active packet handoff.`);
|
|
327
349
|
}
|
|
328
350
|
if (oldGeneration <= 0n) {
|
|
@@ -362,6 +384,24 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
362
384
|
nodeGeneration: source.nodeGeneration,
|
|
363
385
|
authorityOwnerGeneration: source.authorityOwnerGeneration
|
|
364
386
|
});
|
|
387
|
+
const pending: PendingPacket[] = [];
|
|
388
|
+
if (previous?.prefixRelease !== undefined) {
|
|
389
|
+
// Only records still in the FIFO belong to the new barrier. Running
|
|
390
|
+
// records keep their existing terminal; withdrawn records surrender
|
|
391
|
+
// readiness and move their payload before later ingress can arrive.
|
|
392
|
+
for (let index = 0; index < previous.pending.length;) {
|
|
393
|
+
const record = previous.pending[index]!;
|
|
394
|
+
if (record.withdraw?.() === true) {
|
|
395
|
+
record.withdraw = undefined;
|
|
396
|
+
pending.push(record);
|
|
397
|
+
previous.pending.splice(index, 1);
|
|
398
|
+
previous.prefixRelease.cursor -= 1;
|
|
399
|
+
previous.pendingBytes -= packetBytes(record.packet);
|
|
400
|
+
} else {
|
|
401
|
+
index += 1;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
365
405
|
this.active.set(actorId, {
|
|
366
406
|
oldGeneration,
|
|
367
407
|
oldNodeRid: sourceOwner.nodeRid,
|
|
@@ -371,29 +411,23 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
371
411
|
phase,
|
|
372
412
|
deferredJoin: phase === 'provisional',
|
|
373
413
|
connectionBoundSealed: false,
|
|
374
|
-
pending
|
|
375
|
-
nextIndex: 0,
|
|
414
|
+
pending,
|
|
415
|
+
nextIndex: pending.reduce((next, record) => Math.max(next, record.packet.index + 1), 0),
|
|
376
416
|
snapshotIndex: -1,
|
|
377
|
-
pendingBytes: 0
|
|
417
|
+
pendingBytes: pending.reduce((bytes, record) => bytes + packetBytes(record.packet), 0)
|
|
378
418
|
});
|
|
379
419
|
}
|
|
380
420
|
|
|
421
|
+
/** True while a hold owns this Actor's ingress, before its release to the Actor FIFO. */
|
|
381
422
|
isActive(actorId: string): boolean {
|
|
382
|
-
|
|
423
|
+
const handoff = this.active.get(actorId);
|
|
424
|
+
return handoff !== undefined && handoff.phase !== 'releasing';
|
|
383
425
|
}
|
|
384
426
|
|
|
385
427
|
isProvisional(actorId: string): boolean {
|
|
386
428
|
return this.active.get(actorId)?.phase === 'provisional';
|
|
387
429
|
}
|
|
388
430
|
|
|
389
|
-
promoteProvisional(actorId: string): void {
|
|
390
|
-
const handoff = this.active.get(actorId);
|
|
391
|
-
if (handoff?.phase !== 'provisional') {
|
|
392
|
-
throw new Error(`Actor '${actorId}' does not have a provisional packet handoff.`);
|
|
393
|
-
}
|
|
394
|
-
handoff.phase = 'relocating';
|
|
395
|
-
}
|
|
396
|
-
|
|
397
431
|
sealConnectionBoundIngress(actorId: string): void {
|
|
398
432
|
const handoff = this.active.get(actorId);
|
|
399
433
|
if (handoff !== undefined) handoff.connectionBoundSealed = true;
|
|
@@ -459,6 +493,44 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
459
493
|
return this.admitHandoffPrefix(actorId, handoff, queue, preparation, start);
|
|
460
494
|
}
|
|
461
495
|
|
|
496
|
+
/** Installs a restored target's payload in the same owner used by local handoffs. */
|
|
497
|
+
admitTransferredPrefix(
|
|
498
|
+
actorId: string,
|
|
499
|
+
objectGeneration: bigint,
|
|
500
|
+
packets: readonly ZLinkActorHandoffPacket[],
|
|
501
|
+
queue: ZLinkActorHandoffPrefixQueue,
|
|
502
|
+
preparation: ZLinkActorHandoffReplayPreparation | undefined,
|
|
503
|
+
start: Promise<void>,
|
|
504
|
+
onResult: (packet: ZLinkActorHandoffPacket, result: ZLinkActorHandoffResult) => void
|
|
505
|
+
): ZLinkActorHandoffPrefixAdmission {
|
|
506
|
+
this.beginProvisional(actorId, objectGeneration);
|
|
507
|
+
const handoff = this.requireActive(actorId);
|
|
508
|
+
for (const packet of packets) {
|
|
509
|
+
handoff.pending.push({
|
|
510
|
+
packet,
|
|
511
|
+
origin: 'remote',
|
|
512
|
+
resolve: (response) => {
|
|
513
|
+
if (response !== RELOCATED_REQUEST_OWNED_BY_REQUESTER) {
|
|
514
|
+
onResult(packet, { index: packet.index, ok: true, response });
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
reject: (error) =>
|
|
518
|
+
onResult(packet, {
|
|
519
|
+
index: packet.index,
|
|
520
|
+
ok: false,
|
|
521
|
+
error: error instanceof Error ? error.message : String(error),
|
|
522
|
+
errorKind:
|
|
523
|
+
error instanceof ZLinkFrameworkException
|
|
524
|
+
? internalFrameworkErrorKind(error)
|
|
525
|
+
: undefined
|
|
526
|
+
})
|
|
527
|
+
});
|
|
528
|
+
handoff.nextIndex = Math.max(handoff.nextIndex, packet.index + 1);
|
|
529
|
+
handoff.pendingBytes += packetBytes(packet);
|
|
530
|
+
}
|
|
531
|
+
return this.admitHandoffPrefix(actorId, handoff, queue, preparation, start);
|
|
532
|
+
}
|
|
533
|
+
|
|
462
534
|
private admitHandoffPrefix(
|
|
463
535
|
actorId: string,
|
|
464
536
|
handoff: ActiveHandoff,
|
|
@@ -551,6 +623,9 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
551
623
|
prepared = undefined;
|
|
552
624
|
};
|
|
553
625
|
return {
|
|
626
|
+
onWithdrawable: (withdraw) => {
|
|
627
|
+
pending.withdraw = withdraw;
|
|
628
|
+
},
|
|
554
629
|
payloadBytes: packetBytes(pending.packet),
|
|
555
630
|
preparation: {
|
|
556
631
|
prepare: async (signal) => {
|
|
@@ -572,6 +647,9 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
572
647
|
cancel
|
|
573
648
|
},
|
|
574
649
|
drain: async (replay) => {
|
|
650
|
+
// The FIFO claim, rather than this prefix's eventual terminal,
|
|
651
|
+
// ends the record's durable ownership and transfer capability.
|
|
652
|
+
pending.withdraw = undefined;
|
|
575
653
|
const admission =
|
|
576
654
|
prepared === undefined
|
|
577
655
|
? undefined
|
|
@@ -779,11 +857,38 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
779
857
|
provisionalReplay?: ZLinkActorHandoffDispatch,
|
|
780
858
|
onAdmitted?: () => void
|
|
781
859
|
): Promise<unknown> | undefined {
|
|
782
|
-
|
|
860
|
+
let incomingContext = actorMessageFollowContext(fallbackActorRef);
|
|
783
861
|
const originalDeadlineUnixMs =
|
|
784
862
|
deadlineUnixMs ?? incomingContext?.deadlineUnixMs ?? packetDeadlineUnixMs(parts);
|
|
785
|
-
const
|
|
863
|
+
const followRoute = this.findMessageFollowRoute(
|
|
864
|
+
actorId,
|
|
865
|
+
incomingContext,
|
|
866
|
+
messageFollowOrigin?.target
|
|
867
|
+
);
|
|
868
|
+
// An exact departed tenure belongs to its committed route, even while the
|
|
869
|
+
// same Actor incarnation is performing a later Join on this node.
|
|
870
|
+
const handoff = followRoute === undefined ? this.active.get(actorId) : undefined;
|
|
871
|
+
if (
|
|
872
|
+
incomingContext === undefined &&
|
|
873
|
+
followRoute !== undefined &&
|
|
874
|
+
messageFollowOrigin?.target !== undefined
|
|
875
|
+
) {
|
|
876
|
+
incomingContext = this.createInitialIngressContext(
|
|
877
|
+
followRoute.sourceOwner,
|
|
878
|
+
messageFollowOrigin.target.actor.generation,
|
|
879
|
+
parts,
|
|
880
|
+
returnResponse,
|
|
881
|
+
originalDeadlineUnixMs,
|
|
882
|
+
messageFollowOrigin
|
|
883
|
+
);
|
|
884
|
+
}
|
|
786
885
|
if (handoff !== undefined) {
|
|
886
|
+
if (
|
|
887
|
+
handoff.phase === 'releasing' &&
|
|
888
|
+
handoff.prefixRelease !== undefined &&
|
|
889
|
+
handoff.pending.at(-1)?.withdraw === undefined
|
|
890
|
+
)
|
|
891
|
+
return undefined;
|
|
787
892
|
if (parts.length < 2) return Promise.resolve(undefined);
|
|
788
893
|
if (
|
|
789
894
|
handoff.connectionBoundSealed &&
|
|
@@ -806,10 +911,15 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
806
911
|
handoff.oldGeneration,
|
|
807
912
|
parts,
|
|
808
913
|
returnResponse,
|
|
809
|
-
originalDeadlineUnixMs
|
|
914
|
+
originalDeadlineUnixMs,
|
|
915
|
+
messageFollowOrigin
|
|
810
916
|
);
|
|
811
917
|
try {
|
|
812
918
|
this.validateContext(actorId, context, parts, returnResponse, fallbackActorRef);
|
|
919
|
+
// Accepted handoff retains its original deadline; Message Follow uses a local relay window.
|
|
920
|
+
if (context.deadlineUnixMs !== undefined && Date.now() >= context.deadlineUnixMs) {
|
|
921
|
+
throw actorDeadlineExceeded(actorId);
|
|
922
|
+
}
|
|
813
923
|
} catch (error) {
|
|
814
924
|
return Promise.reject(error);
|
|
815
925
|
}
|
|
@@ -844,8 +954,25 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
844
954
|
return Promise.resolve(undefined);
|
|
845
955
|
}
|
|
846
956
|
const result = new Promise((resolve, reject) => {
|
|
847
|
-
const
|
|
957
|
+
const original = messageFollowOrigin?.requestSource;
|
|
958
|
+
const originalRidHex =
|
|
959
|
+
original === undefined ? undefined : routingIdWireHex(original.nodeRid);
|
|
960
|
+
const source =
|
|
961
|
+
original === undefined
|
|
962
|
+
? this.captureRequestSource(handoff.sourceEvidence, context.replyRouteId)
|
|
963
|
+
: {
|
|
964
|
+
ownerId: original.ownerId,
|
|
965
|
+
ownerLeaseGeneration: original.leaseGeneration.toString(),
|
|
966
|
+
nodeRid: String(original.nodeRid),
|
|
967
|
+
...(originalRidHex === undefined ? {} : { nodeRidHex: originalRidHex }),
|
|
968
|
+
nodeGeneration: original.nodeGeneration.toString(),
|
|
969
|
+
replyRouteId: messageFollowOrigin!.originalReplyRouteId.toString()
|
|
970
|
+
};
|
|
848
971
|
const requestPacket = { ...packet, source };
|
|
972
|
+
if (original !== undefined) {
|
|
973
|
+
handoff.pending.push({ packet: requestPacket, origin, resolve, reject });
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
849
976
|
const route: ReplyRoute = {
|
|
850
977
|
actorId,
|
|
851
978
|
operationId: requestPacket.messageFollowContext.operationId,
|
|
@@ -885,7 +1012,6 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
885
1012
|
return result;
|
|
886
1013
|
}
|
|
887
1014
|
|
|
888
|
-
const followRoute = this.findMessageFollowRoute(actorId, incomingContext);
|
|
889
1015
|
const staleGeneration = fallbackActorRef?.objectGeneration;
|
|
890
1016
|
if (
|
|
891
1017
|
fallbackActorRef !== undefined &&
|
|
@@ -984,19 +1110,6 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
984
1110
|
return handoff.pending.map((entry) => entry.packet);
|
|
985
1111
|
}
|
|
986
1112
|
|
|
987
|
-
snapshotCoreBacklog(actorId: string): readonly ZLinkActorHandoffPacket[] {
|
|
988
|
-
const handoff = this.requireActive(actorId);
|
|
989
|
-
let snapshotIndex = -1;
|
|
990
|
-
while (
|
|
991
|
-
snapshotIndex + 1 < handoff.pending.length &&
|
|
992
|
-
handoff.pending[snapshotIndex + 1].packet.returnResponse === false
|
|
993
|
-
) {
|
|
994
|
-
snapshotIndex++;
|
|
995
|
-
}
|
|
996
|
-
handoff.snapshotIndex = snapshotIndex;
|
|
997
|
-
return handoff.pending.slice(0, snapshotIndex + 1).map((entry) => entry.packet);
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
1113
|
/**
|
|
1001
1114
|
* Freezes the post-capture ingress segment immediately before the caller
|
|
1002
1115
|
* appends the one-way cutover on the same relocation lane. Records returned
|
|
@@ -1015,14 +1128,25 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1015
1128
|
target: ZLinkSpotRouteTarget,
|
|
1016
1129
|
targetActorRef: ActorRef,
|
|
1017
1130
|
results: readonly ZLinkActorHandoffResult[],
|
|
1018
|
-
targetOwnerFence: ZLinkActorMessageFollowOwnerFence
|
|
1131
|
+
targetOwnerFence: ZLinkActorMessageFollowOwnerFence | null
|
|
1019
1132
|
): void {
|
|
1020
1133
|
const handoff = this.requireActive(actorId);
|
|
1021
|
-
const committedTargetOwner =
|
|
1134
|
+
const committedTargetOwner =
|
|
1135
|
+
targetOwnerFence === null ? null : requireExactTargetOwnerFence(actorId, targetOwnerFence);
|
|
1022
1136
|
this.active.delete(actorId);
|
|
1137
|
+
// Location runtime §10: a later owner has no source-local Follow route.
|
|
1138
|
+
if (committedTargetOwner === null) {
|
|
1139
|
+
const unavailable = actorLocationStale(actorId);
|
|
1140
|
+
for (const pending of handoff.pending) this.failReleasedPending(pending, unavailable);
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1023
1143
|
const byIndex = new Map(results.map((result) => [result.index, result]));
|
|
1024
1144
|
for (let i = 0; i <= handoff.snapshotIndex; i++) {
|
|
1025
1145
|
const pending = handoff.pending[i];
|
|
1146
|
+
if (pending.packet.messageFollowOrigin?.requestSource !== undefined) {
|
|
1147
|
+
pending.resolve?.(RELOCATED_REQUEST_OWNED_BY_REQUESTER);
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1026
1150
|
if (pending.packet.source !== undefined) continue;
|
|
1027
1151
|
const result = byIndex.get(pending.packet.index);
|
|
1028
1152
|
if (result?.ok === false) {
|
|
@@ -1074,11 +1198,16 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1074
1198
|
}
|
|
1075
1199
|
|
|
1076
1200
|
messageFollowCount(actorId?: string): number {
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1201
|
+
let count = 0;
|
|
1202
|
+
if (actorId === undefined) {
|
|
1203
|
+
for (const id of this.messageFollowRoutes.keys()) count += this.messageFollowCount(id);
|
|
1204
|
+
} else {
|
|
1205
|
+
const routes = this.messageFollowRoutes.get(actorId);
|
|
1206
|
+
if (routes !== undefined) {
|
|
1207
|
+
for (const owners of routes.values()) count += owners.size;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return count;
|
|
1082
1211
|
}
|
|
1083
1212
|
|
|
1084
1213
|
pendingCount(actorId: string): number {
|
|
@@ -1087,7 +1216,7 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1087
1216
|
|
|
1088
1217
|
isKnownStale(actor: ActorRef): boolean {
|
|
1089
1218
|
return (
|
|
1090
|
-
this.
|
|
1219
|
+
!this.messageFollowRoutes.has(actor.actorId) &&
|
|
1091
1220
|
this.options.isCurrentActorRef?.(actor.actorId, actor) !== true &&
|
|
1092
1221
|
this.isKnownStaleRef(actor.actorId, actor)
|
|
1093
1222
|
);
|
|
@@ -1244,8 +1373,24 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1244
1373
|
refs.set(exactRefKey, departedAuthorityOwnerGeneration);
|
|
1245
1374
|
}
|
|
1246
1375
|
}
|
|
1247
|
-
const key = messageFollowRouteKey(
|
|
1248
|
-
|
|
1376
|
+
const key = messageFollowRouteKey(
|
|
1377
|
+
oldGeneration,
|
|
1378
|
+
sourceOwner.nodeRidHex ?? encodeRoutingIdStorageHex(sourceOwner.nodeRid),
|
|
1379
|
+
sourceOwner.nodeGeneration,
|
|
1380
|
+
sourceOwner.authorityOwnerGeneration,
|
|
1381
|
+
sourceOwner.ownerLeaseGeneration
|
|
1382
|
+
);
|
|
1383
|
+
let routes = this.messageFollowRoutes.get(actorId);
|
|
1384
|
+
if (routes === undefined) {
|
|
1385
|
+
routes = new Map();
|
|
1386
|
+
this.messageFollowRoutes.set(actorId, routes);
|
|
1387
|
+
}
|
|
1388
|
+
let owners = routes.get(key);
|
|
1389
|
+
if (owners === undefined) {
|
|
1390
|
+
owners = new Map();
|
|
1391
|
+
routes.set(key, owners);
|
|
1392
|
+
}
|
|
1393
|
+
const previous = owners.get(sourceOwner.ownerId);
|
|
1249
1394
|
if (previous !== undefined) clearTimeout(previous.deadline);
|
|
1250
1395
|
const suppressionFence = actorMessageFollowSuppressionFence(
|
|
1251
1396
|
actorId,
|
|
@@ -1281,15 +1426,21 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1281
1426
|
} else {
|
|
1282
1427
|
this.messageFollowSuppression.replaceRoute(previous.suppressionFence, suppressionFence);
|
|
1283
1428
|
}
|
|
1284
|
-
|
|
1429
|
+
owners.set(sourceOwner.ownerId, entry);
|
|
1285
1430
|
this.options.onMarker?.('message_follow_registered', actorId, this.messageFollowDurationMs);
|
|
1286
1431
|
return entry;
|
|
1287
1432
|
}
|
|
1288
1433
|
|
|
1289
1434
|
private removeMessageFollowRoute(entry: MessageFollowRoute): void {
|
|
1290
|
-
|
|
1435
|
+
const actorId = entry.targetActorRef.actorId;
|
|
1436
|
+
const routes = this.messageFollowRoutes.get(actorId);
|
|
1437
|
+
if (routes === undefined) return;
|
|
1438
|
+
const owners = routes.get(entry.key);
|
|
1439
|
+
if (owners?.get(entry.sourceOwner.ownerId) !== entry) return;
|
|
1291
1440
|
clearTimeout(entry.deadline);
|
|
1292
|
-
|
|
1441
|
+
owners.delete(entry.sourceOwner.ownerId);
|
|
1442
|
+
if (owners.size === 0) routes.delete(entry.key);
|
|
1443
|
+
if (routes.size === 0) this.messageFollowRoutes.delete(actorId);
|
|
1293
1444
|
this.messageFollowSuppression.expireRoute(entry.suppressionFence);
|
|
1294
1445
|
this.pruneStaleTenureRecords(entry);
|
|
1295
1446
|
this.options.onMarker?.('message_follow_route_removed', entry.targetActorRef.actorId);
|
|
@@ -1328,22 +1479,54 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1328
1479
|
|
|
1329
1480
|
private findMessageFollowRoute(
|
|
1330
1481
|
actorId: string,
|
|
1331
|
-
context: ZLinkActorMessageFollowContext | undefined
|
|
1482
|
+
context: ZLinkActorMessageFollowContext | undefined,
|
|
1483
|
+
nativeTarget?: ServiceActorRouteFence
|
|
1332
1484
|
): MessageFollowRoute | undefined {
|
|
1333
|
-
|
|
1334
|
-
return
|
|
1335
|
-
|
|
1336
|
-
|
|
1485
|
+
const routes = this.messageFollowRoutes.get(actorId);
|
|
1486
|
+
if (routes === undefined) return undefined;
|
|
1487
|
+
if (context === undefined) {
|
|
1488
|
+
if (nativeTarget === undefined || nativeTarget.actor.actorId !== actorId) return undefined;
|
|
1489
|
+
return routes
|
|
1490
|
+
.get(
|
|
1491
|
+
messageFollowRouteKey(
|
|
1492
|
+
nativeTarget.actor.generation,
|
|
1493
|
+
encodeRoutingIdStorageHex(nativeTarget.actor.nodeRid),
|
|
1494
|
+
nativeTarget.targetNodeGeneration,
|
|
1495
|
+
nativeTarget.authorityOwnerGeneration,
|
|
1496
|
+
nativeTarget.ownerLeaseGeneration
|
|
1497
|
+
)
|
|
1498
|
+
)
|
|
1499
|
+
?.values()
|
|
1500
|
+
.next().value;
|
|
1501
|
+
}
|
|
1502
|
+
const owner = context.targetOwner;
|
|
1503
|
+
return routes
|
|
1504
|
+
.get(
|
|
1505
|
+
messageFollowRouteKey(
|
|
1506
|
+
BigInt(context.objectGeneration),
|
|
1507
|
+
owner.nodeRidHex ?? encodeRoutingIdStorageHex(owner.nodeRid),
|
|
1508
|
+
owner.nodeGeneration,
|
|
1509
|
+
owner.authorityOwnerGeneration,
|
|
1510
|
+
owner.ownerLeaseGeneration
|
|
1511
|
+
)
|
|
1512
|
+
)
|
|
1513
|
+
?.get(owner.ownerId);
|
|
1337
1514
|
}
|
|
1338
1515
|
|
|
1339
1516
|
private hasMessageFollowRouteForStaleRef(actorId: string, actorRef: ActorRef): boolean {
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
(
|
|
1345
|
-
|
|
1346
|
-
|
|
1517
|
+
const routes = this.messageFollowRoutes.get(actorId);
|
|
1518
|
+
if (routes === undefined) return false;
|
|
1519
|
+
for (const owners of routes.values()) {
|
|
1520
|
+
for (const route of owners.values()) {
|
|
1521
|
+
if (
|
|
1522
|
+
actorRef.objectGeneration === route.oldGeneration &&
|
|
1523
|
+
(route.oldNodeRid === undefined ||
|
|
1524
|
+
routingIdsEqual(actorRef.nodeRid, messageFollowOwnerNodeRid(route.sourceOwner)))
|
|
1525
|
+
)
|
|
1526
|
+
return true;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return false;
|
|
1347
1530
|
}
|
|
1348
1531
|
|
|
1349
1532
|
private createInitialIngressContext(
|
|
@@ -1351,9 +1534,21 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1351
1534
|
generation: bigint,
|
|
1352
1535
|
parts: readonly Message[],
|
|
1353
1536
|
request: boolean,
|
|
1354
|
-
deadlineUnixMs?: number
|
|
1537
|
+
deadlineUnixMs?: number,
|
|
1538
|
+
origin?: ZLinkMessageFollowOrigin
|
|
1355
1539
|
): ZLinkActorMessageFollowContext {
|
|
1356
|
-
|
|
1540
|
+
let operationId: string;
|
|
1541
|
+
if (origin === undefined) {
|
|
1542
|
+
operationId = createMessageFollowId();
|
|
1543
|
+
} else {
|
|
1544
|
+
const bytes = Buffer.allocUnsafe(OPERATION_IDENTITY_BYTES);
|
|
1545
|
+
bytes.writeBigUInt64BE(BigInt.asUintN(UINT64_BYTES * 8, origin.originalOperation.high));
|
|
1546
|
+
bytes.writeBigUInt64BE(
|
|
1547
|
+
BigInt.asUintN(UINT64_BYTES * 8, origin.originalOperation.low),
|
|
1548
|
+
UINT64_BYTES
|
|
1549
|
+
);
|
|
1550
|
+
operationId = bytes.toString('hex');
|
|
1551
|
+
}
|
|
1357
1552
|
return Object.freeze({
|
|
1358
1553
|
operationId,
|
|
1359
1554
|
objectGeneration: generation.toString(),
|
|
@@ -1361,7 +1556,11 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1361
1556
|
targetOwner: sourceOwner,
|
|
1362
1557
|
deadlineUnixMs,
|
|
1363
1558
|
correlationId: request ? createMessageFollowId() : undefined,
|
|
1364
|
-
replyRouteId: request
|
|
1559
|
+
replyRouteId: request
|
|
1560
|
+
? origin === undefined
|
|
1561
|
+
? createMessageFollowId()
|
|
1562
|
+
: operationId
|
|
1563
|
+
: undefined,
|
|
1365
1564
|
request,
|
|
1366
1565
|
hopCount: 0,
|
|
1367
1566
|
visitedOwners: Object.freeze([messageFollowOwnerFenceKey(sourceOwner)]),
|
|
@@ -1385,9 +1584,6 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1385
1584
|
if (context.objectGeneration === '0' || context.request !== request) {
|
|
1386
1585
|
throw actorLocationStale(actorId);
|
|
1387
1586
|
}
|
|
1388
|
-
if (context.deadlineUnixMs !== undefined && Date.now() >= context.deadlineUnixMs) {
|
|
1389
|
-
throw actorDeadlineExceeded(actorId);
|
|
1390
|
-
}
|
|
1391
1587
|
verifyActorMessageFollowPayload(context, parts);
|
|
1392
1588
|
}
|
|
1393
1589
|
|
|
@@ -1433,7 +1629,10 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1433
1629
|
return BigInt(context.targetOwner.authorityOwnerGeneration);
|
|
1434
1630
|
}
|
|
1435
1631
|
const current = this.options.currentOwnerFence?.(actorId);
|
|
1436
|
-
if (
|
|
1632
|
+
if (
|
|
1633
|
+
current !== undefined &&
|
|
1634
|
+
routingIdsEqual(messageFollowOwnerNodeRid(current), actor.nodeRid)
|
|
1635
|
+
) {
|
|
1437
1636
|
return BigInt(current.authorityOwnerGeneration);
|
|
1438
1637
|
}
|
|
1439
1638
|
return undefined;
|
|
@@ -1526,15 +1725,16 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1526
1725
|
await this.messageFollowRelayed(actorId, entry, packet, advanced);
|
|
1527
1726
|
return undefined;
|
|
1528
1727
|
}
|
|
1529
|
-
const
|
|
1728
|
+
const timeoutMs = this.options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1729
|
+
const relayDeadlineMs = performance.now() + timeoutMs;
|
|
1530
1730
|
if (this.options.routedTransport.requestRawToSpot === undefined) {
|
|
1531
|
-
const reply = await
|
|
1731
|
+
const reply = await waitRequestReply(
|
|
1532
1732
|
this.options.routedTransport.requestToSpot<Record<string, unknown>>(target, payload, {
|
|
1533
1733
|
packetName: ZLINK_REMOTE_ACTOR_PACKET_RELAY_PACKET,
|
|
1534
|
-
timeoutMs
|
|
1734
|
+
timeoutMs
|
|
1535
1735
|
}),
|
|
1536
1736
|
actorId,
|
|
1537
|
-
|
|
1737
|
+
relayDeadlineMs
|
|
1538
1738
|
);
|
|
1539
1739
|
if (reply.ok === false) {
|
|
1540
1740
|
throw actorRelayError(actorId, reply.errorKind, reply.error);
|
|
@@ -1542,12 +1742,12 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1542
1742
|
await this.messageFollowRelayed(actorId, entry, packet, advanced);
|
|
1543
1743
|
return reply.response;
|
|
1544
1744
|
}
|
|
1545
|
-
const response = await
|
|
1745
|
+
const response = await waitRequestReply(
|
|
1546
1746
|
requestRoutedJsonReply(
|
|
1547
1747
|
this.options.routedTransport,
|
|
1548
1748
|
target,
|
|
1549
1749
|
payload,
|
|
1550
|
-
{ timeoutMs
|
|
1750
|
+
{ timeoutMs },
|
|
1551
1751
|
`Actor Message Follow raw request is not available for '${actorId}'.`,
|
|
1552
1752
|
(parts) => {
|
|
1553
1753
|
if (parts.length === 0) {
|
|
@@ -1566,7 +1766,7 @@ export class ZLinkActorHandoffCoordinator {
|
|
|
1566
1766
|
}
|
|
1567
1767
|
),
|
|
1568
1768
|
actorId,
|
|
1569
|
-
|
|
1769
|
+
relayDeadlineMs
|
|
1570
1770
|
);
|
|
1571
1771
|
await this.messageFollowRelayed(actorId, entry, packet, advanced);
|
|
1572
1772
|
return response;
|
|
@@ -1775,35 +1975,6 @@ function packetDeadlineUnixMs(parts: readonly Message[]): number | undefined {
|
|
|
1775
1975
|
}
|
|
1776
1976
|
}
|
|
1777
1977
|
|
|
1778
|
-
function remainingRequestTime(
|
|
1779
|
-
actorId: string,
|
|
1780
|
-
deadlineUnixMs: number | undefined
|
|
1781
|
-
): number | undefined {
|
|
1782
|
-
if (deadlineUnixMs === undefined) return undefined;
|
|
1783
|
-
const remaining = deadlineUnixMs - Date.now();
|
|
1784
|
-
if (remaining <= 0) throw actorDeadlineExceeded(actorId);
|
|
1785
|
-
return Math.max(1, Math.ceil(remaining));
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
async function awaitBeforeDeadline<T>(
|
|
1789
|
-
operation: Promise<T>,
|
|
1790
|
-
actorId: string,
|
|
1791
|
-
remainingMs: number | undefined
|
|
1792
|
-
): Promise<T> {
|
|
1793
|
-
if (remainingMs === undefined) return await operation;
|
|
1794
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1795
|
-
try {
|
|
1796
|
-
return await Promise.race([
|
|
1797
|
-
operation,
|
|
1798
|
-
new Promise<never>((_resolve, reject) => {
|
|
1799
|
-
timer = setTimeout(() => reject(actorDeadlineExceeded(actorId)), remainingMs);
|
|
1800
|
-
})
|
|
1801
|
-
]);
|
|
1802
|
-
} finally {
|
|
1803
|
-
if (timer !== undefined) clearTimeout(timer);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
1978
|
async function waitForHandoffReplayStart(start: Promise<void>, signal: AbortSignal): Promise<void> {
|
|
1808
1979
|
if (signal.aborted) throw signal.reason;
|
|
1809
1980
|
let abort!: () => void;
|
|
@@ -1819,11 +1990,13 @@ async function waitForHandoffReplayStart(start: Promise<void>, signal: AbortSign
|
|
|
1819
1990
|
}
|
|
1820
1991
|
|
|
1821
1992
|
function messageFollowRouteKey(
|
|
1822
|
-
actorId: string,
|
|
1823
1993
|
objectGeneration: bigint,
|
|
1824
|
-
|
|
1994
|
+
nodeRidHex: string,
|
|
1995
|
+
nodeGeneration: bigint | string,
|
|
1996
|
+
authorityOwnerGeneration: bigint | string,
|
|
1997
|
+
ownerLeaseGeneration: bigint | string
|
|
1825
1998
|
): string {
|
|
1826
|
-
return `${
|
|
1999
|
+
return `${objectGeneration}\u0000${nodeRidHex}\u0000${nodeGeneration}\u0000${authorityOwnerGeneration}\u0000${ownerLeaseGeneration}`;
|
|
1827
2000
|
}
|
|
1828
2001
|
|
|
1829
2002
|
function actorRefKey(nodeRid: ActorRef['nodeRid'], generation: bigint): string {
|
|
@@ -1846,7 +2019,10 @@ function requestSourcesEqual(
|
|
|
1846
2019
|
expected.replyRouteId === actual.replyRouteId &&
|
|
1847
2020
|
expected.ownerId === actual.ownerId &&
|
|
1848
2021
|
expected.ownerLeaseGeneration === actual.ownerLeaseGeneration &&
|
|
1849
|
-
|
|
2022
|
+
routingIdsEqual(
|
|
2023
|
+
decodeRoutingId(expected.nodeRid, expected.nodeRidHex),
|
|
2024
|
+
decodeRoutingId(actual.nodeRid, actual.nodeRidHex)
|
|
2025
|
+
) &&
|
|
1850
2026
|
expected.nodeGeneration === actual.nodeGeneration &&
|
|
1851
2027
|
/^[1-9][0-9]*$/.test(actual.ownerLeaseGeneration) &&
|
|
1852
2028
|
/^[1-9][0-9]*$/.test(actual.nodeGeneration)
|
|
@@ -33,6 +33,8 @@ export interface ZLinkActorJoinRelocation {
|
|
|
33
33
|
readonly deadlineAtMs?: number;
|
|
34
34
|
readonly signal?: AbortSignal;
|
|
35
35
|
}): Promise<{
|
|
36
|
+
/** Source-only terminal after relay readiness transferred public completion. */
|
|
37
|
+
readonly sourceCleanup?: () => Promise<void>;
|
|
36
38
|
readonly actorRef: ZLinkBackendActorRef;
|
|
37
39
|
readonly membershipEpoch: bigint;
|
|
38
40
|
readonly spotGeneration: bigint;
|
|
@@ -471,6 +471,10 @@ export class ZLinkLocalNativeActorJoin {
|
|
|
471
471
|
admission.parts[0]?.close();
|
|
472
472
|
throw error;
|
|
473
473
|
}
|
|
474
|
+
if (relocated.sourceCleanup !== undefined) {
|
|
475
|
+
admission.parts[0]?.close();
|
|
476
|
+
return { accepted: false, sourceCleanup: relocated.sourceCleanup };
|
|
477
|
+
}
|
|
474
478
|
state.setNativeActorRef(relocated.actorRef);
|
|
475
479
|
if (entrySpot) {
|
|
476
480
|
state.clearJoinedSpot();
|