@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,7 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ServiceStatefulRuntime = void 0;
|
|
4
|
+
exports.sessionOwnerFenceMatches = sessionOwnerFenceMatches;
|
|
4
5
|
exports.statefulMailboxData = statefulMailboxData;
|
|
6
|
+
const abort_1 = require("../abort");
|
|
7
|
+
const channel_envelope_1 = require("../channels/channel-envelope");
|
|
8
|
+
const runtime_message_1 = require("../backend/runtime-message");
|
|
9
|
+
const dispatch_error_details_1 = require("../diagnostics/dispatch-error-details");
|
|
10
|
+
const service_wire_codec_generated_1 = require("../protocol/service_wire_codec.generated");
|
|
11
|
+
const routing_id_1 = require("../routing-id");
|
|
5
12
|
const stream_wire_1 = require("@zlink-systems/stream-wire");
|
|
6
13
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
7
14
|
const contracts_1 = require("../../contracts");
|
|
@@ -30,6 +37,16 @@ const SPOT_MOVING = 34;
|
|
|
30
37
|
const USER_SPOT_OPERATION_CAPACITY = 65_536;
|
|
31
38
|
const USER_SPOT_OPERATION_REPLAY_RETENTION_MS = 5 * 60_000;
|
|
32
39
|
const ACTOR_ROUTE_NOT_FOUND = 1;
|
|
40
|
+
/**
|
|
41
|
+
* The receiving Session owner compares the identity carried by command 42,
|
|
42
|
+
* 51 or 54 with its current values exactly (§4).
|
|
43
|
+
*/
|
|
44
|
+
function sessionOwnerFenceMatches(local, fence) {
|
|
45
|
+
return ((0, routing_id_1.routingIdsEqual)(fence.sessionOwnerNodeRid, local.nodeRid) &&
|
|
46
|
+
fence.sessionOwnerNodeGeneration === local.nodeGeneration &&
|
|
47
|
+
fence.sessionOwnerId === local.ownerId &&
|
|
48
|
+
fence.sessionOwnerLeaseGeneration === local.leaseGeneration);
|
|
49
|
+
}
|
|
33
50
|
/**
|
|
34
51
|
* Owns M6B routing, identity fences and terminal operations. Application turns
|
|
35
52
|
* remain in the common mailbox, where a claimed Spot or Actor owner is serial.
|
|
@@ -77,9 +94,11 @@ class ServiceStatefulRuntime {
|
|
|
77
94
|
asyncInstanceAuthority;
|
|
78
95
|
instanceApplicationLifecycle;
|
|
79
96
|
userSpotOperationHandler;
|
|
97
|
+
requestSourceAcceptance;
|
|
80
98
|
messageFollowHandler;
|
|
81
99
|
mailboxDropHandler;
|
|
82
100
|
dispatchErrors;
|
|
101
|
+
sessionOwnerDescriptors;
|
|
83
102
|
dispatchErrorMeshName;
|
|
84
103
|
admittedUserSpotOperations = new Map();
|
|
85
104
|
pendingInstanceActivations = new Map();
|
|
@@ -96,6 +115,43 @@ class ServiceStatefulRuntime {
|
|
|
96
115
|
setMailboxDropHandler(handler) {
|
|
97
116
|
this.mailboxDropHandler = handler;
|
|
98
117
|
}
|
|
118
|
+
setSessionOwnerDescriptors(source) {
|
|
119
|
+
this.sessionOwnerDescriptors = source;
|
|
120
|
+
}
|
|
121
|
+
/** §4: this host's Session owner identity, taken from its own descriptor. */
|
|
122
|
+
localSessionOwner() {
|
|
123
|
+
const token = this.sessionOwnerDescriptors?.local();
|
|
124
|
+
return token === undefined
|
|
125
|
+
? undefined
|
|
126
|
+
: {
|
|
127
|
+
nodeRid: this.nodeRid,
|
|
128
|
+
nodeGeneration: this.nodeGeneration,
|
|
129
|
+
ownerId: token.ownerId,
|
|
130
|
+
leaseGeneration: token.leaseGeneration
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* §4: the identity of the Session owner that requested a bind. It is this
|
|
135
|
+
* host's own descriptor, or the admitted peer descriptor of that exact
|
|
136
|
+
* lifecycle that passed the owner lease check. Without one the bind is
|
|
137
|
+
* rejected instead of storing a guessed identity.
|
|
138
|
+
*/
|
|
139
|
+
async sessionOwnerOf(nodeRid, nodeGeneration) {
|
|
140
|
+
const token = (0, routing_id_1.routingIdsEqual)(nodeRid, this.nodeRid)
|
|
141
|
+
? nodeGeneration === this.nodeGeneration
|
|
142
|
+
? this.sessionOwnerDescriptors?.local()
|
|
143
|
+
: undefined
|
|
144
|
+
: await this.sessionOwnerDescriptors?.peer(nodeRid, nodeGeneration);
|
|
145
|
+
if (token === undefined) {
|
|
146
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Session owner '${nodeRid}' has no live MeshNode descriptor for its lifecycle.`);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
nodeRid,
|
|
150
|
+
nodeGeneration,
|
|
151
|
+
ownerId: token.ownerId,
|
|
152
|
+
leaseGeneration: token.leaseGeneration
|
|
153
|
+
};
|
|
154
|
+
}
|
|
99
155
|
setDispatchErrorReporter(reporter, meshName) {
|
|
100
156
|
this.dispatchErrors = reporter;
|
|
101
157
|
this.dispatchErrorMeshName = meshName;
|
|
@@ -138,7 +194,7 @@ class ServiceStatefulRuntime {
|
|
|
138
194
|
const current = this.registry.binding(actor.ref);
|
|
139
195
|
if (current?.bindingGeneration === bindingGeneration &&
|
|
140
196
|
current.sessionOwnerNodeRid === sessionNodeRid &&
|
|
141
|
-
current.sessionRid
|
|
197
|
+
(0, routing_id_1.routingIdsEqual)(current.sessionRid, sessionRid)) {
|
|
142
198
|
return;
|
|
143
199
|
}
|
|
144
200
|
this.registry.installSessionBinding({
|
|
@@ -525,6 +581,56 @@ class ServiceStatefulRuntime {
|
|
|
525
581
|
setMessageFollowHandler(handler) {
|
|
526
582
|
this.messageFollowHandler = handler;
|
|
527
583
|
}
|
|
584
|
+
setRequestSourceAcceptance(acceptance) {
|
|
585
|
+
this.requestSourceAcceptance = acceptance;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Location runtime §9.3: the first accepting owner reads the sender's owner values once. A
|
|
589
|
+
* sender without a live descriptor ends the request Unavailable (Session·Actor binding §4). The
|
|
590
|
+
* polled descriptors answer without a promise; only a Store read returns one.
|
|
591
|
+
*/
|
|
592
|
+
acceptRequestSource(ingress, signal) {
|
|
593
|
+
if (ingress.requestSource !== undefined)
|
|
594
|
+
return undefined;
|
|
595
|
+
const acceptance = this.requestSourceAcceptance;
|
|
596
|
+
if (acceptance === undefined)
|
|
597
|
+
return undefined;
|
|
598
|
+
const generation = ingress.sourceNodeGeneration ?? this.tryPeerGeneration(ingress.sourceRoutingId);
|
|
599
|
+
const sourceRouteHex = ingress.sourceRoute === undefined || ingress.sourceRoute.length === 0
|
|
600
|
+
? undefined
|
|
601
|
+
: Buffer.from(ingress.sourceRoute).toString('hex');
|
|
602
|
+
const sourceRid = sourceRouteHex === undefined
|
|
603
|
+
? ingress.sourceRoutingId
|
|
604
|
+
: (0, routing_id_1.decodeRoutingId)(ingress.sourceRoutingId, sourceRouteHex);
|
|
605
|
+
const source = generation === undefined
|
|
606
|
+
? undefined
|
|
607
|
+
: acceptance(sourceRid, generation, sourceRouteHex ?? (0, routing_id_1.encodeRoutingIdStorageHex)(sourceRid), signal);
|
|
608
|
+
if (source instanceof Promise) {
|
|
609
|
+
return source.then((read) => this.recordRequestSource(ingress, read), (error) => {
|
|
610
|
+
if (error instanceof contracts_1.ZLinkFrameworkException &&
|
|
611
|
+
error.kind === contracts_1.ZLinkFrameworkErrorKind.Unavailable &&
|
|
612
|
+
this.dispatchErrors?.captureEnabled() === true) {
|
|
613
|
+
this.dispatchErrors.report({
|
|
614
|
+
surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.Node,
|
|
615
|
+
messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Request,
|
|
616
|
+
reason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget,
|
|
617
|
+
action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.ReplyError,
|
|
618
|
+
meshName: this.dispatchErrorMeshName,
|
|
619
|
+
sourceRid: ingress.sourceRoutingId,
|
|
620
|
+
error
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
throw error;
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
this.recordRequestSource(ingress, source);
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
629
|
+
recordRequestSource(ingress, source) {
|
|
630
|
+
if (source === undefined)
|
|
631
|
+
throw requestSourceUnavailable(ingress.sourceRoutingId);
|
|
632
|
+
ingress.requestSource = source;
|
|
633
|
+
}
|
|
528
634
|
sealSpotMessageFollowIngress(source) {
|
|
529
635
|
this.requireOpen();
|
|
530
636
|
if (source.targetNodeRid !== this.nodeRid ||
|
|
@@ -574,6 +680,10 @@ class ServiceStatefulRuntime {
|
|
|
574
680
|
const state = this.exactSpotMessageFollow(seal);
|
|
575
681
|
if (state === undefined || state.target !== undefined)
|
|
576
682
|
return false;
|
|
683
|
+
if (target === null) {
|
|
684
|
+
this.failExpiredSpotMessageFollow(state);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
577
687
|
if (!Number.isSafeInteger(durationMs) || durationMs < 0) {
|
|
578
688
|
throw new RangeError('Message Follow duration must be a non-negative safe integer.');
|
|
579
689
|
}
|
|
@@ -692,8 +802,8 @@ class ServiceStatefulRuntime {
|
|
|
692
802
|
this.submitRequest(pending, target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'spotRequest', undefined, onAdmitted);
|
|
693
803
|
return pending;
|
|
694
804
|
}
|
|
695
|
-
async sendToActor(target,
|
|
696
|
-
const route = this.tryActorFence(target);
|
|
805
|
+
async sendToActor(target, payload, sourceActor, boundSession, routeFence) {
|
|
806
|
+
const route = routeFence ?? this.tryActorFence(target);
|
|
697
807
|
if (route === undefined)
|
|
698
808
|
return runtime_values_1.SubmitResult.NotFound;
|
|
699
809
|
const header = (0, service_stateful_wire_codec_1.encodeActorHeader)('actorSend', route, undefined, sourceActor, boundSession === undefined
|
|
@@ -704,9 +814,10 @@ class ServiceStatefulRuntime {
|
|
|
704
814
|
}, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
|
|
705
815
|
return this.submitOneWay(target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
|
|
706
816
|
}
|
|
707
|
-
requestToActor(target,
|
|
708
|
-
const
|
|
709
|
-
const
|
|
817
|
+
requestToActor(target, payload, timeoutMs, sourceActor, boundSession, onAdmitted, routeFence) {
|
|
818
|
+
const operationLow = this.nextMessageFollowOperation++;
|
|
819
|
+
const pending = this.operations.register(timeoutMs, 'registry', operationLow);
|
|
820
|
+
const route = routeFence ?? this.tryActorFence(target);
|
|
710
821
|
if (route === undefined) {
|
|
711
822
|
this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
|
|
712
823
|
return pending;
|
|
@@ -716,10 +827,18 @@ class ServiceStatefulRuntime {
|
|
|
716
827
|
: {
|
|
717
828
|
...boundSession,
|
|
718
829
|
sequence: this.nextSessionSequence++
|
|
719
|
-
}, { high: this.nodeGeneration, low:
|
|
830
|
+
}, { high: this.nodeGeneration, low: operationLow });
|
|
720
831
|
this.submitRequest(pending, target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'actorRequest', undefined, onAdmitted);
|
|
721
832
|
return pending;
|
|
722
833
|
}
|
|
834
|
+
acceptRelocatedActorTerminal(operation, replyRouteId, result) {
|
|
835
|
+
if (operation.high !== this.nodeGeneration ||
|
|
836
|
+
this.operations.context(replyRouteId) !== operation.low)
|
|
837
|
+
return undefined;
|
|
838
|
+
return this.operations.reply(replyRouteId, result, service_stateful_registry_1.RELOCATION_REPLY_RETENTION_MS)
|
|
839
|
+
? 'terminalReceived'
|
|
840
|
+
: 'alreadyTerminal';
|
|
841
|
+
}
|
|
723
842
|
async sendToInstanceSpot(route, payload, sourceSpotId, metadataFrame, instanceIntent = false) {
|
|
724
843
|
return this.submitOneWay(route.targetNodeRid, instanceOperationParts([
|
|
725
844
|
(0, service_stateful_wire_codec_1.encodeInstanceSpotHeader)(route, this.nodeGeneration, this.nodeRid, sourceSpotId, 'send', { high: 0n, low: 0n }, undefined, metadataFrame !== undefined, instanceIntent),
|
|
@@ -844,26 +963,40 @@ class ServiceStatefulRuntime {
|
|
|
844
963
|
});
|
|
845
964
|
return pending;
|
|
846
965
|
}
|
|
847
|
-
bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority) {
|
|
966
|
+
bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority, close) {
|
|
848
967
|
const deadlineMs = performance.now() + timeoutMs;
|
|
849
968
|
const pending = this.operations.register(timeoutMs, 'sender');
|
|
850
|
-
const
|
|
969
|
+
const sessionOwner = this.localSessionOwner();
|
|
970
|
+
if (sessionOwner === undefined) {
|
|
971
|
+
this.operations.reply(pending.id, failure((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Session owner '${this.nodeRid}' has no live MeshNode descriptor.`)));
|
|
972
|
+
return pending;
|
|
973
|
+
}
|
|
974
|
+
const deliveryKey = actorKey(actor);
|
|
975
|
+
const previousDelivery = this.sessionDeliveries.get(deliveryKey);
|
|
976
|
+
const previousBinding = previousDelivery?.binding;
|
|
977
|
+
const generation = previousBinding !== undefined &&
|
|
978
|
+
sameActorRef(previousBinding.actor, actor) &&
|
|
979
|
+
previousBinding.sessionRid === sessionRid &&
|
|
980
|
+
previousBinding.sessionOwnerNodeRid === sessionOwner.nodeRid &&
|
|
981
|
+
previousBinding.sessionOwnerNodeGeneration === sessionOwner.nodeGeneration
|
|
982
|
+
? previousBinding.bindingGeneration
|
|
983
|
+
: this.nextSessionSequence++;
|
|
851
984
|
const localBinding = {
|
|
852
985
|
actor,
|
|
853
986
|
sessionRid,
|
|
854
|
-
sessionOwnerNodeRid:
|
|
855
|
-
sessionOwnerNodeGeneration:
|
|
856
|
-
sessionOwnerId:
|
|
857
|
-
sessionOwnerLeaseGeneration:
|
|
987
|
+
sessionOwnerNodeRid: sessionOwner.nodeRid,
|
|
988
|
+
sessionOwnerNodeGeneration: sessionOwner.nodeGeneration,
|
|
989
|
+
sessionOwnerId: sessionOwner.ownerId,
|
|
990
|
+
sessionOwnerLeaseGeneration: sessionOwner.leaseGeneration,
|
|
858
991
|
bindingGeneration: generation,
|
|
859
992
|
membershipEpoch: this.registry.actor(actor.actorId)?.membershipEpoch ?? 1n
|
|
860
993
|
};
|
|
861
994
|
const delivery = {
|
|
862
995
|
binding: localBinding,
|
|
863
996
|
deliver,
|
|
997
|
+
...(close === undefined ? {} : { close }),
|
|
864
998
|
...(onBindingReplaced === undefined ? {} : { onBindingReplaced })
|
|
865
999
|
};
|
|
866
|
-
const deliveryKey = actorKey(actor);
|
|
867
1000
|
if (actor.nodeRid === this.nodeRid) {
|
|
868
1001
|
let installedDelivery;
|
|
869
1002
|
try {
|
|
@@ -886,11 +1019,7 @@ class ServiceStatefulRuntime {
|
|
|
886
1019
|
});
|
|
887
1020
|
return pending;
|
|
888
1021
|
}
|
|
889
|
-
const
|
|
890
|
-
const binding = this.registry.bindSession(actor, sessionRid, this.nodeRid, this.nodeGeneration, this.nodeRid, this.nodeGeneration);
|
|
891
|
-
if (previousDelivery !== undefined && previous !== undefined) {
|
|
892
|
-
this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
|
|
893
|
-
}
|
|
1022
|
+
const binding = this.registry.installSessionBinding(localBinding);
|
|
894
1023
|
installedDelivery = { ...delivery, binding };
|
|
895
1024
|
this.sessionDeliveries.set(deliveryKey, installedDelivery);
|
|
896
1025
|
this.operations.reply(pending.id, {
|
|
@@ -898,7 +1027,10 @@ class ServiceStatefulRuntime {
|
|
|
898
1027
|
failureCode: 0,
|
|
899
1028
|
kindData: undefined
|
|
900
1029
|
});
|
|
901
|
-
if (previous !== undefined) {
|
|
1030
|
+
if (previous !== undefined && previous !== binding) {
|
|
1031
|
+
if (previousDelivery !== undefined) {
|
|
1032
|
+
this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
|
|
1033
|
+
}
|
|
902
1034
|
this.sendBoundSessionReplacement(previous, actorAuthorityFromRoute(this.tryActorFence(actor) ?? {
|
|
903
1035
|
actor,
|
|
904
1036
|
targetNodeGeneration: this.nodeGeneration,
|
|
@@ -916,7 +1048,6 @@ class ServiceStatefulRuntime {
|
|
|
916
1048
|
}
|
|
917
1049
|
return pending;
|
|
918
1050
|
}
|
|
919
|
-
const previousDelivery = this.sessionDeliveries.get(deliveryKey);
|
|
920
1051
|
let bindingActorFence;
|
|
921
1052
|
let header;
|
|
922
1053
|
try {
|
|
@@ -954,7 +1085,10 @@ class ServiceStatefulRuntime {
|
|
|
954
1085
|
// Publish the exact Location authority used by command 38 in the
|
|
955
1086
|
// same Session-owner completion turn as the binding route. Actor
|
|
956
1087
|
// lookup only carries a peer-lifecycle fallback for owner lease.
|
|
957
|
-
this.rememberActorRoute(
|
|
1088
|
+
this.rememberActorRoute({
|
|
1089
|
+
...bindingActorFence,
|
|
1090
|
+
authorityOwnerGeneration: result.streamBinding.authorityOwnerGeneration
|
|
1091
|
+
});
|
|
958
1092
|
this.sessionDeliveries.set(deliveryKey, committed);
|
|
959
1093
|
}
|
|
960
1094
|
}
|
|
@@ -962,11 +1096,38 @@ class ServiceStatefulRuntime {
|
|
|
962
1096
|
})
|
|
963
1097
|
};
|
|
964
1098
|
}
|
|
1099
|
+
closeBoundSession(actor, expectedBindingGeneration, timeoutMs) {
|
|
1100
|
+
const pending = this.operations.register(timeoutMs);
|
|
1101
|
+
const binding = this.registry.binding(actor);
|
|
1102
|
+
if (binding === undefined) {
|
|
1103
|
+
this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound));
|
|
1104
|
+
return pending;
|
|
1105
|
+
}
|
|
1106
|
+
const header = Buffer.from((0, service_wire_codec_generated_1.encodeBoundSessionCloseCommand)({
|
|
1107
|
+
command: 'boundSessionClose',
|
|
1108
|
+
flags: 0,
|
|
1109
|
+
correlation: pending.id,
|
|
1110
|
+
actor: { actorId: actor.actorId, objectGeneration: actor.generation },
|
|
1111
|
+
session: {
|
|
1112
|
+
sessionOwnerNodeRid: Buffer.from((0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionOwnerNodeRid), 'hex'),
|
|
1113
|
+
sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
|
|
1114
|
+
sessionOwnerId: binding.sessionOwnerId,
|
|
1115
|
+
sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
|
|
1116
|
+
sessionRid: Buffer.from((0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionRid), 'hex'),
|
|
1117
|
+
retiredBindingGeneration: expectedBindingGeneration
|
|
1118
|
+
}
|
|
1119
|
+
}, {})[0]);
|
|
1120
|
+
const reply = (0, routing_id_1.routingIdsEqual)(binding.sessionOwnerNodeRid, this.nodeRid)
|
|
1121
|
+
? this.requestLocalInfrastructure(header, pending.id, timeoutMs)
|
|
1122
|
+
: this.raw.requestService(binding.sessionOwnerNodeRid, [header], timeoutMs);
|
|
1123
|
+
void reply.then((parts) => this.completeRemoteReply(pending, binding.sessionOwnerNodeRid, 'boundSessionClose', undefined, parts), (error) => this.operations.fail(pending.id, error));
|
|
1124
|
+
return pending;
|
|
1125
|
+
}
|
|
965
1126
|
unbindSession(sessionRid, actor, expectedBindingGeneration, timeoutMs) {
|
|
966
1127
|
const pending = this.operations.register(timeoutMs);
|
|
967
1128
|
const delivery = this.sessionDeliveries.get(actorKey(actor));
|
|
968
1129
|
if (delivery === undefined ||
|
|
969
|
-
delivery.binding.sessionRid
|
|
1130
|
+
!(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid) ||
|
|
970
1131
|
delivery.binding.bindingGeneration !== expectedBindingGeneration) {
|
|
971
1132
|
this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
|
|
972
1133
|
return pending;
|
|
@@ -992,7 +1153,7 @@ class ServiceStatefulRuntime {
|
|
|
992
1153
|
sessionBindings(sessionRid) {
|
|
993
1154
|
return [...this.sessionDeliveries.values()]
|
|
994
1155
|
.map((value) => value.binding)
|
|
995
|
-
.filter((binding) => binding.sessionRid
|
|
1156
|
+
.filter((binding) => (0, routing_id_1.routingIdsEqual)(binding.sessionRid, sessionRid))
|
|
996
1157
|
.map((binding) => {
|
|
997
1158
|
const owner = requireSessionOwnerIdentity(binding);
|
|
998
1159
|
return {
|
|
@@ -1008,10 +1169,10 @@ class ServiceStatefulRuntime {
|
|
|
1008
1169
|
}
|
|
1009
1170
|
async sendSessionToActor(sessionRid, actor, payload) {
|
|
1010
1171
|
const delivery = this.sessionDeliveries.get(actorKey(actor));
|
|
1011
|
-
if (delivery === undefined || delivery.binding.sessionRid
|
|
1172
|
+
if (delivery === undefined || !(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid)) {
|
|
1012
1173
|
return runtime_values_1.SubmitResult.NotFound;
|
|
1013
1174
|
}
|
|
1014
|
-
return this.sendToActor(actor,
|
|
1175
|
+
return this.sendToActor(actor, payload, undefined, {
|
|
1015
1176
|
sessionRid,
|
|
1016
1177
|
bindingGeneration: delivery.binding.bindingGeneration
|
|
1017
1178
|
});
|
|
@@ -1045,6 +1206,10 @@ class ServiceStatefulRuntime {
|
|
|
1045
1206
|
get pendingOperationCount() {
|
|
1046
1207
|
return this.operations.size;
|
|
1047
1208
|
}
|
|
1209
|
+
/** The next stateful request expiry, as a lower bound. */
|
|
1210
|
+
nextMaintenanceDeadlineMs() {
|
|
1211
|
+
return this.operations.nextDeadlineMs();
|
|
1212
|
+
}
|
|
1048
1213
|
close() {
|
|
1049
1214
|
if (this.closed)
|
|
1050
1215
|
return;
|
|
@@ -1070,6 +1235,9 @@ class ServiceStatefulRuntime {
|
|
|
1070
1235
|
}
|
|
1071
1236
|
this.spotMessageFollow.clear();
|
|
1072
1237
|
}
|
|
1238
|
+
cancelPendingOperations(reason) {
|
|
1239
|
+
this.operations.failAll(reason);
|
|
1240
|
+
}
|
|
1073
1241
|
async ingress(record) {
|
|
1074
1242
|
let decoded;
|
|
1075
1243
|
let canonicalActorJoin;
|
|
@@ -1110,7 +1278,8 @@ class ServiceStatefulRuntime {
|
|
|
1110
1278
|
decoded.kind === 'userSpotClose' ||
|
|
1111
1279
|
decoded.kind === 'actorCreate' ||
|
|
1112
1280
|
decoded.kind === 'messageFollow' ||
|
|
1113
|
-
decoded.kind === 'boundSessionReplaced'
|
|
1281
|
+
decoded.kind === 'boundSessionReplaced' ||
|
|
1282
|
+
decoded.kind === 'boundSessionClose';
|
|
1114
1283
|
if (record.parts.length < 1 ||
|
|
1115
1284
|
record.parts.length > (instanceMetadata || statefulMetadata ? 3 : 2) ||
|
|
1116
1285
|
(hasPayload &&
|
|
@@ -1142,7 +1311,7 @@ class ServiceStatefulRuntime {
|
|
|
1142
1311
|
if (decoded.kind === 'instanceSpot' &&
|
|
1143
1312
|
decoded.activation === 'missing' &&
|
|
1144
1313
|
(error instanceof contracts_1.ZLinkFrameworkException || error instanceof service_stateful_registry_1.ServiceStaleGenerationError)) {
|
|
1145
|
-
this.finishMissingInstanceActivationFailure(record, decoded, error);
|
|
1314
|
+
this.finishMissingInstanceActivationFailure(record, decoded, error, undefined, payloadFrame);
|
|
1146
1315
|
return 'infrastructure';
|
|
1147
1316
|
}
|
|
1148
1317
|
const correlation = statefulCorrelation(decoded);
|
|
@@ -1246,7 +1415,7 @@ class ServiceStatefulRuntime {
|
|
|
1246
1415
|
: this.validateActorFence(record.target);
|
|
1247
1416
|
if (record.boundSession !== undefined) {
|
|
1248
1417
|
const binding = this.registry.validateBoundSession(record.target.actor, record.boundSession.bindingGeneration);
|
|
1249
|
-
if (binding.sessionRid
|
|
1418
|
+
if (!(0, routing_id_1.routingIdsEqual)(binding.sessionRid, record.boundSession.sessionRid) ||
|
|
1250
1419
|
binding.sessionOwnerNodeRid !== ingress.sourceRoutingId) {
|
|
1251
1420
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('binding', record.target.actor.actorId);
|
|
1252
1421
|
}
|
|
@@ -1263,12 +1432,13 @@ class ServiceStatefulRuntime {
|
|
|
1263
1432
|
: { sourceBindingGeneration: record.boundSession.bindingGeneration }),
|
|
1264
1433
|
targetActor: actor.ref,
|
|
1265
1434
|
messageFollowOrigin: {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
high: this.peerGeneration(ingress.sourceRoutingId),
|
|
1269
|
-
low: record.correlation ?? this.nextMessageFollowOperation++
|
|
1435
|
+
get requestSource() {
|
|
1436
|
+
return ingress.requestSource;
|
|
1270
1437
|
},
|
|
1271
|
-
|
|
1438
|
+
target: record.target,
|
|
1439
|
+
sourceNodeRid: ingress.sourceRoutingId,
|
|
1440
|
+
originalOperation: record.operation,
|
|
1441
|
+
originalReplyRouteId: record.correlation ?? 0n
|
|
1272
1442
|
},
|
|
1273
1443
|
...(record.kind === 'actorRequest'
|
|
1274
1444
|
? { reply: this.replyPort(ingress, record.correlation) }
|
|
@@ -1292,7 +1462,9 @@ class ServiceStatefulRuntime {
|
|
|
1292
1462
|
this.validateSpotFence(record.target);
|
|
1293
1463
|
return this.enqueueActorJoin(ingress, record, payloadFrame, canonicalActorJoin, canonicalActorJoinPayload);
|
|
1294
1464
|
case 'boundSessionBind':
|
|
1295
|
-
return this.replySessionBind(ingress, record);
|
|
1465
|
+
return await this.replySessionBind(ingress, record);
|
|
1466
|
+
case 'boundSessionClose':
|
|
1467
|
+
return await this.handleBoundSessionClose(ingress, record);
|
|
1296
1468
|
case 'boundSessionReplaced':
|
|
1297
1469
|
return this.handleBoundSessionReplaced(ingress, record);
|
|
1298
1470
|
case 'boundSessionSend':
|
|
@@ -1429,7 +1601,7 @@ class ServiceStatefulRuntime {
|
|
|
1429
1601
|
});
|
|
1430
1602
|
}
|
|
1431
1603
|
catch (error) {
|
|
1432
|
-
this.finishMissingInstanceActivationFailure(ingress, record, error, localReply);
|
|
1604
|
+
this.finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame);
|
|
1433
1605
|
}
|
|
1434
1606
|
}
|
|
1435
1607
|
async continueReadyInstanceMaterialization(ingress, record, payloadFrame, metadataFrame) {
|
|
@@ -1452,6 +1624,7 @@ class ServiceStatefulRuntime {
|
|
|
1452
1624
|
const refreshedRecord = latestRoute !== undefined && sameInstanceApplicationOwner(latestRoute, record.route)
|
|
1453
1625
|
? { ...record, route: latestRoute }
|
|
1454
1626
|
: record;
|
|
1627
|
+
this.publishCommittedInstanceRoute(intent.instanceType, refreshedRecord.route);
|
|
1455
1628
|
const spot = this.requireInstanceActivation(ingress, refreshedRecord);
|
|
1456
1629
|
const admitted = this.enqueueActivatedInstanceSpot(ingress, record, payloadFrame, spot, undefined, this.instanceApplicationTerminalCompletion(this.instanceApplicationTarget(refreshedRecord)), metadataFrame, undefined, this.instanceApplicationTarget(refreshedRecord));
|
|
1457
1630
|
if (admitted !== 'application') {
|
|
@@ -1573,7 +1746,7 @@ class ServiceStatefulRuntime {
|
|
|
1573
1746
|
for (const waiter of waiters)
|
|
1574
1747
|
waiter();
|
|
1575
1748
|
}
|
|
1576
|
-
finishMissingInstanceActivationFailure(ingress, record, error, localReply) {
|
|
1749
|
+
finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame) {
|
|
1577
1750
|
if (record.operationKind === 'request') {
|
|
1578
1751
|
if (record.deadlineUnixMs <= BigInt(Date.now()))
|
|
1579
1752
|
return;
|
|
@@ -1587,17 +1760,46 @@ class ServiceStatefulRuntime {
|
|
|
1587
1760
|
return;
|
|
1588
1761
|
}
|
|
1589
1762
|
const reporter = this.dispatchErrors;
|
|
1763
|
+
const tracePoint = (0, message_flow_1.flowIfEnabled)(reporter?.flow, ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped);
|
|
1764
|
+
if (tracePoint === undefined && reporter?.captureEnabled() !== true)
|
|
1765
|
+
return;
|
|
1766
|
+
const reason = (0, abort_1.isAbortError)(error)
|
|
1767
|
+
? ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.Shutdown
|
|
1768
|
+
: (0, dispatch_error_details_1.dispatchReasonFromError)(error);
|
|
1769
|
+
// Decode the retained first message only after diagnostics accepts the terminal.
|
|
1770
|
+
// Detached local and remote activation share this owner and its explicit flow.
|
|
1771
|
+
const payload = payloadFrame === undefined ? undefined : (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payloadFrame);
|
|
1772
|
+
const header = payload?.contentType === service_wire_constants_generated_1.SERVICE_FRAMEWORK_MULTIPART_CONTENT_TYPE
|
|
1773
|
+
? (0, channel_envelope_1.decodeChannelHeader)((0, service_wire_m6a_codec_1.decodeMultipartApplicationParts)(payloadFrame, runtime_message_1.ZLinkBufferMessage.fromOwned), reporter?.flow.flowCreationEnabled())
|
|
1774
|
+
: undefined;
|
|
1775
|
+
const context = {
|
|
1776
|
+
surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.InstanceSpot,
|
|
1777
|
+
messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
|
|
1778
|
+
meshName: this.dispatchErrorMeshName,
|
|
1779
|
+
sourceRid: record.sourceNodeRid,
|
|
1780
|
+
spotId: record.target.targetSpotId,
|
|
1781
|
+
instanceSpotType: record.target.stableType,
|
|
1782
|
+
activationState: 'activating',
|
|
1783
|
+
packetName: header?.messageName ?? payload?.packetName,
|
|
1784
|
+
flowId: header?.flowId,
|
|
1785
|
+
flowOrigin: header?.flowOrigin
|
|
1786
|
+
};
|
|
1787
|
+
tracePoint?.trace({
|
|
1788
|
+
...context,
|
|
1789
|
+
outcome: ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped,
|
|
1790
|
+
errorReason: reason === ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.Shutdown
|
|
1791
|
+
? reason
|
|
1792
|
+
: error instanceof contracts_1.ZLinkFrameworkException &&
|
|
1793
|
+
error.kind === contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded
|
|
1794
|
+
? 'activation_timeout'
|
|
1795
|
+
: 'activation_rejected',
|
|
1796
|
+
...(0, dispatch_error_details_1.dispatchErrorDetails)(error)
|
|
1797
|
+
});
|
|
1590
1798
|
if (reporter?.captureEnabled() === true) {
|
|
1591
1799
|
reporter.report({
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
reason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget,
|
|
1800
|
+
...context,
|
|
1801
|
+
reason,
|
|
1595
1802
|
action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.Drop,
|
|
1596
|
-
meshName: this.dispatchErrorMeshName,
|
|
1597
|
-
sourceRid: record.sourceNodeRid,
|
|
1598
|
-
spotId: record.target.targetSpotId,
|
|
1599
|
-
instanceSpotType: record.target.stableType,
|
|
1600
|
-
activationState: 'activating',
|
|
1601
1803
|
error
|
|
1602
1804
|
});
|
|
1603
1805
|
}
|
|
@@ -1736,11 +1938,17 @@ class ServiceStatefulRuntime {
|
|
|
1736
1938
|
activateMissingInstanceAsync(record, payloadFrame, metadataFrame, admit) {
|
|
1737
1939
|
const key = record.target.targetSpotId;
|
|
1738
1940
|
const pending = this.pendingInstanceActivations.get(key);
|
|
1941
|
+
const metric = pending === undefined
|
|
1942
|
+
? this.dispatchErrors?.metrics?.startInstanceSpotActivation(record.target.targetMeshName, record.target.stableType)
|
|
1943
|
+
: undefined;
|
|
1739
1944
|
const ready = pending ??
|
|
1740
|
-
this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) =>
|
|
1741
|
-
|
|
1742
|
-
stableType: record.target.stableType
|
|
1743
|
-
})
|
|
1945
|
+
this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) => {
|
|
1946
|
+
metric?.complete('ready');
|
|
1947
|
+
return { ...activation, stableType: record.target.stableType };
|
|
1948
|
+
}, (error) => {
|
|
1949
|
+
metric?.complete(instanceActivationOutcome(error));
|
|
1950
|
+
throw error;
|
|
1951
|
+
});
|
|
1744
1952
|
const operation = ready.then(async (value) => {
|
|
1745
1953
|
if (pending !== undefined) {
|
|
1746
1954
|
await this.asyncInstanceAuthority?.read(record.target, undefined, {
|
|
@@ -1768,10 +1976,24 @@ class ServiceStatefulRuntime {
|
|
|
1768
1976
|
return operation;
|
|
1769
1977
|
}
|
|
1770
1978
|
async runMissingInstanceActivation(record, payloadFrame, metadataFrame) {
|
|
1979
|
+
const deadline = operationDeadline(record.deadlineUnixMs);
|
|
1980
|
+
try {
|
|
1981
|
+
deadline.signal.throwIfAborted();
|
|
1982
|
+
return await (0, abort_1.awaitWithAbort)(this.runMissingInstanceActivationCore(record, payloadFrame, metadataFrame, deadline.signal), deadline.signal);
|
|
1983
|
+
}
|
|
1984
|
+
catch (error) {
|
|
1985
|
+
if ((0, abort_1.isAbortError)(error) && deadline.signal.aborted)
|
|
1986
|
+
throw deadline.signal.reason;
|
|
1987
|
+
throw error;
|
|
1988
|
+
}
|
|
1989
|
+
finally {
|
|
1990
|
+
deadline.close();
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
async runMissingInstanceActivationCore(record, payloadFrame, metadataFrame, signal) {
|
|
1771
1994
|
const target = record.target;
|
|
1772
1995
|
if (target.targetNodeRid !== this.nodeRid ||
|
|
1773
|
-
target.targetNodeGeneration !== this.nodeGeneration
|
|
1774
|
-
record.deadlineUnixMs < BigInt(Date.now())) {
|
|
1996
|
+
target.targetNodeGeneration !== this.nodeGeneration) {
|
|
1775
1997
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1776
1998
|
}
|
|
1777
1999
|
const authority = this.asyncInstanceAuthority;
|
|
@@ -1865,21 +2087,18 @@ class ServiceStatefulRuntime {
|
|
|
1865
2087
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1866
2088
|
}
|
|
1867
2089
|
}
|
|
1868
|
-
const
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
finally {
|
|
1874
|
-
deadline.close();
|
|
1875
|
-
}
|
|
1876
|
-
if (this.closed || record.deadlineUnixMs < BigInt(Date.now())) {
|
|
2090
|
+
const reserved = await authority.reserve(activationRequest, signal);
|
|
2091
|
+
if (this.closed || signal.aborted) {
|
|
2092
|
+
const error = new contracts_1.ZLinkFrameworkException(this.closed
|
|
2093
|
+
? contracts_1.ZLinkFrameworkErrorKind.ShuttingDown
|
|
2094
|
+
: contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded, this.closed ? 'Runtime stopped during Instance activation.' : 'Operation deadline exceeded.');
|
|
1877
2095
|
await authority.abort(target, reserved.reservation);
|
|
1878
|
-
throw
|
|
2096
|
+
throw error;
|
|
1879
2097
|
}
|
|
1880
2098
|
let activation;
|
|
1881
2099
|
try {
|
|
1882
2100
|
await this.instanceApplicationLifecycle?.materialize(target, reserved.reservation.attempt);
|
|
2101
|
+
signal.throwIfAborted();
|
|
1883
2102
|
activation = this.activateInstanceSpot(target.targetSpotId, target.stableType, reserved.reservation.attempt, reserved.reservation.authorityOwnerGeneration);
|
|
1884
2103
|
}
|
|
1885
2104
|
catch (error) {
|
|
@@ -1925,7 +2144,6 @@ class ServiceStatefulRuntime {
|
|
|
1925
2144
|
this.registry.closeSpot(activation.spot.ref);
|
|
1926
2145
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1927
2146
|
}
|
|
1928
|
-
this.publishCommittedInstanceRoute(target.stableType, route);
|
|
1929
2147
|
const confirmed = await authority.read(target);
|
|
1930
2148
|
if (confirmed.kind !== 'ready' || !sameInstanceRoute(confirmed.route, route)) {
|
|
1931
2149
|
if (confirmed.kind === 'ready' && confirmed.route.targetNodeRid !== this.nodeRid) {
|
|
@@ -1938,6 +2156,7 @@ class ServiceStatefulRuntime {
|
|
|
1938
2156
|
!routeMatchesLocal(confirmed.route, current, this.nodeRid, this.nodeGeneration)) {
|
|
1939
2157
|
throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
|
|
1940
2158
|
}
|
|
2159
|
+
this.publishCommittedInstanceRoute(target.stableType, confirmed.route);
|
|
1941
2160
|
return { spot: current, route: confirmed.route };
|
|
1942
2161
|
}
|
|
1943
2162
|
publishCommittedInstanceRoute(stableType, route, expectedCurrentRoute) {
|
|
@@ -1949,6 +2168,9 @@ class ServiceStatefulRuntime {
|
|
|
1949
2168
|
: instanceRouteAsDirectRoute(expectedCurrentRoute);
|
|
1950
2169
|
this.rememberSpotRoute(directRoute, expectedDirectRoute);
|
|
1951
2170
|
this.registerInstanceIntent(stableType, route, expectedCurrentRoute);
|
|
2171
|
+
const target = this.instanceSpotApplicationTarget(route.targetSpotId);
|
|
2172
|
+
if (target !== undefined)
|
|
2173
|
+
this.instanceApplicationLifecycle?.publish?.({ targetSpotId: route.targetSpotId, ...target });
|
|
1952
2174
|
}
|
|
1953
2175
|
replaceCommittedInstanceRoute(stableType, previous, next) {
|
|
1954
2176
|
const current = this.instanceIntents.get(previous.targetSpotId);
|
|
@@ -2057,39 +2279,30 @@ class ServiceStatefulRuntime {
|
|
|
2057
2279
|
}
|
|
2058
2280
|
return 'infrastructure';
|
|
2059
2281
|
}
|
|
2060
|
-
replySessionBind(ingress, record) {
|
|
2282
|
+
async replySessionBind(ingress, record) {
|
|
2061
2283
|
try {
|
|
2062
2284
|
if (record.binding.state === 'active') {
|
|
2285
|
+
const sessionOwner = await this.sessionOwnerOf(ingress.sourceRoutingId, ingress.sourceNodeGeneration ?? this.peerGeneration(ingress.sourceRoutingId));
|
|
2063
2286
|
const actor = this.validateActorFence(record.actor);
|
|
2064
|
-
const
|
|
2065
|
-
|
|
2066
|
-
const binding = (0, service_stateful_wire_codec_1.sessionBindingFromWire)(actor.ref, record.sessionRid, ingress.sourceRoutingId, record.binding.generation, actor.membershipEpoch, sourceGeneration, ingress.sourceRoutingId, sourceGeneration);
|
|
2067
|
-
if (previous !== undefined && sameSessionIdentity(previous, binding)) {
|
|
2068
|
-
// Registry publication is the last step of the first binding owner
|
|
2069
|
-
// turn, so an observable same-Session binding already has every
|
|
2070
|
-
// Actor route projection installed and can complete idempotently.
|
|
2071
|
-
this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0, undefined, {
|
|
2072
|
-
kind: 'streamBind',
|
|
2073
|
-
bindingGeneration: previous.bindingGeneration,
|
|
2074
|
-
authorityOwnerGeneration: actor.authorityOwnerGeneration
|
|
2075
|
-
});
|
|
2076
|
-
return 'infrastructure';
|
|
2077
|
-
}
|
|
2287
|
+
const binding = (0, service_stateful_wire_codec_1.sessionBindingFromWire)(actor.ref, record.sessionRid, sessionOwner.nodeRid, record.binding.generation, actor.membershipEpoch, sessionOwner.nodeGeneration, sessionOwner.ownerId, sessionOwner.leaseGeneration);
|
|
2288
|
+
let completedBinding = binding;
|
|
2078
2289
|
const accepted = this.enqueueActorBindingControl(ingress, binding, record.actor, (terminalResult, failureCode) => {
|
|
2079
|
-
let completedBinding = binding;
|
|
2080
2290
|
let replacedBinding;
|
|
2081
2291
|
if (terminalResult === runtime_values_1.RequestResult.Ok) {
|
|
2082
2292
|
// This callback runs inside the Actor binding control turn,
|
|
2083
|
-
//
|
|
2293
|
+
// before the Host copies the accepted Actor-to-session projection.
|
|
2084
2294
|
// Publish the authority-owned registry view in that same turn
|
|
2085
2295
|
// before making the terminal reply observable.
|
|
2086
2296
|
const turnCurrent = this.registry.binding(actor.ref);
|
|
2087
|
-
|
|
2088
|
-
completedBinding =
|
|
2297
|
+
try {
|
|
2298
|
+
completedBinding = this.registry.installSessionBinding(binding);
|
|
2299
|
+
if (turnCurrent !== completedBinding)
|
|
2300
|
+
replacedBinding = turnCurrent;
|
|
2089
2301
|
}
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
this.
|
|
2302
|
+
catch (error) {
|
|
2303
|
+
const result = failure(error);
|
|
2304
|
+
this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
|
|
2305
|
+
return false;
|
|
2093
2306
|
}
|
|
2094
2307
|
}
|
|
2095
2308
|
this.replyWire(ingress, record.correlation, terminalResult, failureCode, undefined, terminalResult === runtime_values_1.RequestResult.Ok
|
|
@@ -2108,7 +2321,7 @@ class ServiceStatefulRuntime {
|
|
|
2108
2321
|
}));
|
|
2109
2322
|
}
|
|
2110
2323
|
return true;
|
|
2111
|
-
});
|
|
2324
|
+
}, () => completedBinding);
|
|
2112
2325
|
if (!accepted) {
|
|
2113
2326
|
const result = failure((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Actor '${actor.ref.actorId}' no longer accepts session bindings.`));
|
|
2114
2327
|
this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
|
|
@@ -2124,6 +2337,29 @@ class ServiceStatefulRuntime {
|
|
|
2124
2337
|
}
|
|
2125
2338
|
return 'infrastructure';
|
|
2126
2339
|
}
|
|
2340
|
+
async handleBoundSessionClose(ingress, record) {
|
|
2341
|
+
if (ingress.requestSequence === undefined)
|
|
2342
|
+
return 'protocolError';
|
|
2343
|
+
try {
|
|
2344
|
+
const delivery = this.sessionDeliveries.get(actorKey(record.actor));
|
|
2345
|
+
const sessionOwner = this.localSessionOwner();
|
|
2346
|
+
if (sessionOwner === undefined ||
|
|
2347
|
+
!sessionOwnerFenceMatches(sessionOwner, record.session) ||
|
|
2348
|
+
delivery === undefined ||
|
|
2349
|
+
delivery.binding.actor.generation !== record.actor.generation ||
|
|
2350
|
+
!exactRetiredDelivery(delivery.binding, record.session) ||
|
|
2351
|
+
delivery.close === undefined) {
|
|
2352
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, 'The requested session binding is no longer current.');
|
|
2353
|
+
}
|
|
2354
|
+
await delivery.close();
|
|
2355
|
+
this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0);
|
|
2356
|
+
}
|
|
2357
|
+
catch (error) {
|
|
2358
|
+
const result = failure(error);
|
|
2359
|
+
this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
|
|
2360
|
+
}
|
|
2361
|
+
return 'infrastructure';
|
|
2362
|
+
}
|
|
2127
2363
|
/**
|
|
2128
2364
|
* Handles the replacement notice at the retired session owner. This path
|
|
2129
2365
|
* intentionally never calls validateActorFence(): the notice is authorized
|
|
@@ -2143,10 +2379,13 @@ class ServiceStatefulRuntime {
|
|
|
2143
2379
|
// session that belongs to the new lifecycle.
|
|
2144
2380
|
return 'infrastructure';
|
|
2145
2381
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2382
|
+
const sessionOwner = this.localSessionOwner();
|
|
2383
|
+
if (sessionOwner === undefined) {
|
|
2384
|
+
(0, message_flow_1.traceSessionBindingControlDrop)(this.dispatchErrors?.flow, ingress.sourceRoutingId, authority.actor.actorId, 'boundSessionReplaced', 'location_unavailable');
|
|
2385
|
+
return 'infrastructure';
|
|
2386
|
+
}
|
|
2387
|
+
if (!sessionOwnerFenceMatches(sessionOwner, record.retiredSession)) {
|
|
2388
|
+
(0, message_flow_1.traceSessionBindingControlDrop)(this.dispatchErrors?.flow, ingress.sourceRoutingId, authority.actor.actorId, 'boundSessionReplaced', 'stale_target');
|
|
2150
2389
|
return 'infrastructure';
|
|
2151
2390
|
}
|
|
2152
2391
|
const actor = authority.actor;
|
|
@@ -2172,6 +2411,9 @@ class ServiceStatefulRuntime {
|
|
|
2172
2411
|
if (delivery === undefined)
|
|
2173
2412
|
return 'infrastructure';
|
|
2174
2413
|
this.appliedReplacementNotices.add(key);
|
|
2414
|
+
if (delivery === current) {
|
|
2415
|
+
this.sessionDeliveries.delete(deliveryKey);
|
|
2416
|
+
}
|
|
2175
2417
|
delivery.onBindingReplaced?.(actor.actorId, record.retiredSession, actor);
|
|
2176
2418
|
if (retired !== undefined) {
|
|
2177
2419
|
this.retiredSessionDeliveries.delete(sessionDeliveryKey(retired.binding));
|
|
@@ -2179,14 +2421,18 @@ class ServiceStatefulRuntime {
|
|
|
2179
2421
|
return 'infrastructure';
|
|
2180
2422
|
}
|
|
2181
2423
|
sendBoundSessionReplacement(previous, actorAuthority) {
|
|
2182
|
-
|
|
2183
|
-
|
|
2424
|
+
// Command 51 carries the retired binding's stored identity unchanged; a
|
|
2425
|
+
// binding without one has nothing to notify.
|
|
2426
|
+
if (previous.sessionOwnerNodeGeneration === undefined ||
|
|
2427
|
+
previous.sessionOwnerId === undefined ||
|
|
2428
|
+
previous.sessionOwnerLeaseGeneration === undefined) {
|
|
2184
2429
|
return;
|
|
2430
|
+
}
|
|
2185
2431
|
const header = (0, service_stateful_wire_codec_1.encodeBoundSessionReplacedHeader)(actorAuthority, {
|
|
2186
2432
|
sessionOwnerNodeRid: previous.sessionOwnerNodeRid,
|
|
2187
|
-
sessionOwnerNodeGeneration:
|
|
2188
|
-
sessionOwnerId: previous.sessionOwnerId
|
|
2189
|
-
sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration
|
|
2433
|
+
sessionOwnerNodeGeneration: previous.sessionOwnerNodeGeneration,
|
|
2434
|
+
sessionOwnerId: previous.sessionOwnerId,
|
|
2435
|
+
sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration,
|
|
2190
2436
|
sessionRid: previous.sessionRid,
|
|
2191
2437
|
retiredBindingGeneration: previous.bindingGeneration
|
|
2192
2438
|
});
|
|
@@ -2204,11 +2450,9 @@ class ServiceStatefulRuntime {
|
|
|
2204
2450
|
if (current === undefined ||
|
|
2205
2451
|
sourceGeneration === undefined ||
|
|
2206
2452
|
current.bindingGeneration !== record.binding.retiredGeneration ||
|
|
2207
|
-
current.sessionRid
|
|
2453
|
+
!(0, routing_id_1.routingIdsEqual)(current.sessionRid, record.sessionRid) ||
|
|
2208
2454
|
current.sessionOwnerNodeRid !== ingress.sourceRoutingId ||
|
|
2209
|
-
current.sessionOwnerNodeGeneration !== sourceGeneration
|
|
2210
|
-
current.sessionOwnerId !== ingress.sourceRoutingId ||
|
|
2211
|
-
current.sessionOwnerLeaseGeneration !== sourceGeneration) {
|
|
2455
|
+
current.sessionOwnerNodeGeneration !== sourceGeneration) {
|
|
2212
2456
|
this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0);
|
|
2213
2457
|
return;
|
|
2214
2458
|
}
|
|
@@ -2340,6 +2584,31 @@ class ServiceStatefulRuntime {
|
|
|
2340
2584
|
errorReason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget
|
|
2341
2585
|
});
|
|
2342
2586
|
}
|
|
2587
|
+
prepareRequestSource(ingress, stateful, signal) {
|
|
2588
|
+
const reject = (error) => {
|
|
2589
|
+
if (signal.aborted)
|
|
2590
|
+
return false;
|
|
2591
|
+
if (!(error instanceof contracts_1.ZLinkFrameworkException))
|
|
2592
|
+
throw error;
|
|
2593
|
+
const result = failure(error);
|
|
2594
|
+
stateful.reply?.(result.terminalResult, result.failureCode);
|
|
2595
|
+
return false;
|
|
2596
|
+
};
|
|
2597
|
+
if (signal.aborted)
|
|
2598
|
+
return false;
|
|
2599
|
+
try {
|
|
2600
|
+
const pending = this.acceptRequestSource(ingress, signal);
|
|
2601
|
+
return pending === undefined
|
|
2602
|
+
? true
|
|
2603
|
+
: (0, abort_1.awaitWithAbort)(pending, signal).then(() => true, reject);
|
|
2604
|
+
}
|
|
2605
|
+
catch (error) {
|
|
2606
|
+
return reject(error);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
prepareDispatch(record, signal) {
|
|
2610
|
+
return this.prepareRequestSource(record.ingress, record.stateful, signal);
|
|
2611
|
+
}
|
|
2343
2612
|
enqueueApplicationFrame(ingress, owner, payloadFrame, stateful) {
|
|
2344
2613
|
return this.enqueueFrame('application', ingress, owner, payloadFrame, stateful);
|
|
2345
2614
|
}
|
|
@@ -2353,6 +2622,10 @@ class ServiceStatefulRuntime {
|
|
|
2353
2622
|
domain,
|
|
2354
2623
|
parts: [ingress.parts[0], payloadFrame],
|
|
2355
2624
|
sourceRoutingId: ingress.sourceRoutingId,
|
|
2625
|
+
ingress,
|
|
2626
|
+
get requestSource() {
|
|
2627
|
+
return ingress.requestSource;
|
|
2628
|
+
},
|
|
2356
2629
|
sourceRoute: ingress.sourceRoute,
|
|
2357
2630
|
...(ingress.reply === undefined ? {} : { reply: ingress.reply }),
|
|
2358
2631
|
...(ingress.requestSequence === undefined
|
|
@@ -2360,6 +2633,14 @@ class ServiceStatefulRuntime {
|
|
|
2360
2633
|
: { requestSequence: ingress.requestSequence }),
|
|
2361
2634
|
...(stateful.correlation === undefined ? {} : { correlation: stateful.correlation }),
|
|
2362
2635
|
stateful,
|
|
2636
|
+
sourcePreparationOwner: domain === 'application' &&
|
|
2637
|
+
this.requestSourceAcceptance !== undefined &&
|
|
2638
|
+
(stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.SpotSend ||
|
|
2639
|
+
stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.SpotRequest ||
|
|
2640
|
+
stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.ActorSend ||
|
|
2641
|
+
stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.ActorRequest)
|
|
2642
|
+
? this
|
|
2643
|
+
: undefined,
|
|
2363
2644
|
applicationJob
|
|
2364
2645
|
});
|
|
2365
2646
|
if (accepted) {
|
|
@@ -2465,9 +2746,9 @@ class ServiceStatefulRuntime {
|
|
|
2465
2746
|
}
|
|
2466
2747
|
});
|
|
2467
2748
|
}
|
|
2468
|
-
enqueueActorBindingControl(ingress, binding, actorAuthority, reply) {
|
|
2749
|
+
enqueueActorBindingControl(ingress, binding, actorAuthority, reply, acceptedBinding) {
|
|
2469
2750
|
const actor = binding.actor;
|
|
2470
|
-
|
|
2751
|
+
requireSessionOwnerIdentity(binding);
|
|
2471
2752
|
const header = Buffer.from([
|
|
2472
2753
|
service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[0],
|
|
2473
2754
|
service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[1],
|
|
@@ -2492,12 +2773,27 @@ class ServiceStatefulRuntime {
|
|
|
2492
2773
|
actorNodeGeneration: actorAuthority.targetNodeGeneration,
|
|
2493
2774
|
authorityOwnerGeneration: actorAuthority.authorityOwnerGeneration,
|
|
2494
2775
|
ownerLeaseGeneration: actorAuthority.ownerLeaseGeneration,
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2776
|
+
// The Host reads only Session identity fields before `reply` installs the
|
|
2777
|
+
// binding; installation keeps that identity. Generation and owner fields
|
|
2778
|
+
// are read after `reply`, so they always come from the accepted binding.
|
|
2779
|
+
get bindingGeneration() {
|
|
2780
|
+
return acceptedBinding().bindingGeneration;
|
|
2781
|
+
},
|
|
2782
|
+
get sessionNodeRid() {
|
|
2783
|
+
return acceptedBinding().sessionOwnerNodeRid;
|
|
2784
|
+
},
|
|
2785
|
+
get sessionRid() {
|
|
2786
|
+
return acceptedBinding().sessionRid;
|
|
2787
|
+
},
|
|
2788
|
+
get sessionOwnerNodeGeneration() {
|
|
2789
|
+
return acceptedBinding().sessionOwnerNodeGeneration;
|
|
2790
|
+
},
|
|
2791
|
+
get sessionOwnerId() {
|
|
2792
|
+
return acceptedBinding().sessionOwnerId;
|
|
2793
|
+
},
|
|
2794
|
+
get sessionOwnerLeaseGeneration() {
|
|
2795
|
+
return acceptedBinding().sessionOwnerLeaseGeneration;
|
|
2796
|
+
}
|
|
2501
2797
|
},
|
|
2502
2798
|
reply
|
|
2503
2799
|
},
|
|
@@ -2920,6 +3216,15 @@ class ServiceStatefulRuntime {
|
|
|
2920
3216
|
operationKind: service_runtime_contracts_1.OperationKind.ActorRequest,
|
|
2921
3217
|
correlation: decoded.correlation,
|
|
2922
3218
|
targetActor: current.ref,
|
|
3219
|
+
messageFollowOrigin: {
|
|
3220
|
+
get requestSource() {
|
|
3221
|
+
return ingress.requestSource;
|
|
3222
|
+
},
|
|
3223
|
+
target: decoded.target,
|
|
3224
|
+
sourceNodeRid: ingress.sourceRoutingId,
|
|
3225
|
+
originalOperation: decoded.operation,
|
|
3226
|
+
originalReplyRouteId: decoded.correlation ?? 0n
|
|
3227
|
+
},
|
|
2923
3228
|
...(decoded.sourceActor === undefined
|
|
2924
3229
|
? {}
|
|
2925
3230
|
: { sourceActor: { ...decoded.sourceActor, nodeRid: ingress.sourceRoutingId } }),
|
|
@@ -3007,7 +3312,8 @@ class ServiceStatefulRuntime {
|
|
|
3007
3312
|
try {
|
|
3008
3313
|
const current = this.validateActorFence(decoded.actor);
|
|
3009
3314
|
if (decoded.binding.state === 'active') {
|
|
3010
|
-
|
|
3315
|
+
const sessionOwner = await this.sessionOwnerOf(this.nodeRid, this.nodeGeneration);
|
|
3316
|
+
this.registry.installSessionBinding((0, service_stateful_wire_codec_1.sessionBindingFromWire)(current.ref, decoded.sessionRid, sessionOwner.nodeRid, decoded.binding.generation, current.membershipEpoch, sessionOwner.nodeGeneration, sessionOwner.ownerId, sessionOwner.leaseGeneration));
|
|
3011
3317
|
}
|
|
3012
3318
|
else {
|
|
3013
3319
|
this.registry.unbindSession(current.ref, decoded.binding.retiredGeneration, decoded.sessionRid, this.nodeRid);
|
|
@@ -3522,6 +3828,25 @@ function isEntrySpotFence(fence) {
|
|
|
3522
3828
|
fence.authorityOwnerGeneration === fence.targetNodeGeneration &&
|
|
3523
3829
|
fence.ownerLeaseGeneration === fence.targetNodeGeneration);
|
|
3524
3830
|
}
|
|
3831
|
+
function instanceActivationOutcome(error) {
|
|
3832
|
+
if ((0, abort_1.isAbortError)(error))
|
|
3833
|
+
return 'shutdown';
|
|
3834
|
+
if (error instanceof contracts_1.ZLinkFrameworkException) {
|
|
3835
|
+
switch (error.kind) {
|
|
3836
|
+
case contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded:
|
|
3837
|
+
return 'timed_out';
|
|
3838
|
+
case contracts_1.ZLinkFrameworkErrorKind.ShuttingDown:
|
|
3839
|
+
return 'shutdown';
|
|
3840
|
+
case contracts_1.ZLinkFrameworkErrorKind.AlreadyExists:
|
|
3841
|
+
return 'conflict';
|
|
3842
|
+
case contracts_1.ZLinkFrameworkErrorKind.InvalidOperation:
|
|
3843
|
+
return 'fenced';
|
|
3844
|
+
case contracts_1.ZLinkFrameworkErrorKind.Unavailable:
|
|
3845
|
+
return 'store_failure';
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
return 'rejected';
|
|
3849
|
+
}
|
|
3525
3850
|
function operationDeadline(deadlineUnixMs) {
|
|
3526
3851
|
const controller = new AbortController();
|
|
3527
3852
|
const delay = Number(deadlineUnixMs - BigInt(Date.now()));
|
|
@@ -3562,6 +3887,9 @@ function actorLocation(actor) {
|
|
|
3562
3887
|
membershipEpoch: actor.membershipEpoch
|
|
3563
3888
|
};
|
|
3564
3889
|
}
|
|
3890
|
+
function requestSourceUnavailable(nodeRid) {
|
|
3891
|
+
return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, `Request source '${nodeRid}' has no live MeshNode descriptor.`);
|
|
3892
|
+
}
|
|
3565
3893
|
function activationRefused() {
|
|
3566
3894
|
return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Instance cold activation authority was refused.');
|
|
3567
3895
|
}
|
|
@@ -3579,20 +3907,18 @@ function actorKey(actor) {
|
|
|
3579
3907
|
}
|
|
3580
3908
|
function sameSessionBinding(left, right) {
|
|
3581
3909
|
return (sameActorRef(left.actor, right.actor) &&
|
|
3582
|
-
left.sessionRid
|
|
3910
|
+
(0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
|
|
3583
3911
|
sameSessionOwnerIdentity(left, right) &&
|
|
3584
3912
|
left.bindingGeneration === right.bindingGeneration);
|
|
3585
3913
|
}
|
|
3586
3914
|
function sameSessionIdentity(left, right) {
|
|
3587
3915
|
return (sameActorRef(left.actor, right.actor) &&
|
|
3588
|
-
left.sessionRid
|
|
3916
|
+
(0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
|
|
3589
3917
|
sameSessionOwnerIdentity(left, right));
|
|
3590
3918
|
}
|
|
3591
3919
|
function sameSessionOwnerIdentity(left, right) {
|
|
3592
3920
|
return (left.sessionOwnerNodeRid === right.sessionOwnerNodeRid &&
|
|
3593
|
-
left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration
|
|
3594
|
-
left.sessionOwnerId === right.sessionOwnerId &&
|
|
3595
|
-
left.sessionOwnerLeaseGeneration === right.sessionOwnerLeaseGeneration);
|
|
3921
|
+
left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration);
|
|
3596
3922
|
}
|
|
3597
3923
|
function requireSessionOwnerIdentity(binding) {
|
|
3598
3924
|
if (binding.sessionOwnerNodeGeneration === undefined ||
|
|
@@ -3607,15 +3933,15 @@ function requireSessionOwnerIdentity(binding) {
|
|
|
3607
3933
|
};
|
|
3608
3934
|
}
|
|
3609
3935
|
function sessionDeliveryKey(binding) {
|
|
3610
|
-
return (`${actorKey(binding.actor)}\0${binding.sessionOwnerNodeRid}\0${binding.sessionRid}` +
|
|
3936
|
+
return (`${actorKey(binding.actor)}\0${binding.sessionOwnerNodeRid}\0${(0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionRid)}` +
|
|
3611
3937
|
`\0${binding.sessionOwnerNodeGeneration ?? ''}` +
|
|
3612
3938
|
`\0${binding.sessionOwnerId ?? ''}` +
|
|
3613
3939
|
`\0${binding.sessionOwnerLeaseGeneration ?? ''}` +
|
|
3614
3940
|
`\0${binding.bindingGeneration}`);
|
|
3615
3941
|
}
|
|
3616
3942
|
function exactRetiredDelivery(binding, retired) {
|
|
3617
|
-
return (binding.sessionRid
|
|
3618
|
-
binding.sessionOwnerNodeRid
|
|
3943
|
+
return ((0, routing_id_1.routingIdsEqual)(binding.sessionRid, retired.sessionRid) &&
|
|
3944
|
+
(0, routing_id_1.routingIdsEqual)(binding.sessionOwnerNodeRid, retired.sessionOwnerNodeRid) &&
|
|
3619
3945
|
binding.sessionOwnerNodeGeneration === retired.sessionOwnerNodeGeneration &&
|
|
3620
3946
|
binding.sessionOwnerId === retired.sessionOwnerId &&
|
|
3621
3947
|
binding.sessionOwnerLeaseGeneration === retired.sessionOwnerLeaseGeneration &&
|
|
@@ -3629,7 +3955,7 @@ function replacementNoticeKey(record) {
|
|
|
3629
3955
|
`\0${record.retiredSession.sessionOwnerNodeGeneration}` +
|
|
3630
3956
|
`\0${record.retiredSession.sessionOwnerId}` +
|
|
3631
3957
|
`\0${record.retiredSession.sessionOwnerLeaseGeneration}` +
|
|
3632
|
-
`\0${record.retiredSession.sessionRid}` +
|
|
3958
|
+
`\0${(0, routing_id_1.encodeRoutingIdStorageHex)(record.retiredSession.sessionRid)}` +
|
|
3633
3959
|
`\0${record.retiredSession.retiredBindingGeneration}`);
|
|
3634
3960
|
}
|
|
3635
3961
|
function actorAuthorityFromRoute(route) {
|
|
@@ -3880,7 +4206,8 @@ function acceptsStatefulIngress(command) {
|
|
|
3880
4206
|
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotClose &&
|
|
3881
4207
|
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.actorCreate &&
|
|
3882
4208
|
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.messageFollow &&
|
|
3883
|
-
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced
|
|
4209
|
+
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced &&
|
|
4210
|
+
command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionClose)) {
|
|
3884
4211
|
return false;
|
|
3885
4212
|
}
|
|
3886
4213
|
return true;
|