@zlink-systems/framework 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Common/ZLinkMessage.js +5 -5
- package/dist/contracts/Configuration/CodecContentType.js +5 -7
- package/dist/contracts/Configuration/DiagnosticsValidation.js +1 -6
- package/dist/contracts/Configuration/EndpointNotation.js +4 -8
- package/dist/contracts/Configuration/Registration.js +14 -11
- package/dist/contracts/Configuration/RegistrationBuilders.js +32 -25
- package/dist/contracts/Configuration/RegistrationNormalizers.js +25 -26
- package/dist/contracts/Configuration/RegistrationValidators.js +36 -38
- package/dist/contracts/Configuration/SendTimeoutValidation.js +4 -4
- package/dist/contracts/Configuration/TimerRegistrationValidator.js +7 -7
- package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +1 -0
- package/dist/contracts/Handlers/JsonContract.js +23 -11
- package/dist/contracts/Spots/SpotKind.js +16 -8
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -1
- package/dist/location-store-integration.js +16 -16
- package/dist/nest-integration.js +17 -11
- package/dist/runtime/abort.js +9 -5
- package/dist/runtime/actors/actor-authority-payload-codec.js +12 -16
- package/dist/runtime/actors/actor-authority-publication.js +18 -17
- package/dist/runtime/actors/actor-client.js +83 -63
- package/dist/runtime/actors/actor-context.js +28 -22
- package/dist/runtime/actors/actor-creation.js +4 -3
- package/dist/runtime/actors/actor-handoff.js +89 -92
- package/dist/runtime/actors/actor-join-deferred-scope.d.ts +0 -1
- package/dist/runtime/actors/actor-join-deferred-scope.js +0 -18
- package/dist/runtime/actors/actor-local-native-join.js +18 -19
- package/dist/runtime/actors/actor-mailbox.js +1 -1
- package/dist/runtime/actors/actor-message-follow-context.js +24 -21
- package/dist/runtime/actors/actor-packet-relay-wire.js +1 -3
- package/dist/runtime/actors/actor-remote-joiner.js +20 -17
- package/dist/runtime/actors/actor-remote-wire.js +6 -7
- package/dist/runtime/actors/actor-runtime-state.js +87 -81
- package/dist/runtime/actors/actor-transfer-registry.js +3 -5
- package/dist/runtime/actors/bound-session-wire.js +14 -9
- package/dist/runtime/actors/deferred-join-accepted-journal.js +160 -130
- package/dist/runtime/actors/index.js +2 -5
- package/dist/runtime/actors/post-commit-actor-binder.js +3 -6
- package/dist/runtime/actors/post-commit-actor-location.js +1 -1
- package/dist/runtime/actors/spot-actor-dispatch.js +5 -5
- package/dist/runtime/actors/transferred-actor-rollback.js +4 -4
- package/dist/runtime/admission.js +2 -6
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +2 -6
- package/dist/runtime/application-jobs/receive-flow-controller.js +11 -12
- package/dist/runtime/backend/contracts/index.d.ts +1 -0
- package/dist/runtime/backend/mesh-completion-table.js +1 -3
- package/dist/runtime/backend/mesh-dispatch-pump.js +12 -16
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +1 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +26 -17
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +4 -3
- package/dist/runtime/backend/node/node-raw-binding-port.js +7 -6
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +3 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +134 -118
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +12 -13
- package/dist/runtime/backend/runtime-message.js +3 -3
- package/dist/runtime/backend/runtime-values.d.ts +2 -2
- package/dist/runtime/backend/runtime-values.js +4 -5
- package/dist/runtime/channels/channel-clients.js +27 -24
- package/dist/runtime/channels/channel-dispatch-pipeline.js +12 -20
- package/dist/runtime/channels/channel-dispatch-services.js +7 -4
- package/dist/runtime/channels/channel-dispatchers.js +9 -9
- package/dist/runtime/channels/channel-envelope-inspection.js +16 -13
- package/dist/runtime/channels/channel-envelope.js +83 -47
- package/dist/runtime/channels/channel-outbound-operations.js +8 -8
- package/dist/runtime/channels/channel-receive-loops.js +20 -22
- package/dist/runtime/channels/channel-receive-task-tracker.js +1 -1
- package/dist/runtime/channels/channel-runtime-lifecycle.js +61 -56
- package/dist/runtime/channels/channel-runtime-manager.js +18 -9
- package/dist/runtime/channels/channel-socket-registry.js +126 -123
- package/dist/runtime/channels/channel-transports.js +46 -42
- package/dist/runtime/channels/client-server-location-runtime.js +32 -40
- package/dist/runtime/channels/client-server-service-wire.js +29 -22
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +1 -0
- package/dist/runtime/channels/dispatch-error-reporter.js +9 -39
- package/dist/runtime/channels/fanout-location-runtime.js +34 -47
- package/dist/runtime/channels/fanout-service-wire.js +3 -5
- package/dist/runtime/channels/local-spot-route-transport.js +7 -1
- package/dist/runtime/channels/route-member-snapshot.js +3 -3
- package/dist/runtime/channels/source-spot-router.js +6 -2
- package/dist/runtime/channels/spot-route-bridge-transport.js +5 -2
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +2 -2
- package/dist/runtime/channels/spot-route-target-resolver.js +6 -6
- package/dist/runtime/diagnostics/dispatch-error-details.d.ts +6 -0
- package/dist/runtime/diagnostics/dispatch-error-details.js +55 -0
- package/dist/runtime/diagnostics/flow-context.d.ts +2 -1
- package/dist/runtime/diagnostics/flow-context.js +2 -2
- package/dist/runtime/diagnostics/index.js +38 -10
- package/dist/runtime/diagnostics/message-flow.js +58 -42
- package/dist/runtime/diagnostics/runtime-metrics.js +18 -9
- package/dist/runtime/diagnostics/runtime-observation-queue.js +8 -10
- package/dist/runtime/diagnostics/topology-runtime-projections.js +17 -10
- package/dist/runtime/execution/index.js +7 -6
- package/dist/runtime/execution/serial-execution-queue.js +12 -18
- package/dist/runtime/execution/state-lane.js +2 -2
- package/dist/runtime/foundation/actor-join-recovery-codec.js +31 -27
- package/dist/runtime/foundation/event-loop-resources.js +4 -4
- package/dist/runtime/foundation/message-follow-suppression-registry.js +4 -4
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +4 -2
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +169 -144
- package/dist/runtime/foundation/route-mesh-connection-policy.js +4 -4
- package/dist/runtime/foundation/runtime-state-projections.js +22 -11
- package/dist/runtime/foundation/service-authority-payload-codec.js +13 -15
- package/dist/runtime/foundation/service-discovery-registry.js +35 -33
- package/dist/runtime/foundation/service-instance-activation-recovery-codec.js +20 -22
- package/dist/runtime/foundation/service-liveness-registry.js +16 -12
- package/dist/runtime/foundation/service-maintenance-runtime.js +2 -4
- package/dist/runtime/foundation/service-relocation-aggregate-committer.js +24 -24
- package/dist/runtime/foundation/service-relocation-object-owner.js +6 -6
- package/dist/runtime/foundation/service-relocation-runtime.js +137 -94
- package/dist/runtime/foundation/service-runtime-contracts.js +5 -5
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +1 -0
- package/dist/runtime/foundation/service-stateful-registry.js +24 -23
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -0
- package/dist/runtime/foundation/service-stateful-runtime.js +461 -439
- package/dist/runtime/foundation/service-stateful-wire-codec.js +95 -98
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -0
- package/dist/runtime/foundation/service-topology-registry.js +105 -96
- package/dist/runtime/foundation/service-weighted-selection.js +6 -11
- package/dist/runtime/foundation/service-wire-binary-primitives.js +5 -6
- package/dist/runtime/foundation/service-wire-m6a-codec.js +46 -35
- package/dist/runtime/framework-errors-internal.js +7 -10
- package/dist/runtime/handlers/handler-instance-scope.js +4 -5
- package/dist/runtime/handlers/index.js +3 -1
- package/dist/runtime/host/actor-packet-relay.js +74 -70
- package/dist/runtime/host/actor-placement-coordinator.js +29 -31
- package/dist/runtime/host/actor-runtime-options-factory.js +12 -14
- package/dist/runtime/host/actor-transfer-authority-runtime.js +7 -9
- package/dist/runtime/host/actor-transfer-runtime.js +176 -153
- package/dist/runtime/host/application-job-queue.js +18 -22
- package/dist/runtime/host/bound-session-relay.js +3 -1
- package/dist/runtime/host/channel-runtime-options-factory.js +31 -14
- package/dist/runtime/host/host-capacity-status.js +8 -4
- package/dist/runtime/host/index.js +245 -228
- package/dist/runtime/host/instance-activation-authority.js +93 -96
- package/dist/runtime/host/location-runtime-owner.js +16 -14
- package/dist/runtime/host/mesh-router-resolver.js +11 -13
- package/dist/runtime/host/relocation-direct-transfer.js +10 -9
- package/dist/runtime/host/remote-actor-join-receiver.js +20 -15
- package/dist/runtime/host/remote-actor-packet-target-store.js +18 -22
- package/dist/runtime/host/remote-bound-session-relay.js +97 -73
- package/dist/runtime/host/route-mesh-runtime.js +64 -69
- package/dist/runtime/host/runtime-shutdown.js +1 -2
- package/dist/runtime/host/service-relocation-host-runtime.js +586 -511
- package/dist/runtime/host/spot-address-transport.js +69 -71
- package/dist/runtime/host/spot-runtime-options-factory.js +30 -29
- package/dist/runtime/host/stateful-authority-route-runtime.js +65 -68
- package/dist/runtime/host/user-spot-creation-coordinator.js +61 -67
- package/dist/runtime/locations/actor-location-claims.js +26 -20
- package/dist/runtime/locations/aggregate-inventory-store.js +72 -75
- package/dist/runtime/locations/authority-key-codec.js +7 -7
- package/dist/runtime/locations/auto-connect-loop.js +3 -3
- package/dist/runtime/locations/auto-connect-planner.js +25 -19
- package/dist/runtime/locations/auto-connect-reconciler.js +51 -31
- package/dist/runtime/locations/in-memory-authority-store.js +128 -118
- package/dist/runtime/locations/in-memory-location-store.js +195 -168
- package/dist/runtime/locations/in-memory-provider-location-store.js +8 -10
- package/dist/runtime/locations/key-codec.js +1 -1
- package/dist/runtime/locations/lease-tracker.js +23 -21
- package/dist/runtime/locations/lifecycle.js +4 -5
- package/dist/runtime/locations/location-store-repository.js +368 -324
- package/dist/runtime/locations/opaque-record-key.js +2 -2
- package/dist/runtime/locations/resolvers.js +73 -82
- package/dist/runtime/locations/runtime.js +68 -63
- package/dist/runtime/locations/spot-location-claims.js +39 -35
- package/dist/runtime/messaging/framework-json-v1.js +7 -7
- package/dist/runtime/messaging/packet-name.js +7 -6
- package/dist/runtime/messaging/payload-codec.js +21 -18
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +30 -2
- package/dist/runtime/protocol/service_wire_codec.generated.js +1671 -234
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +20 -18
- package/dist/runtime/routing-id.js +3 -5
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +35 -31
- package/dist/runtime/spots/formal-remote-actor-transfer-registry.js +1 -2
- package/dist/runtime/spots/index.js +209 -220
- package/dist/runtime/spots/spot-activation-registry.js +15 -14
- package/dist/runtime/spots/spot-activation-state.js +17 -15
- package/dist/runtime/spots/spot-activation.js +33 -16
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +18 -15
- package/dist/runtime/spots/spot-actor-membership.js +1 -3
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +29 -21
- package/dist/runtime/spots/spot-actor-packet-drain.js +14 -10
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +10 -6
- package/dist/runtime/spots/spot-closing.js +3 -7
- package/dist/runtime/spots/spot-context.js +2 -2
- package/dist/runtime/spots/spot-entry-activation.js +13 -14
- package/dist/runtime/spots/spot-handle.js +6 -3
- package/dist/runtime/spots/spot-handler-registry.js +12 -12
- package/dist/runtime/spots/spot-manager-public.js +5 -6
- package/dist/runtime/spots/spot-native-actor-join-admission.js +4 -3
- package/dist/runtime/spots/spot-node-autoconnect.js +15 -18
- package/dist/runtime/spots/spot-node-runtime-manager.js +79 -86
- package/dist/runtime/spots/spot-outbound.js +10 -14
- package/dist/runtime/spots/spot-remote-codec.js +22 -26
- package/dist/runtime/spots/spot-remote-route-codec.js +5 -7
- package/dist/runtime/spots/spot-route-packet-dispatch.js +17 -15
- package/dist/runtime/spots/spot-route-replies.js +4 -6
- package/dist/runtime/spots/spot-routed-actor-admission.js +9 -7
- package/dist/runtime/spots/spot-routed-bound-session-dispatch.js +2 -3
- package/dist/runtime/spots/spot-routed-frame-dispatch.js +5 -5
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +14 -10
- package/dist/runtime/spots/spot-serial-executor.js +5 -8
- package/dist/runtime/spots/spot-serial-turn-executor.js +4 -6
- package/dist/runtime/spots/spot-subscription-dispatch.js +6 -6
- package/dist/runtime/spots/spot-timer.js +26 -30
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +21 -8
- package/dist/runtime/streams/actor-session-binding-registry.js +168 -148
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +1 -0
- package/dist/runtime/streams/actor-session-lifecycle-coordinator.js +3 -1
- package/dist/runtime/streams/bound-actor-relay-sender.js +20 -17
- package/dist/runtime/streams/bound-session-response-target.js +8 -1
- package/dist/runtime/streams/bound-session-service.d.ts +1 -0
- package/dist/runtime/streams/bound-session-service.js +14 -12
- package/dist/runtime/streams/index.js +28 -20
- package/dist/runtime/streams/managed-stream.d.ts +3 -0
- package/dist/runtime/streams/managed-stream.js +52 -31
- package/dist/runtime/streams/native-fallback-bound-session.js +21 -17
- package/dist/runtime/streams/protocol.d.ts +5 -1
- package/dist/runtime/streams/protocol.js +68 -20
- package/dist/runtime/streams/session-actor-coordinator.js +37 -41
- package/dist/runtime/streams/session-context.d.ts +9 -2
- package/dist/runtime/streams/session-context.js +50 -32
- package/dist/runtime/streams/session-local-actors.d.ts +3 -1
- package/dist/runtime/streams/session-local-actors.js +17 -2
- package/dist/runtime/streams/session-provider.js +2 -2
- package/dist/runtime/streams/session-serial-executor.js +1 -2
- package/dist/runtime/streams/stream-frame-factory.d.ts +1 -1
- package/dist/runtime/streams/stream-frame-factory.js +14 -7
- package/dist/runtime/streams/stream-session-runtime.js +112 -78
- package/dist/runtime/workers/index.js +15 -4
- package/package.json +3 -3
- package/src/contracts/Channels/RouteCalls.ts +6 -1
- package/src/contracts/Common/ZLinkMessage.ts +5 -5
- package/src/contracts/Common/ZLinkMessageMetadata.ts +4 -3
- package/src/contracts/Configuration/Builders.ts +14 -14
- package/src/contracts/Configuration/CodecContentType.ts +8 -10
- package/src/contracts/Configuration/DiagnosticsValidation.ts +1 -6
- package/src/contracts/Configuration/EndpointNotation.ts +11 -11
- package/src/contracts/Configuration/ObjectRoles.ts +1 -3
- package/src/contracts/Configuration/Registration.ts +46 -17
- package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +10 -8
- package/src/contracts/Configuration/RegistrationBuilders.ts +107 -96
- package/src/contracts/Configuration/RegistrationCodecRegistry.ts +9 -3
- package/src/contracts/Configuration/RegistrationNormalizers.ts +116 -84
- package/src/contracts/Configuration/RegistrationTypes.ts +21 -25
- package/src/contracts/Configuration/RegistrationValidators.ts +122 -73
- package/src/contracts/Configuration/RouteChannelInternalState.ts +1 -4
- package/src/contracts/Configuration/RuntimeEndpointConnections.ts +4 -1
- package/src/contracts/Configuration/SendTimeoutValidation.ts +6 -4
- package/src/contracts/Configuration/TimerRegistrationValidator.ts +8 -13
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -6
- package/src/contracts/Errors/index.ts +1 -4
- package/src/contracts/Handlers/Attributes.ts +15 -9
- package/src/contracts/Handlers/IZLinkChannelHandlers.ts +24 -4
- package/src/contracts/Handlers/JsonContract.ts +53 -19
- package/src/contracts/Locations/ActorTransfer.ts +1 -5
- package/src/contracts/Locations/Authority.ts +4 -11
- package/src/contracts/Locations/Keys.ts +6 -1
- package/src/contracts/Locations/Options.ts +3 -2
- package/src/contracts/Locations/RelocationStore.ts +1 -4
- package/src/contracts/Locations/Resolvers.ts +5 -5
- package/src/contracts/Locations/RuntimeQuery.ts +6 -2
- package/src/contracts/Locations/Stores.ts +1 -2
- package/src/contracts/Locations/index.ts +2 -8
- package/src/contracts/RouteMesh/Contracts.ts +1 -7
- package/src/contracts/RouteMesh/RuntimeTopology.ts +1 -4
- package/src/contracts/Spots/Contracts.ts +2 -8
- package/src/contracts/Spots/SpotKind.ts +16 -8
- package/src/contracts/Spots/ZLinkSpot.ts +8 -11
- package/src/contracts/Streams/IZLinkSession.ts +2 -2
- package/src/contracts/Streams/IZLinkSessionActor.ts +5 -1
- package/src/contracts/Streams/IZLinkSessionPacketHandler.ts +5 -1
- package/src/internal.ts +5 -4
- package/src/location-store-integration.ts +24 -16
- package/src/nest-integration.ts +40 -25
- package/src/runtime/abort.ts +10 -4
- package/src/runtime/actors/actor-authority-payload-codec.ts +20 -29
- package/src/runtime/actors/actor-authority-publication.ts +92 -77
- package/src/runtime/actors/actor-client.ts +162 -133
- package/src/runtime/actors/actor-context.ts +142 -134
- package/src/runtime/actors/actor-creation.ts +47 -44
- package/src/runtime/actors/actor-execution-context.ts +6 -4
- package/src/runtime/actors/actor-handoff.ts +269 -293
- package/src/runtime/actors/actor-join-deferred-scope.ts +1 -32
- package/src/runtime/actors/actor-lifecycle-snapshot.ts +5 -8
- package/src/runtime/actors/actor-local-native-join.ts +131 -159
- package/src/runtime/actors/actor-mailbox.ts +16 -19
- package/src/runtime/actors/actor-message-follow-context.ts +46 -36
- package/src/runtime/actors/actor-packet-relay-wire.ts +32 -21
- package/src/runtime/actors/actor-remote-joiner.ts +50 -54
- package/src/runtime/actors/actor-remote-wire.ts +9 -13
- package/src/runtime/actors/actor-routed-join-transport.ts +10 -2
- package/src/runtime/actors/actor-runtime-contracts.ts +2 -5
- package/src/runtime/actors/actor-runtime-state.ts +127 -124
- package/src/runtime/actors/actor-transfer-registry.ts +9 -14
- package/src/runtime/actors/actor-transport-delivery-gate.ts +4 -6
- package/src/runtime/actors/bound-session-wire.ts +37 -17
- package/src/runtime/actors/deferred-join-accepted-journal.ts +353 -326
- package/src/runtime/actors/index.ts +43 -86
- package/src/runtime/actors/post-commit-actor-binder.ts +10 -10
- package/src/runtime/actors/post-commit-actor-location.ts +30 -23
- package/src/runtime/actors/spot-actor-dispatch.ts +78 -53
- package/src/runtime/actors/transferred-actor-rollback.ts +18 -13
- package/src/runtime/admission.ts +9 -9
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +5 -15
- package/src/runtime/application-jobs/application-job-queue-handler-start-gate.ts +3 -2
- package/src/runtime/application-jobs/receive-flow-controller.ts +17 -14
- package/src/runtime/backend/contracts/index.ts +77 -52
- package/src/runtime/backend/mesh-actor-session-node-adapter.ts +4 -14
- package/src/runtime/backend/mesh-completion-table.ts +6 -9
- package/src/runtime/backend/mesh-dispatch-pump.ts +38 -30
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +23 -21
- package/src/runtime/backend/node/node-backend-adapter-support.ts +36 -22
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +59 -58
- package/src/runtime/backend/node/node-event-loop-poller.ts +2 -10
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +12 -5
- package/src/runtime/backend/node/node-monitor-backend-adapter.ts +4 -3
- package/src/runtime/backend/node/node-raw-binding-port.ts +29 -29
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +370 -390
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +101 -54
- package/src/runtime/backend/runtime-message.ts +5 -3
- package/src/runtime/backend/runtime-values.ts +10 -7
- package/src/runtime/channels/channel-autoconnect.ts +1 -4
- package/src/runtime/channels/channel-clients.ts +93 -73
- package/src/runtime/channels/channel-dispatch-pipeline.ts +44 -44
- package/src/runtime/channels/channel-dispatch-services.ts +51 -49
- package/src/runtime/channels/channel-dispatchers.ts +152 -96
- package/src/runtime/channels/channel-envelope-inspection.ts +20 -16
- package/src/runtime/channels/channel-envelope.ts +256 -150
- package/src/runtime/channels/channel-multipart.ts +13 -5
- package/src/runtime/channels/channel-outbound-operations.ts +37 -41
- package/src/runtime/channels/channel-receive-loops.ts +102 -98
- package/src/runtime/channels/channel-receive-task-tracker.ts +1 -1
- package/src/runtime/channels/channel-runtime-lifecycle.ts +248 -190
- package/src/runtime/channels/channel-runtime-manager.ts +63 -37
- package/src/runtime/channels/channel-socket-options.ts +3 -10
- package/src/runtime/channels/channel-socket-registry.ts +331 -273
- package/src/runtime/channels/channel-transports.ts +218 -206
- package/src/runtime/channels/client-server-location-runtime.ts +116 -100
- package/src/runtime/channels/client-server-service-wire.ts +37 -36
- package/src/runtime/channels/dispatch-error-reporter.ts +12 -47
- package/src/runtime/channels/fanout-location-runtime.ts +91 -94
- package/src/runtime/channels/fanout-service-wire.ts +5 -12
- package/src/runtime/channels/handler-filter-scope.ts +1 -4
- package/src/runtime/channels/index.ts +1 -4
- package/src/runtime/channels/local-spot-route-transport.ts +20 -5
- package/src/runtime/channels/route-member-snapshot.ts +11 -5
- package/src/runtime/channels/router-socket-spot-route-transport.ts +1 -7
- package/src/runtime/channels/source-spot-router.ts +26 -22
- package/src/runtime/channels/spot-direct-envelope.ts +10 -8
- package/src/runtime/channels/spot-node-route-transport.ts +13 -16
- package/src/runtime/channels/spot-route-bridge-transport.ts +26 -9
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +40 -13
- package/src/runtime/channels/spot-route-target-resolver.ts +18 -9
- package/src/runtime/codecs/index.ts +3 -2
- package/src/runtime/diagnostics/dispatch-error-details.ts +62 -0
- package/src/runtime/diagnostics/flow-context.ts +18 -7
- package/src/runtime/diagnostics/index.ts +96 -61
- package/src/runtime/diagnostics/internal-event-contracts.ts +87 -33
- package/src/runtime/diagnostics/message-flow.ts +107 -79
- package/src/runtime/diagnostics/runtime-metrics.ts +46 -24
- package/src/runtime/diagnostics/runtime-observation-queue.ts +17 -28
- package/src/runtime/diagnostics/topology-runtime-projections.ts +62 -43
- package/src/runtime/execution/index.ts +18 -26
- package/src/runtime/execution/serial-execution-queue.ts +31 -40
- package/src/runtime/execution/state-lane.ts +2 -2
- package/src/runtime/foundation/actor-join-recovery-codec.ts +69 -55
- package/src/runtime/foundation/event-loop-resources.ts +8 -4
- package/src/runtime/foundation/message-follow-suppression-registry.ts +7 -14
- package/src/runtime/foundation/operation-identity.ts +1 -2
- package/src/runtime/foundation/operation-registry.ts +8 -2
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +364 -396
- package/src/runtime/foundation/route-mesh-connection-policy.ts +7 -8
- package/src/runtime/foundation/runtime-state-projections.ts +24 -23
- package/src/runtime/foundation/service-authority-payload-codec.ts +54 -57
- package/src/runtime/foundation/service-discovery-registry.ts +67 -59
- package/src/runtime/foundation/service-instance-activation-recovery-codec.ts +28 -29
- package/src/runtime/foundation/service-liveness-registry.ts +18 -13
- package/src/runtime/foundation/service-mailbox.ts +14 -14
- package/src/runtime/foundation/service-maintenance-runtime.ts +22 -21
- package/src/runtime/foundation/service-metadata-codec.ts +2 -9
- package/src/runtime/foundation/service-relocation-aggregate-committer.ts +39 -36
- package/src/runtime/foundation/service-relocation-coordinator.ts +1 -4
- package/src/runtime/foundation/service-relocation-object-owner.ts +40 -58
- package/src/runtime/foundation/service-relocation-runtime.ts +292 -216
- package/src/runtime/foundation/service-runtime-contracts.ts +8 -8
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -4
- package/src/runtime/foundation/service-stateful-registry.ts +69 -59
- package/src/runtime/foundation/service-stateful-runtime.ts +1233 -1112
- package/src/runtime/foundation/service-stateful-wire-codec.ts +318 -270
- package/src/runtime/foundation/service-topology-registry.ts +170 -159
- package/src/runtime/foundation/service-weighted-selection.ts +9 -15
- package/src/runtime/foundation/service-wire-binary-primitives.ts +6 -12
- package/src/runtime/foundation/service-wire-m6a-codec.ts +69 -47
- package/src/runtime/framework-errors-internal.ts +31 -30
- package/src/runtime/handlers/handler-instance-scope.ts +18 -29
- package/src/runtime/handlers/index.ts +18 -8
- package/src/runtime/host/actor-packet-relay.ts +290 -261
- package/src/runtime/host/actor-placement-coordinator.ts +165 -150
- package/src/runtime/host/actor-runtime-options-factory.ts +89 -87
- package/src/runtime/host/actor-transfer-authority-runtime.ts +46 -38
- package/src/runtime/host/actor-transfer-runtime.ts +391 -395
- package/src/runtime/host/application-job-queue.ts +32 -48
- package/src/runtime/host/bound-session-relay.ts +7 -9
- package/src/runtime/host/channel-runtime-options-factory.ts +75 -35
- package/src/runtime/host/host-capacity-status.ts +10 -9
- package/src/runtime/host/index.ts +861 -789
- package/src/runtime/host/instance-activation-authority.ts +125 -143
- package/src/runtime/host/location-runtime-owner.ts +38 -26
- package/src/runtime/host/mesh-router-resolver.ts +30 -23
- package/src/runtime/host/relocation-direct-transfer.ts +15 -15
- package/src/runtime/host/relocation-integrity-fault-gate.ts +3 -2
- package/src/runtime/host/remote-actor-join-receiver.ts +43 -34
- package/src/runtime/host/remote-actor-packet-target-store.ts +54 -52
- package/src/runtime/host/remote-bound-session-relay.ts +274 -247
- package/src/runtime/host/route-mesh-runtime-options.ts +1 -3
- package/src/runtime/host/route-mesh-runtime.ts +227 -181
- package/src/runtime/host/runtime-shutdown.ts +4 -3
- package/src/runtime/host/service-relocation-control.ts +14 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +1388 -1165
- package/src/runtime/host/spot-address-transport.ts +284 -237
- package/src/runtime/host/spot-node-runtime-options-factory.ts +14 -8
- package/src/runtime/host/spot-runtime-options-factory.ts +71 -62
- package/src/runtime/host/stateful-authority-route-runtime.ts +117 -116
- package/src/runtime/host/user-spot-creation-coordinator.ts +225 -220
- package/src/runtime/locations/actor-location-claims.ts +61 -49
- package/src/runtime/locations/actor-session-route-claims.ts +1 -4
- package/src/runtime/locations/aggregate-inventory-store.ts +105 -134
- package/src/runtime/locations/authority-key-codec.ts +13 -10
- package/src/runtime/locations/auto-connect-loop.ts +14 -11
- package/src/runtime/locations/auto-connect-planner.ts +42 -31
- package/src/runtime/locations/auto-connect-reconciler.ts +106 -63
- package/src/runtime/locations/canonical-codec.ts +3 -1
- package/src/runtime/locations/creation-operation-id.ts +4 -3
- package/src/runtime/locations/domain-store-contract.ts +13 -7
- package/src/runtime/locations/in-memory-authority-store.ts +232 -199
- package/src/runtime/locations/in-memory-location-store.ts +432 -250
- package/src/runtime/locations/in-memory-provider-location-store.ts +16 -17
- package/src/runtime/locations/internal-store-contracts.ts +95 -38
- package/src/runtime/locations/key-codec.ts +3 -4
- package/src/runtime/locations/lease-tracker.ts +36 -27
- package/src/runtime/locations/lifecycle-runtime.ts +15 -3
- package/src/runtime/locations/lifecycle.ts +33 -28
- package/src/runtime/locations/location-store-repository.ts +1329 -1185
- package/src/runtime/locations/opaque-record-key.ts +4 -9
- package/src/runtime/locations/resolvers.ts +201 -178
- package/src/runtime/locations/runtime.ts +251 -159
- package/src/runtime/locations/spot-location-claims.ts +110 -112
- package/src/runtime/messaging/creation-payload-codec.ts +4 -1
- package/src/runtime/messaging/framework-json-v1.ts +34 -15
- package/src/runtime/messaging/packet-name.ts +8 -6
- package/src/runtime/messaging/payload-codec.ts +70 -50
- package/src/runtime/messaging/submission-result.ts +6 -9
- package/src/runtime/protocol/service_wire_codec.generated.ts +1376 -159
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +19 -18
- package/src/runtime/routing-id.ts +10 -7
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +56 -62
- package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +23 -20
- package/src/runtime/spots/index.ts +595 -564
- package/src/runtime/spots/spot-activation-registry.ts +38 -34
- package/src/runtime/spots/spot-activation-state.ts +43 -51
- package/src/runtime/spots/spot-activation.ts +179 -116
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +110 -78
- package/src/runtime/spots/spot-actor-join-dispatch.ts +57 -41
- package/src/runtime/spots/spot-actor-lifecycle-drain.ts +5 -7
- package/src/runtime/spots/spot-actor-membership.ts +25 -27
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +196 -148
- package/src/runtime/spots/spot-actor-packet-drain.ts +56 -42
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +37 -39
- package/src/runtime/spots/spot-closing.ts +11 -12
- package/src/runtime/spots/spot-context.ts +46 -26
- package/src/runtime/spots/spot-entry-activation.ts +84 -65
- package/src/runtime/spots/spot-handle.ts +17 -15
- package/src/runtime/spots/spot-handler-registry.ts +44 -31
- package/src/runtime/spots/spot-location-claim.ts +5 -4
- package/src/runtime/spots/spot-manager-public.ts +62 -82
- package/src/runtime/spots/spot-native-actor-join-admission.ts +20 -16
- package/src/runtime/spots/spot-node-autoconnect.ts +54 -61
- package/src/runtime/spots/spot-node-runtime-manager.ts +235 -222
- package/src/runtime/spots/spot-outbound.ts +47 -59
- package/src/runtime/spots/spot-publisher-transport.ts +5 -4
- package/src/runtime/spots/spot-remote-codec.ts +66 -65
- package/src/runtime/spots/spot-remote-route-codec.ts +61 -41
- package/src/runtime/spots/spot-route-packet-dispatch.ts +129 -95
- package/src/runtime/spots/spot-route-replies.ts +23 -24
- package/src/runtime/spots/spot-route-reply-wire.ts +3 -2
- package/src/runtime/spots/spot-routed-actor-admission.ts +37 -27
- package/src/runtime/spots/spot-routed-bound-session-dispatch.ts +13 -18
- package/src/runtime/spots/spot-routed-frame-dispatch.ts +18 -15
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +35 -26
- package/src/runtime/spots/spot-routing-internal.ts +1 -4
- package/src/runtime/spots/spot-runtime-ports.ts +5 -5
- package/src/runtime/spots/spot-serial-executor.ts +5 -9
- package/src/runtime/spots/spot-serial-turn-executor.ts +19 -26
- package/src/runtime/spots/spot-subscription-dispatch.ts +58 -47
- package/src/runtime/spots/spot-timer.ts +103 -91
- package/src/runtime/streams/actor-session-binding-registry.ts +421 -292
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +8 -4
- package/src/runtime/streams/actor-session-lifecycle-coordinator.ts +3 -1
- package/src/runtime/streams/bound-actor-relay-sender.ts +60 -50
- package/src/runtime/streams/bound-session-response-target.ts +39 -9
- package/src/runtime/streams/bound-session-service.ts +52 -42
- package/src/runtime/streams/index.ts +183 -100
- package/src/runtime/streams/managed-stream.ts +123 -90
- package/src/runtime/streams/native-fallback-bound-session.ts +57 -52
- package/src/runtime/streams/protocol.ts +115 -46
- package/src/runtime/streams/session-actor-coordinator.ts +109 -93
- package/src/runtime/streams/session-calls.ts +2 -8
- package/src/runtime/streams/session-context.ts +96 -51
- package/src/runtime/streams/session-local-actors.ts +19 -3
- package/src/runtime/streams/session-provider.ts +5 -7
- package/src/runtime/streams/session-serial-executor.ts +7 -6
- package/src/runtime/streams/stream-binding-runtime-ports.ts +79 -29
- package/src/runtime/streams/stream-frame-factory.ts +59 -40
- package/src/runtime/streams/stream-session-runtime.ts +317 -214
- package/src/runtime/workers/index.ts +68 -29
|
@@ -7,14 +7,12 @@ import type {
|
|
|
7
7
|
ZLinkRawReceivedRecord,
|
|
8
8
|
ZLinkRawRouterPort
|
|
9
9
|
} from '../backend/raw-binding-port';
|
|
10
|
-
import { RequestResult } from '../backend/runtime-values';
|
|
10
|
+
import { RequestResult, SubmitResult } from '../backend/runtime-values';
|
|
11
11
|
import type {
|
|
12
12
|
ApplicationJobPermitPort,
|
|
13
13
|
ApplicationJobQueuePort
|
|
14
14
|
} from '../application-jobs/contracts';
|
|
15
|
-
import {
|
|
16
|
-
ApplicationIngressRecordOwner
|
|
17
|
-
} from '../application-jobs/application-ingress-record-owner';
|
|
15
|
+
import { ApplicationIngressRecordOwner } from '../application-jobs/application-ingress-record-owner';
|
|
18
16
|
import { OperationRegistry, type PendingOperation } from './operation-registry';
|
|
19
17
|
import { ServiceLivenessRegistry, type ServiceLivenessTick } from './service-liveness-registry';
|
|
20
18
|
import { ServiceMailbox, type ServiceMailboxRecord } from './service-mailbox';
|
|
@@ -55,16 +53,9 @@ import {
|
|
|
55
53
|
} from './service-wire-constants.generated';
|
|
56
54
|
|
|
57
55
|
export type RawServicePumpResult =
|
|
58
|
-
| '
|
|
59
|
-
| 'infrastructure'
|
|
60
|
-
| 'application'
|
|
61
|
-
| 'dropped'
|
|
62
|
-
| 'protocolError';
|
|
56
|
+
'noData' | 'infrastructure' | 'application' | 'dropped' | 'protocolError';
|
|
63
57
|
|
|
64
|
-
export type RawServicePumpObserver = (
|
|
65
|
-
sourceRoutingId: string,
|
|
66
|
-
byteCount: number
|
|
67
|
-
) => void;
|
|
58
|
+
export type RawServicePumpObserver = (sourceRoutingId: string, byteCount: number) => void;
|
|
68
59
|
|
|
69
60
|
export interface RawServiceRequestResult {
|
|
70
61
|
readonly terminalResult: number;
|
|
@@ -72,6 +63,19 @@ export interface RawServiceRequestResult {
|
|
|
72
63
|
readonly payload?: ServiceApplicationPayload;
|
|
73
64
|
}
|
|
74
65
|
|
|
66
|
+
type RawServiceChannelTargetSelection =
|
|
67
|
+
| { readonly kind: 'selected'; readonly peer: AdmittedServicePeer }
|
|
68
|
+
| {
|
|
69
|
+
readonly kind: 'noMember';
|
|
70
|
+
readonly submitResult: typeof SubmitResult.NotFound;
|
|
71
|
+
readonly requestResult: RawServiceRequestResult;
|
|
72
|
+
}
|
|
73
|
+
| {
|
|
74
|
+
readonly kind: 'knownButNotReady';
|
|
75
|
+
readonly submitResult: typeof SubmitResult.NotConnected;
|
|
76
|
+
readonly requestResult: RawServiceRequestResult;
|
|
77
|
+
};
|
|
78
|
+
|
|
75
79
|
/** An M6A application frame already owned by the Framework runtime. */
|
|
76
80
|
type ServiceApplicationPayloadInput = ServiceApplicationPayload | Buffer;
|
|
77
81
|
|
|
@@ -101,10 +105,7 @@ export interface RawServiceMeshRuntimeOptions {
|
|
|
101
105
|
readonly peerAdmissionSealed?: () => boolean;
|
|
102
106
|
readonly onReceiveFlowConfigFailure?: (error: unknown) => void;
|
|
103
107
|
readonly onMailboxReady?: (domain: 'application' | 'infrastructure') => void;
|
|
104
|
-
readonly onPeerNotRequired?: (
|
|
105
|
-
nodeRoutingId: string,
|
|
106
|
-
endpoint: string
|
|
107
|
-
) => void;
|
|
108
|
+
readonly onPeerNotRequired?: (nodeRoutingId: string, endpoint: string) => void;
|
|
108
109
|
readonly onPeerDisconnected?: (
|
|
109
110
|
nodeRoutingId: string,
|
|
110
111
|
endpoint: string,
|
|
@@ -153,13 +154,16 @@ export class RawServiceMeshRuntime {
|
|
|
153
154
|
readonly liveness: ServiceLivenessRegistry;
|
|
154
155
|
|
|
155
156
|
private readonly operations = new OperationRegistry<RawServiceRequestResult>();
|
|
156
|
-
private readonly expectedPeers = new Map<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
private readonly expectedPeers = new Map<
|
|
158
|
+
string,
|
|
159
|
+
{
|
|
160
|
+
readonly meshName: string;
|
|
161
|
+
readonly nodeRoutingId: string;
|
|
162
|
+
readonly endpoint?: string;
|
|
163
|
+
readonly securityIdentity?: string;
|
|
164
|
+
readonly lifecycleGeneration?: bigint;
|
|
165
|
+
}
|
|
166
|
+
>();
|
|
163
167
|
private readonly endpointOnlyPeers = new Set<string>();
|
|
164
168
|
private readonly peerConnectionIntentRemoved = new Set<(nodeRoutingId: string) => void>();
|
|
165
169
|
private readonly connectionCandidates = new Map<
|
|
@@ -183,8 +187,7 @@ export class RawServiceMeshRuntime {
|
|
|
183
187
|
private readonly onPeerNotRequired?: RawServiceMeshRuntimeOptions['onPeerNotRequired'];
|
|
184
188
|
private readonly onPeerDisconnected?: RawServiceMeshRuntimeOptions['onPeerDisconnected'];
|
|
185
189
|
private readonly onProtocolError?: RawServiceMeshRuntimeOptions['onProtocolError'];
|
|
186
|
-
private readonly onReceiveFlowConfigFailure?:
|
|
187
|
-
RawServiceMeshRuntimeOptions['onReceiveFlowConfigFailure'];
|
|
190
|
+
private readonly onReceiveFlowConfigFailure?: RawServiceMeshRuntimeOptions['onReceiveFlowConfigFailure'];
|
|
188
191
|
private readonly resolveAdvertisedEndpoint?: RawServiceMeshRuntimeOptions['resolveAdvertisedEndpoint'];
|
|
189
192
|
private descriptor: ServiceNodeDescriptor;
|
|
190
193
|
private host?: ZLinkRawHostPort;
|
|
@@ -223,15 +226,14 @@ export class RawServiceMeshRuntime {
|
|
|
223
226
|
router.setRoutingId(this.descriptor.nodeRoutingId);
|
|
224
227
|
this.applicationJobQueue.registerReceiveFlowTarget?.(
|
|
225
228
|
router,
|
|
226
|
-
state => receiveFlowRouter.setReceiveFlowState(state),
|
|
229
|
+
(state) => receiveFlowRouter.setReceiveFlowState(state),
|
|
227
230
|
this.onReceiveFlowConfigFailure
|
|
228
231
|
);
|
|
229
232
|
router.bind(this.descriptor.advertisedEndpoint);
|
|
230
233
|
const boundEndpoint = router.localEndpoint();
|
|
231
234
|
const next = {
|
|
232
235
|
...this.descriptor,
|
|
233
|
-
advertisedEndpoint: this.resolveAdvertisedEndpoint?.(boundEndpoint)
|
|
234
|
-
?? boundEndpoint,
|
|
236
|
+
advertisedEndpoint: this.resolveAdvertisedEndpoint?.(boundEndpoint) ?? boundEndpoint,
|
|
235
237
|
descriptorRevision: this.descriptor.descriptorRevision + 1n,
|
|
236
238
|
state: 'serving' as const
|
|
237
239
|
};
|
|
@@ -297,35 +299,20 @@ export class RawServiceMeshRuntime {
|
|
|
297
299
|
this.endpointOnlyPeers.add(endpoint);
|
|
298
300
|
}
|
|
299
301
|
|
|
300
|
-
disconnectPeer(
|
|
301
|
-
endpoint: string,
|
|
302
|
-
nodeRoutingId: string,
|
|
303
|
-
lifecycleGeneration?: bigint
|
|
304
|
-
): void {
|
|
302
|
+
disconnectPeer(endpoint: string, nodeRoutingId: string, lifecycleGeneration?: bigint): void {
|
|
305
303
|
const current = this.topology.peer(nodeRoutingId);
|
|
306
304
|
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
307
305
|
if (
|
|
308
|
-
lifecycleGeneration !== undefined
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
)
|
|
319
|
-
||
|
|
320
|
-
(
|
|
321
|
-
current !== undefined
|
|
322
|
-
&& current.descriptor.lifecycleGeneration !== lifecycleGeneration
|
|
323
|
-
)
|
|
324
|
-
|| (
|
|
325
|
-
current === undefined
|
|
326
|
-
&& expected?.lifecycleGeneration !== lifecycleGeneration
|
|
327
|
-
)
|
|
328
|
-
)
|
|
306
|
+
lifecycleGeneration !== undefined &&
|
|
307
|
+
// Discovery has already fenced this RID to a replacement process.
|
|
308
|
+
// The old auto-connect intent must not use disconnectRid here: that
|
|
309
|
+
// is RID-wide and can close the provisional replacement before its
|
|
310
|
+
// Hello/admission promotes it. admitPeer owns exact old-pair teardown
|
|
311
|
+
// after the replacement descriptor is accepted.
|
|
312
|
+
((expected?.lifecycleGeneration !== undefined &&
|
|
313
|
+
expected.lifecycleGeneration !== lifecycleGeneration) ||
|
|
314
|
+
(current !== undefined && current.descriptor.lifecycleGeneration !== lifecycleGeneration) ||
|
|
315
|
+
(current === undefined && expected?.lifecycleGeneration !== lifecycleGeneration))
|
|
329
316
|
) {
|
|
330
317
|
return;
|
|
331
318
|
}
|
|
@@ -342,9 +329,9 @@ export class RawServiceMeshRuntime {
|
|
|
342
329
|
if (current !== undefined) this.removePeer(current);
|
|
343
330
|
this.topology.forgetNotRequired(nodeRoutingId);
|
|
344
331
|
if (
|
|
345
|
-
lifecycleGeneration === undefined
|
|
346
|
-
|
|
347
|
-
|
|
332
|
+
lifecycleGeneration === undefined ||
|
|
333
|
+
expected?.lifecycleGeneration === undefined ||
|
|
334
|
+
expected.lifecycleGeneration === lifecycleGeneration
|
|
348
335
|
) {
|
|
349
336
|
this.expectedPeers.delete(nodeRoutingId);
|
|
350
337
|
}
|
|
@@ -378,34 +365,38 @@ export class RawServiceMeshRuntime {
|
|
|
378
365
|
|
|
379
366
|
observePeerConnectionIntentRemoved(listener: (nodeRoutingId: string) => void): () => void {
|
|
380
367
|
this.peerConnectionIntentRemoved.add(listener);
|
|
381
|
-
return () => {
|
|
368
|
+
return () => {
|
|
369
|
+
this.peerConnectionIntentRemoved.delete(listener);
|
|
370
|
+
};
|
|
382
371
|
}
|
|
383
372
|
|
|
384
373
|
private notifyPeerConnectionIntentRemoved(nodeRoutingId: string): void {
|
|
385
374
|
// Only the logical owner's removal publishes lifecycle termination.
|
|
386
375
|
// A physical disconnect alone retains the connection expectation.
|
|
387
|
-
if (this.expectedPeers.has(nodeRoutingId) || this.topology.peer(nodeRoutingId) !== undefined)
|
|
376
|
+
if (this.expectedPeers.has(nodeRoutingId) || this.topology.peer(nodeRoutingId) !== undefined)
|
|
377
|
+
return;
|
|
388
378
|
for (const listener of this.peerConnectionIntentRemoved) listener(nodeRoutingId);
|
|
389
379
|
}
|
|
390
380
|
|
|
391
381
|
async announcePeer(nodeRoutingId: string): Promise<boolean> {
|
|
392
|
-
if (!this.expectedPeers.has(nodeRoutingId) || this.peerAdmissionSealed?.() === true)
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
);
|
|
382
|
+
if (!this.expectedPeers.has(nodeRoutingId) || this.peerAdmissionSealed?.() === true)
|
|
383
|
+
return false;
|
|
384
|
+
return this.send(nodeRoutingId, [
|
|
385
|
+
encodeRouteMeshAdmission(M6aServiceWireCommand.hello, this.topology.localDescriptor())
|
|
386
|
+
]);
|
|
397
387
|
}
|
|
398
388
|
|
|
399
389
|
isPeerRouteReady(nodeRoutingId: string, lifecycleGeneration?: bigint): boolean {
|
|
400
390
|
const peer = this.topology.peer(nodeRoutingId);
|
|
401
391
|
const monitorConnection = this.monitorConnectionStates.get(nodeRoutingId);
|
|
402
|
-
const applicationRouteReady =
|
|
403
|
-
|| monitorConnection === peer?.connectionId;
|
|
404
|
-
const ready =
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
&&
|
|
392
|
+
const applicationRouteReady =
|
|
393
|
+
monitorConnection === undefined || monitorConnection === peer?.connectionId;
|
|
394
|
+
const ready =
|
|
395
|
+
peer !== undefined &&
|
|
396
|
+
(lifecycleGeneration === undefined ||
|
|
397
|
+
peer.descriptor.lifecycleGeneration === lifecycleGeneration) &&
|
|
398
|
+
applicationRouteReady &&
|
|
399
|
+
this.liveness.isReady(nodeRoutingId, peer.connectionId);
|
|
409
400
|
return ready;
|
|
410
401
|
}
|
|
411
402
|
|
|
@@ -430,14 +421,16 @@ export class RawServiceMeshRuntime {
|
|
|
430
421
|
readonly state?: 'draining';
|
|
431
422
|
}): Promise<void> {
|
|
432
423
|
const current = this.topology.localDescriptor();
|
|
433
|
-
const channels =
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
channel
|
|
439
|
-
|
|
440
|
-
|
|
424
|
+
const channels =
|
|
425
|
+
options.state === 'draining'
|
|
426
|
+
? current.channels.map((channel) => ({ ...channel, weight: 0 }))
|
|
427
|
+
: options.channelName === undefined
|
|
428
|
+
? current.channels
|
|
429
|
+
: current.channels.map((channel) =>
|
|
430
|
+
channel.name === options.channelName
|
|
431
|
+
? { ...channel, weight: options.channelWeight! }
|
|
432
|
+
: channel
|
|
433
|
+
);
|
|
441
434
|
const next = {
|
|
442
435
|
...current,
|
|
443
436
|
descriptorRevision: current.descriptorRevision + 1n,
|
|
@@ -461,16 +454,15 @@ export class RawServiceMeshRuntime {
|
|
|
461
454
|
await this.announceExpectedPeers();
|
|
462
455
|
}
|
|
463
456
|
|
|
464
|
-
replaceDiscoveredNotRequired(
|
|
465
|
-
descriptors: readonly ServiceNodeDescriptor[]
|
|
466
|
-
): void {
|
|
457
|
+
replaceDiscoveredNotRequired(descriptors: readonly ServiceNodeDescriptor[]): void {
|
|
467
458
|
this.topology.replaceDiscoveredNotRequired(descriptors);
|
|
468
459
|
}
|
|
469
460
|
|
|
470
461
|
isObjectClientNodeDirectTarget(nodeRoutingId: string): boolean {
|
|
471
|
-
const descriptor =
|
|
472
|
-
|
|
473
|
-
|
|
462
|
+
const descriptor =
|
|
463
|
+
nodeRoutingId === this.descriptor.nodeRoutingId
|
|
464
|
+
? this.topology.localDescriptor()
|
|
465
|
+
: this.topology.knownDescriptor(nodeRoutingId);
|
|
474
466
|
return descriptor?.objectRole === 'client';
|
|
475
467
|
}
|
|
476
468
|
|
|
@@ -478,21 +470,16 @@ export class RawServiceMeshRuntime {
|
|
|
478
470
|
targetNodeRoutingId: string,
|
|
479
471
|
payload: ServiceApplicationPayloadInput
|
|
480
472
|
): Promise<boolean> {
|
|
481
|
-
return this.send(
|
|
482
|
-
targetNodeRoutingId,
|
|
483
|
-
[encodeNodeSendHeader(), this.applicationFrame(payload)]
|
|
484
|
-
);
|
|
473
|
+
return this.send(targetNodeRoutingId, [encodeNodeSendHeader(), this.applicationFrame(payload)]);
|
|
485
474
|
}
|
|
486
475
|
|
|
487
476
|
async sendToChannel(
|
|
488
477
|
channelName: string,
|
|
489
478
|
payload: ServiceApplicationPayloadInput
|
|
490
|
-
): Promise<
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
);
|
|
495
|
-
if (selected === undefined) return false;
|
|
479
|
+
): Promise<SubmitResult> {
|
|
480
|
+
const selection = this.selectChannelTarget(channelName);
|
|
481
|
+
if (selection.kind !== 'selected') return selection.submitResult;
|
|
482
|
+
const selected = selection.peer;
|
|
496
483
|
const applicationFrame = this.applicationFrame(payload);
|
|
497
484
|
if (selected.descriptor.nodeRoutingId === this.descriptor.nodeRoutingId) {
|
|
498
485
|
const applicationJobOwner = await this.reserveLocalIngress();
|
|
@@ -506,15 +493,17 @@ export class RawServiceMeshRuntime {
|
|
|
506
493
|
applicationJob
|
|
507
494
|
});
|
|
508
495
|
if (!accepted) applicationJob.close();
|
|
509
|
-
return accepted;
|
|
496
|
+
return accepted ? SubmitResult.Ok : SubmitResult.NotAdmitted;
|
|
510
497
|
} finally {
|
|
511
498
|
applicationJobOwner.close();
|
|
512
499
|
}
|
|
513
500
|
}
|
|
514
|
-
return this.send(selected.descriptor.nodeRoutingId, [
|
|
501
|
+
return (await this.send(selected.descriptor.nodeRoutingId, [
|
|
515
502
|
encodeChannelSendHeader(channelName),
|
|
516
503
|
applicationFrame
|
|
517
|
-
])
|
|
504
|
+
]))
|
|
505
|
+
? SubmitResult.Ok
|
|
506
|
+
: SubmitResult.NotConnected;
|
|
518
507
|
}
|
|
519
508
|
|
|
520
509
|
requestToNode(
|
|
@@ -529,19 +518,44 @@ export class RawServiceMeshRuntime {
|
|
|
529
518
|
channelName: string,
|
|
530
519
|
payload: ServiceApplicationPayloadInput,
|
|
531
520
|
timeoutMs: number
|
|
532
|
-
): PendingOperation<RawServiceRequestResult>
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
521
|
+
): PendingOperation<RawServiceRequestResult> {
|
|
522
|
+
const selection = this.selectChannelTarget(channelName);
|
|
523
|
+
if (selection.kind !== 'selected') {
|
|
524
|
+
const pending = this.operations.register(timeoutMs);
|
|
525
|
+
this.operations.complete(pending.id, selection.requestResult);
|
|
526
|
+
return pending;
|
|
527
|
+
}
|
|
528
|
+
return this.requestToTarget(
|
|
529
|
+
selection.peer.descriptor.nodeRoutingId,
|
|
530
|
+
payload,
|
|
531
|
+
timeoutMs,
|
|
532
|
+
channelName
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private selectChannelTarget(channelName: string): RawServiceChannelTargetSelection {
|
|
537
|
+
const selected = this.topology.selectChannel(channelName, (peer) =>
|
|
538
|
+
this.isLocalOrReadyPeer(peer.descriptor.nodeRoutingId)
|
|
536
539
|
);
|
|
537
|
-
return selected
|
|
538
|
-
|
|
539
|
-
|
|
540
|
+
if (selected !== undefined) return { kind: 'selected', peer: selected };
|
|
541
|
+
return this.topology.hasKnownChannelTarget(channelName)
|
|
542
|
+
? {
|
|
543
|
+
kind: 'knownButNotReady',
|
|
544
|
+
submitResult: SubmitResult.NotConnected,
|
|
545
|
+
requestResult: { terminalResult: RequestResult.NotConnected, failureCode: 0 }
|
|
546
|
+
}
|
|
547
|
+
: {
|
|
548
|
+
kind: 'noMember',
|
|
549
|
+
submitResult: SubmitResult.NotFound,
|
|
550
|
+
requestResult: {
|
|
551
|
+
terminalResult: RequestResult.NotFound,
|
|
552
|
+
failureCode: REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
|
|
553
|
+
}
|
|
554
|
+
};
|
|
540
555
|
}
|
|
541
556
|
|
|
542
557
|
private isLocalOrReadyPeer(nodeRoutingId: string): boolean {
|
|
543
|
-
return nodeRoutingId === this.descriptor.nodeRoutingId
|
|
544
|
-
|| this.isPeerRouteReady(nodeRoutingId);
|
|
558
|
+
return nodeRoutingId === this.descriptor.nodeRoutingId || this.isPeerRouteReady(nodeRoutingId);
|
|
545
559
|
}
|
|
546
560
|
|
|
547
561
|
setServiceIngress(handler: RawServiceIngressHandler): void {
|
|
@@ -551,24 +565,16 @@ export class RawServiceMeshRuntime {
|
|
|
551
565
|
this.serviceIngress = handler;
|
|
552
566
|
}
|
|
553
567
|
|
|
554
|
-
async reserveLocalIngress(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
: AbortSignal.any([this.applicationJobStop.signal, signal]);
|
|
568
|
+
async reserveLocalIngress(signal?: AbortSignal): Promise<ApplicationIngressRecordOwner> {
|
|
569
|
+
const waitSignal =
|
|
570
|
+
signal === undefined
|
|
571
|
+
? this.applicationJobStop.signal
|
|
572
|
+
: AbortSignal.any([this.applicationJobStop.signal, signal]);
|
|
560
573
|
const permit = await this.applicationJobQueue.acquire(waitSignal);
|
|
561
|
-
return ApplicationIngressRecordOwner.create(
|
|
562
|
-
this.applicationJobQueue,
|
|
563
|
-
permit,
|
|
564
|
-
{ close() {} }
|
|
565
|
-
);
|
|
574
|
+
return ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, { close() {} });
|
|
566
575
|
}
|
|
567
576
|
|
|
568
|
-
async sendService(
|
|
569
|
-
targetNodeRoutingId: string,
|
|
570
|
-
parts: readonly Uint8Array[]
|
|
571
|
-
): Promise<boolean> {
|
|
577
|
+
async sendService(targetNodeRoutingId: string, parts: readonly Uint8Array[]): Promise<boolean> {
|
|
572
578
|
return this.send(targetNodeRoutingId, parts);
|
|
573
579
|
}
|
|
574
580
|
|
|
@@ -637,7 +643,9 @@ export class RawServiceMeshRuntime {
|
|
|
637
643
|
const startedAtMs = performance.now();
|
|
638
644
|
let messages = 0;
|
|
639
645
|
let bytes = 0;
|
|
640
|
-
const observe: RawServicePumpObserver = (_source, byteCount) => {
|
|
646
|
+
const observe: RawServicePumpObserver = (_source, byteCount) => {
|
|
647
|
+
bytes += byteCount;
|
|
648
|
+
};
|
|
641
649
|
while (receiveReady && messages < 64 && !this.closed) {
|
|
642
650
|
const result = await this.receiveOne(performance.now(), observe);
|
|
643
651
|
if (result === 'noData') {
|
|
@@ -704,13 +712,13 @@ export class RawServiceMeshRuntime {
|
|
|
704
712
|
}
|
|
705
713
|
|
|
706
714
|
private pullMonitorEvents(): void {
|
|
707
|
-
this.monitor?.drain(event => {
|
|
715
|
+
this.monitor?.drain((event) => {
|
|
708
716
|
this.observeMonitorEvent(event);
|
|
709
717
|
if (this.monitorEvents.length < MAX_PENDING_MONITOR_EVENTS) {
|
|
710
718
|
this.monitorEvents.push(event);
|
|
711
719
|
return;
|
|
712
720
|
}
|
|
713
|
-
const existingIndex = this.monitorEvents.findIndex(candidate =>
|
|
721
|
+
const existingIndex = this.monitorEvents.findIndex((candidate) =>
|
|
714
722
|
sameMonitorConnection(candidate, event)
|
|
715
723
|
);
|
|
716
724
|
if (existingIndex >= 0) this.monitorEvents[existingIndex] = event;
|
|
@@ -740,17 +748,20 @@ export class RawServiceMeshRuntime {
|
|
|
740
748
|
if (received.requestSeq === undefined || received.parts.length === 0) return false;
|
|
741
749
|
try {
|
|
742
750
|
const header = decodeHeader(received.parts[0]!);
|
|
743
|
-
const correlation =
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
751
|
+
const correlation =
|
|
752
|
+
header.command === M6aServiceWireCommand.nodeRequest
|
|
753
|
+
? decodeNodeRequestHeader(received.parts[0]!)
|
|
754
|
+
: header.command === M6aServiceWireCommand.channelRequest
|
|
755
|
+
? decodeChannelRequestHeader(received.parts[0]!).correlation
|
|
756
|
+
: undefined;
|
|
748
757
|
if (correlation === undefined) return false;
|
|
749
|
-
const reply = [
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
758
|
+
const reply = [
|
|
759
|
+
encodeReplyHeader(
|
|
760
|
+
correlation,
|
|
761
|
+
RequestResult.ProtocolError,
|
|
762
|
+
ServiceWireFrameworkErrorCode.requestProtocolError
|
|
763
|
+
)
|
|
764
|
+
];
|
|
754
765
|
if (received.reply === undefined) return false;
|
|
755
766
|
received.reply(reply);
|
|
756
767
|
return true;
|
|
@@ -766,17 +777,13 @@ export class RawServiceMeshRuntime {
|
|
|
766
777
|
applicationJobOwner: ApplicationIngressRecordOwner
|
|
767
778
|
): Promise<RawServicePumpResult> {
|
|
768
779
|
if (
|
|
769
|
-
received.parts.length === 0
|
|
770
|
-
|
|
771
|
-
received.parts.length === 1
|
|
772
|
-
&& received.parts[0]!.byteLength === 0
|
|
773
|
-
)
|
|
780
|
+
received.parts.length === 0 ||
|
|
781
|
+
(received.parts.length === 1 && received.parts[0]!.byteLength === 0)
|
|
774
782
|
) {
|
|
775
783
|
if (this.peerAdmissionSealed?.() === true) return 'dropped';
|
|
776
|
-
return await this.send(
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
)
|
|
784
|
+
return (await this.send(received.sourceRid, [
|
|
785
|
+
encodeRouteMeshAdmission(M6aServiceWireCommand.hello, this.topology.localDescriptor())
|
|
786
|
+
]))
|
|
780
787
|
? 'infrastructure'
|
|
781
788
|
: 'dropped';
|
|
782
789
|
}
|
|
@@ -786,9 +793,9 @@ export class RawServiceMeshRuntime {
|
|
|
786
793
|
return 'dropped';
|
|
787
794
|
}
|
|
788
795
|
if (
|
|
789
|
-
header.command === M6aServiceWireCommand.hello
|
|
790
|
-
|
|
791
|
-
|
|
796
|
+
header.command === M6aServiceWireCommand.hello ||
|
|
797
|
+
header.command === M6aServiceWireCommand.admit ||
|
|
798
|
+
header.command === M6aServiceWireCommand.update
|
|
792
799
|
) {
|
|
793
800
|
if (received.parts.length !== 1) return 'protocolError';
|
|
794
801
|
const descriptor = decodeRouteMeshAdmission(
|
|
@@ -798,11 +805,9 @@ export class RawServiceMeshRuntime {
|
|
|
798
805
|
);
|
|
799
806
|
const expected = this.expectedPeers.get(received.sourceRid);
|
|
800
807
|
if (
|
|
801
|
-
expected !== undefined
|
|
802
|
-
|
|
803
|
-
expected.
|
|
804
|
-
|| expected.nodeRoutingId !== descriptor.nodeRoutingId
|
|
805
|
-
)
|
|
808
|
+
expected !== undefined &&
|
|
809
|
+
(expected.meshName !== descriptor.meshName ||
|
|
810
|
+
expected.nodeRoutingId !== descriptor.nodeRoutingId)
|
|
806
811
|
) {
|
|
807
812
|
await this.send(received.sourceRid, [encodeReject(3)]);
|
|
808
813
|
return 'infrastructure';
|
|
@@ -811,23 +816,19 @@ export class RawServiceMeshRuntime {
|
|
|
811
816
|
received.sourceRid,
|
|
812
817
|
descriptor.advertisedEndpoint
|
|
813
818
|
);
|
|
814
|
-
const result = this.admitPeer(
|
|
815
|
-
descriptor,
|
|
816
|
-
connection,
|
|
817
|
-
nowMs,
|
|
818
|
-
expected
|
|
819
|
-
);
|
|
819
|
+
const result = this.admitPeer(descriptor, connection, nowMs, expected);
|
|
820
820
|
if (result !== 'admitted' && result !== 'notRequired') {
|
|
821
|
-
const detail =
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
821
|
+
const detail =
|
|
822
|
+
result === 'invalidDescriptor'
|
|
823
|
+
? describeInvalidAdmissionDescriptor(
|
|
824
|
+
descriptor,
|
|
825
|
+
expected,
|
|
826
|
+
this.topology.peer(descriptor.nodeRoutingId)?.descriptor
|
|
827
|
+
)
|
|
828
|
+
: undefined;
|
|
828
829
|
console.warn(
|
|
829
|
-
`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}`
|
|
830
|
-
|
|
830
|
+
`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
|
|
831
|
+
(detail === undefined ? '.' : ` (${detail}).`)
|
|
831
832
|
);
|
|
832
833
|
await this.send(received.sourceRid, [encodeReject(admissionReason(result))]);
|
|
833
834
|
return 'infrastructure';
|
|
@@ -837,15 +838,11 @@ export class RawServiceMeshRuntime {
|
|
|
837
838
|
// Hello supplies only the sender's descriptor. Even NotRequired
|
|
838
839
|
// peers must receive ours before the intent owner closes transport;
|
|
839
840
|
// submitting a response does not guarantee delivery before close.
|
|
840
|
-
await this.send(
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
);
|
|
841
|
+
await this.send(received.sourceRid, [
|
|
842
|
+
encodeRouteMeshAdmission(M6aServiceWireCommand.admit, this.topology.localDescriptor())
|
|
843
|
+
]);
|
|
844
844
|
} else if (result === 'notRequired') {
|
|
845
|
-
this.retireNotRequiredExpectedPeer(
|
|
846
|
-
received.sourceRid,
|
|
847
|
-
descriptor.advertisedEndpoint
|
|
848
|
-
);
|
|
845
|
+
this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
|
|
849
846
|
}
|
|
850
847
|
return 'infrastructure';
|
|
851
848
|
}
|
|
@@ -875,8 +872,8 @@ export class RawServiceMeshRuntime {
|
|
|
875
872
|
const peer = this.topology.peer(received.sourceRid);
|
|
876
873
|
if (peer === undefined) return 'protocolError';
|
|
877
874
|
if (
|
|
878
|
-
header.command === M6aServiceWireCommand.livenessProbe
|
|
879
|
-
|
|
875
|
+
header.command === M6aServiceWireCommand.livenessProbe ||
|
|
876
|
+
header.command === M6aServiceWireCommand.livenessAck
|
|
880
877
|
) {
|
|
881
878
|
if (received.parts.length !== 1) return 'protocolError';
|
|
882
879
|
const record = livenessCodec.decodeLivenessRecord(received.parts[0]!);
|
|
@@ -886,23 +883,19 @@ export class RawServiceMeshRuntime {
|
|
|
886
883
|
peer.connectionId,
|
|
887
884
|
record.probeId
|
|
888
885
|
);
|
|
889
|
-
const sent =
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
886
|
+
const sent =
|
|
887
|
+
ack !== undefined &&
|
|
888
|
+
(await this.send(received.sourceRid, [
|
|
889
|
+
livenessCodec.encodeLivenessRecord({
|
|
890
|
+
command: M6aServiceWireCommand.livenessAck,
|
|
891
|
+
probeId: record.probeId
|
|
892
|
+
})
|
|
893
|
+
]));
|
|
896
894
|
if (!sent) {
|
|
897
895
|
return 'protocolError';
|
|
898
896
|
}
|
|
899
897
|
} else {
|
|
900
|
-
this.liveness.acknowledge(
|
|
901
|
-
received.sourceRid,
|
|
902
|
-
peer.connectionId,
|
|
903
|
-
record.probeId,
|
|
904
|
-
nowMs
|
|
905
|
-
);
|
|
898
|
+
this.liveness.acknowledge(received.sourceRid, peer.connectionId, record.probeId, nowMs);
|
|
906
899
|
}
|
|
907
900
|
return 'infrastructure';
|
|
908
901
|
}
|
|
@@ -919,7 +912,7 @@ export class RawServiceMeshRuntime {
|
|
|
919
912
|
});
|
|
920
913
|
if (stateful !== undefined) return stateful;
|
|
921
914
|
if (
|
|
922
|
-
header.flags === 0
|
|
915
|
+
header.flags === 0 &&
|
|
923
916
|
// A bare infrastructure control is normally exactly one frame, but a
|
|
924
917
|
// relocation Prepare now rides its bound-session journal as
|
|
925
918
|
// node-internal ZLNI frames trailing the canonical command frame
|
|
@@ -931,8 +924,8 @@ export class RawServiceMeshRuntime {
|
|
|
931
924
|
// protocolError (surfaced downstream as `invalid_frame`, stalling
|
|
932
925
|
// the source's Prepare resend loop past the relocation admission
|
|
933
926
|
// budget).
|
|
934
|
-
|
|
935
|
-
|
|
927
|
+
received.parts.length >= 1 &&
|
|
928
|
+
isBareInfrastructureControl(header.command)
|
|
936
929
|
) {
|
|
937
930
|
const accepted = this.mailbox.tryEnqueue({
|
|
938
931
|
owner: `node:${this.descriptor.nodeRoutingId}`,
|
|
@@ -946,9 +939,9 @@ export class RawServiceMeshRuntime {
|
|
|
946
939
|
return accepted ? 'infrastructure' : 'dropped';
|
|
947
940
|
}
|
|
948
941
|
if (
|
|
949
|
-
header.flags !== 0
|
|
950
|
-
|
|
951
|
-
|
|
942
|
+
header.flags !== 0 ||
|
|
943
|
+
received.parts.length !== 2 ||
|
|
944
|
+
![
|
|
952
945
|
M6aServiceWireCommand.nodeSend,
|
|
953
946
|
M6aServiceWireCommand.nodeRequest,
|
|
954
947
|
M6aServiceWireCommand.channelSend,
|
|
@@ -986,18 +979,15 @@ export class RawServiceMeshRuntime {
|
|
|
986
979
|
if (accepted) return 'application';
|
|
987
980
|
applicationJob.close();
|
|
988
981
|
if (correlation !== undefined && received.requestSeq !== undefined) {
|
|
989
|
-
this.replyService(
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
0
|
|
999
|
-
)
|
|
1000
|
-
]);
|
|
982
|
+
this.replyService(
|
|
983
|
+
{
|
|
984
|
+
sourceRoutingId: received.sourceRid,
|
|
985
|
+
sourceRoute: received.sourceRoute,
|
|
986
|
+
requestSequence: received.requestSeq,
|
|
987
|
+
...(received.reply === undefined ? {} : { reply: received.reply })
|
|
988
|
+
},
|
|
989
|
+
[encodeReplyHeader(correlation, RequestResult.NotConnected, 0)]
|
|
990
|
+
);
|
|
1001
991
|
return 'infrastructure';
|
|
1002
992
|
}
|
|
1003
993
|
return 'dropped';
|
|
@@ -1011,10 +1001,12 @@ export class RawServiceMeshRuntime {
|
|
|
1011
1001
|
const result = this.liveness.tick(nowMs);
|
|
1012
1002
|
this.requireStarted();
|
|
1013
1003
|
for (const probe of result.probes) {
|
|
1014
|
-
await this.send(probe.nodeRoutingId, [
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1004
|
+
await this.send(probe.nodeRoutingId, [
|
|
1005
|
+
livenessCodec.encodeLivenessRecord({
|
|
1006
|
+
command: M6aServiceWireCommand.livenessProbe,
|
|
1007
|
+
probeId: probe.probeId
|
|
1008
|
+
})
|
|
1009
|
+
]);
|
|
1018
1010
|
}
|
|
1019
1011
|
for (const nodeRoutingId of result.timedOutNodes) {
|
|
1020
1012
|
const peer = this.topology.peer(nodeRoutingId);
|
|
@@ -1039,15 +1031,17 @@ export class RawServiceMeshRuntime {
|
|
|
1039
1031
|
this.monitorEvents.length = 0;
|
|
1040
1032
|
for (const event of events) {
|
|
1041
1033
|
handled++;
|
|
1042
|
-
const nodeRoutingId = event.routingId
|
|
1043
|
-
?? this.expectedPeerRoutingId(event.remoteAddress);
|
|
1034
|
+
const nodeRoutingId = event.routingId ?? this.expectedPeerRoutingId(event.remoteAddress);
|
|
1044
1035
|
if (event.event === MONITOR_CONNECTION_READY && isConnectionReadyEdge(event)) {
|
|
1045
1036
|
if (nodeRoutingId === undefined) {
|
|
1046
1037
|
const candidate = this.createUnresolvedConnectionCandidate(event);
|
|
1047
1038
|
const alreadyQueued = this.unresolvedConnectionCandidates.some(
|
|
1048
|
-
value => value.connectionId === candidate.connectionId
|
|
1039
|
+
(value) => value.connectionId === candidate.connectionId
|
|
1049
1040
|
);
|
|
1050
|
-
if (
|
|
1041
|
+
if (
|
|
1042
|
+
!alreadyQueued &&
|
|
1043
|
+
this.unresolvedConnectionCandidates.length < MAX_UNRESOLVED_CONNECTION_CANDIDATES
|
|
1044
|
+
) {
|
|
1051
1045
|
this.unresolvedConnectionCandidates.push(candidate);
|
|
1052
1046
|
}
|
|
1053
1047
|
continue;
|
|
@@ -1064,7 +1058,8 @@ export class RawServiceMeshRuntime {
|
|
|
1064
1058
|
if (existingPeer !== undefined) {
|
|
1065
1059
|
if (this.liveness.isReady(nodeRoutingId, existingPeer.connectionId)) {
|
|
1066
1060
|
const existingCandidate = this.connectionCandidates
|
|
1067
|
-
.get(nodeRoutingId)
|
|
1061
|
+
.get(nodeRoutingId)
|
|
1062
|
+
?.get(existingPeer.connectionId);
|
|
1068
1063
|
if (this.isDiscoveredLifecycleReplacement(existingPeer, nodeRoutingId)) {
|
|
1069
1064
|
// A current discovery descriptor with the same RID but a
|
|
1070
1065
|
// different lifecycle token denotes a replacement process.
|
|
@@ -1117,22 +1112,17 @@ export class RawServiceMeshRuntime {
|
|
|
1117
1112
|
// route evidence available to the admission message.
|
|
1118
1113
|
this.connectionIds.set(nodeRoutingId, candidate.connectionId);
|
|
1119
1114
|
await this.announcePeer(nodeRoutingId);
|
|
1120
|
-
} else if (
|
|
1121
|
-
event.event === MONITOR_DISCONNECTED
|
|
1122
|
-
&& nodeRoutingId !== undefined
|
|
1123
|
-
) {
|
|
1115
|
+
} else if (event.event === MONITOR_DISCONNECTED && nodeRoutingId !== undefined) {
|
|
1124
1116
|
const peer = this.topology.peer(nodeRoutingId);
|
|
1125
1117
|
const disconnectedId = monitorConnectionId(event, nodeRoutingId);
|
|
1126
1118
|
this.removeConnectionCandidate(nodeRoutingId, disconnectedId);
|
|
1127
1119
|
if (peer !== undefined && peer.connectionId === disconnectedId) {
|
|
1128
1120
|
this.removePeer(peer);
|
|
1129
1121
|
}
|
|
1130
|
-
} else if (
|
|
1131
|
-
event.event === MONITOR_DISCONNECTED
|
|
1132
|
-
) {
|
|
1122
|
+
} else if (event.event === MONITOR_DISCONNECTED) {
|
|
1133
1123
|
const disconnectedId = monitorConnectionId(event);
|
|
1134
1124
|
const index = this.unresolvedConnectionCandidates.findIndex(
|
|
1135
|
-
candidate => candidate.connectionId === disconnectedId
|
|
1125
|
+
(candidate) => candidate.connectionId === disconnectedId
|
|
1136
1126
|
);
|
|
1137
1127
|
if (index >= 0) this.unresolvedConnectionCandidates.splice(index, 1);
|
|
1138
1128
|
}
|
|
@@ -1170,15 +1160,16 @@ export class RawServiceMeshRuntime {
|
|
|
1170
1160
|
channelName?: string
|
|
1171
1161
|
): PendingOperation<RawServiceRequestResult> {
|
|
1172
1162
|
const correlation = this.nextCorrelation++;
|
|
1173
|
-
const header =
|
|
1174
|
-
|
|
1175
|
-
|
|
1163
|
+
const header =
|
|
1164
|
+
channelName === undefined
|
|
1165
|
+
? encodeNodeRequestHeader(correlation)
|
|
1166
|
+
: encodeChannelRequestHeader(correlation, channelName);
|
|
1176
1167
|
const encodedPayload = this.applicationFrame(payload);
|
|
1177
1168
|
const pending = this.operations.register(timeoutMs);
|
|
1178
1169
|
let selectedTargetNodeRoutingId = targetNodeRoutingId;
|
|
1179
1170
|
if (
|
|
1180
|
-
selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId
|
|
1181
|
-
|
|
1171
|
+
selectedTargetNodeRoutingId !== this.descriptor.nodeRoutingId &&
|
|
1172
|
+
!this.isPeerRouteReady(selectedTargetNodeRoutingId)
|
|
1182
1173
|
) {
|
|
1183
1174
|
// Channel selection happens before native admission. If that selection
|
|
1184
1175
|
// becomes stale during a peer drain, choose another ready channel peer
|
|
@@ -1188,19 +1179,15 @@ export class RawServiceMeshRuntime {
|
|
|
1188
1179
|
if (channelName !== undefined) {
|
|
1189
1180
|
const excludedTargets = new Set([selectedTargetNodeRoutingId]);
|
|
1190
1181
|
for (;;) {
|
|
1191
|
-
const alternate = this.topology.selectChannel(
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
return !excludedTargets.has(candidate)
|
|
1196
|
-
&& this.isLocalOrReadyPeer(candidate);
|
|
1197
|
-
}
|
|
1198
|
-
);
|
|
1182
|
+
const alternate = this.topology.selectChannel(channelName, (peer) => {
|
|
1183
|
+
const candidate = peer.descriptor.nodeRoutingId;
|
|
1184
|
+
return !excludedTargets.has(candidate) && this.isLocalOrReadyPeer(candidate);
|
|
1185
|
+
});
|
|
1199
1186
|
if (alternate === undefined) break;
|
|
1200
1187
|
selectedTargetNodeRoutingId = alternate.descriptor.nodeRoutingId;
|
|
1201
1188
|
if (
|
|
1202
|
-
selectedTargetNodeRoutingId === this.descriptor.nodeRoutingId
|
|
1203
|
-
|
|
1189
|
+
selectedTargetNodeRoutingId === this.descriptor.nodeRoutingId ||
|
|
1190
|
+
this.isPeerRouteReady(selectedTargetNodeRoutingId)
|
|
1204
1191
|
) {
|
|
1205
1192
|
break;
|
|
1206
1193
|
}
|
|
@@ -1225,9 +1212,10 @@ export class RawServiceMeshRuntime {
|
|
|
1225
1212
|
return;
|
|
1226
1213
|
}
|
|
1227
1214
|
const accepted = this.mailbox.tryEnqueue({
|
|
1228
|
-
owner:
|
|
1229
|
-
|
|
1230
|
-
|
|
1215
|
+
owner:
|
|
1216
|
+
channelName === undefined
|
|
1217
|
+
? `node:${this.descriptor.nodeRoutingId}`
|
|
1218
|
+
: `channel:${channelName}`,
|
|
1231
1219
|
domain: 'application',
|
|
1232
1220
|
parts,
|
|
1233
1221
|
sourceRoutingId: this.descriptor.nodeRoutingId,
|
|
@@ -1250,7 +1238,7 @@ export class RawServiceMeshRuntime {
|
|
|
1250
1238
|
} finally {
|
|
1251
1239
|
applicationJobOwner.close();
|
|
1252
1240
|
}
|
|
1253
|
-
})().catch(error => this.operations.fail(pending.id, error));
|
|
1241
|
+
})().catch((error) => this.operations.fail(pending.id, error));
|
|
1254
1242
|
return pending;
|
|
1255
1243
|
}
|
|
1256
1244
|
if (!this.isPeerRouteReady(selectedTargetNodeRoutingId)) {
|
|
@@ -1258,12 +1246,11 @@ export class RawServiceMeshRuntime {
|
|
|
1258
1246
|
// topology has never observed. A known peer without a usable route is
|
|
1259
1247
|
// a Framework NotConnected result; an unknown RID is completed locally
|
|
1260
1248
|
// as RequestTargetNotFound without submitting an application frame.
|
|
1261
|
-
const knownTarget =
|
|
1262
|
-
|
|
1249
|
+
const knownTarget =
|
|
1250
|
+
this.topology.peer(selectedTargetNodeRoutingId) !== undefined ||
|
|
1251
|
+
this.topology.knownDescriptor(selectedTargetNodeRoutingId) !== undefined;
|
|
1263
1252
|
this.operations.complete(pending.id, {
|
|
1264
|
-
terminalResult: knownTarget
|
|
1265
|
-
? RequestResult.NotConnected
|
|
1266
|
-
: RequestResult.NotFound,
|
|
1253
|
+
terminalResult: knownTarget ? RequestResult.NotConnected : RequestResult.NotFound,
|
|
1267
1254
|
failureCode: knownTarget ? 0 : REQUEST_TARGET_NOT_FOUND_FAILURE_CODE
|
|
1268
1255
|
});
|
|
1269
1256
|
return pending;
|
|
@@ -1273,25 +1260,24 @@ export class RawServiceMeshRuntime {
|
|
|
1273
1260
|
let request: Promise<readonly Uint8Array[]>;
|
|
1274
1261
|
try {
|
|
1275
1262
|
router = this.requireStarted();
|
|
1276
|
-
request = router.request(
|
|
1277
|
-
selectedTargetNodeRoutingId,
|
|
1278
|
-
parts,
|
|
1279
|
-
timeoutMs
|
|
1280
|
-
);
|
|
1263
|
+
request = router.request(selectedTargetNodeRoutingId, parts, timeoutMs);
|
|
1281
1264
|
} catch (error) {
|
|
1282
1265
|
this.operations.fail(pending.id, error);
|
|
1283
1266
|
return pending;
|
|
1284
1267
|
}
|
|
1285
1268
|
void request.then(
|
|
1286
|
-
replyParts => {
|
|
1269
|
+
(replyParts) => {
|
|
1287
1270
|
try {
|
|
1288
1271
|
if (replyParts.length < 1 || replyParts.length > 2) {
|
|
1289
1272
|
throw new ServiceWireProtocolError('Invalid reply parts.');
|
|
1290
1273
|
}
|
|
1291
1274
|
const reply = decodeReplyHeader(replyParts[0]!);
|
|
1292
|
-
if (reply.correlation !== correlation)
|
|
1275
|
+
if (reply.correlation !== correlation)
|
|
1276
|
+
throw new ServiceWireProtocolError('Reply correlation mismatch.');
|
|
1293
1277
|
if (reply.tail.byteLength !== 0) {
|
|
1294
|
-
throw new ServiceWireProtocolError(
|
|
1278
|
+
throw new ServiceWireProtocolError(
|
|
1279
|
+
'Generic node/channel reply carries an operation-specific tail.'
|
|
1280
|
+
);
|
|
1295
1281
|
}
|
|
1296
1282
|
if (reply.terminalResult === 0 && replyParts.length !== 2) {
|
|
1297
1283
|
throw new ServiceWireProtocolError('Successful reply omits its payload.');
|
|
@@ -1313,7 +1299,7 @@ export class RawServiceMeshRuntime {
|
|
|
1313
1299
|
this.operations.fail(pending.id, error);
|
|
1314
1300
|
}
|
|
1315
1301
|
},
|
|
1316
|
-
error => {
|
|
1302
|
+
(error) => {
|
|
1317
1303
|
this.operations.fail(pending.id, error);
|
|
1318
1304
|
}
|
|
1319
1305
|
);
|
|
@@ -1344,15 +1330,11 @@ export class RawServiceMeshRuntime {
|
|
|
1344
1330
|
): PeerAdmissionResult {
|
|
1345
1331
|
const previous = this.topology.peer(descriptor.nodeRoutingId);
|
|
1346
1332
|
if (
|
|
1347
|
-
previous !== undefined
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
descriptor.descriptorRevision
|
|
1351
|
-
|
|
1352
|
-
descriptor.descriptorRevision === previous.descriptor.descriptorRevision
|
|
1353
|
-
&& !sameServiceNodeDescriptor(previous.descriptor, descriptor)
|
|
1354
|
-
)
|
|
1355
|
-
)
|
|
1333
|
+
previous !== undefined &&
|
|
1334
|
+
previous.descriptor.lifecycleGeneration === descriptor.lifecycleGeneration &&
|
|
1335
|
+
(descriptor.descriptorRevision < previous.descriptor.descriptorRevision ||
|
|
1336
|
+
(descriptor.descriptorRevision === previous.descriptor.descriptorRevision &&
|
|
1337
|
+
!sameServiceNodeDescriptor(previous.descriptor, descriptor)))
|
|
1356
1338
|
) {
|
|
1357
1339
|
throw new ServiceWireProtocolError(
|
|
1358
1340
|
`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`
|
|
@@ -1365,45 +1347,24 @@ export class RawServiceMeshRuntime {
|
|
|
1365
1347
|
connection.discriminator
|
|
1366
1348
|
);
|
|
1367
1349
|
if (result === 'admitted') {
|
|
1368
|
-
this.connectionIds.set(
|
|
1369
|
-
descriptor.nodeRoutingId,
|
|
1370
|
-
connection.connectionId
|
|
1371
|
-
);
|
|
1350
|
+
this.connectionIds.set(descriptor.nodeRoutingId, connection.connectionId);
|
|
1372
1351
|
this.liveness.admit(descriptor.nodeRoutingId, connection.connectionId, nowMs);
|
|
1373
|
-
this.liveness.requestProbe(
|
|
1374
|
-
|
|
1375
|
-
connection.connectionId,
|
|
1376
|
-
nowMs
|
|
1377
|
-
);
|
|
1378
|
-
this.monitorConnectionStates.set(
|
|
1379
|
-
descriptor.nodeRoutingId,
|
|
1380
|
-
connection.connectionId
|
|
1381
|
-
);
|
|
1352
|
+
this.liveness.requestProbe(descriptor.nodeRoutingId, connection.connectionId, nowMs);
|
|
1353
|
+
this.monitorConnectionStates.set(descriptor.nodeRoutingId, connection.connectionId);
|
|
1382
1354
|
if (previous !== undefined && previous.connectionId !== connection.connectionId) {
|
|
1383
1355
|
const previousCandidate = this.connectionCandidates
|
|
1384
|
-
.get(descriptor.nodeRoutingId)
|
|
1356
|
+
.get(descriptor.nodeRoutingId)
|
|
1357
|
+
?.get(previous.connectionId);
|
|
1385
1358
|
if (previousCandidate !== undefined) {
|
|
1386
|
-
this.removeConnectionCandidate(
|
|
1387
|
-
descriptor.nodeRoutingId,
|
|
1388
|
-
previousCandidate.connectionId
|
|
1389
|
-
);
|
|
1359
|
+
this.removeConnectionCandidate(descriptor.nodeRoutingId, previousCandidate.connectionId);
|
|
1390
1360
|
}
|
|
1391
1361
|
}
|
|
1392
1362
|
} else if (result === 'notRequired' && previous !== undefined) {
|
|
1393
|
-
this.liveness.disconnect(
|
|
1394
|
-
descriptor.nodeRoutingId,
|
|
1395
|
-
previous.connectionId
|
|
1396
|
-
);
|
|
1363
|
+
this.liveness.disconnect(descriptor.nodeRoutingId, previous.connectionId);
|
|
1397
1364
|
} else if (previous !== undefined) {
|
|
1398
|
-
this.connectionIds.set(
|
|
1399
|
-
descriptor.nodeRoutingId,
|
|
1400
|
-
previous.connectionId
|
|
1401
|
-
);
|
|
1365
|
+
this.connectionIds.set(descriptor.nodeRoutingId, previous.connectionId);
|
|
1402
1366
|
if (connection.connectionId !== previous.connectionId) {
|
|
1403
|
-
this.removeConnectionCandidate(
|
|
1404
|
-
descriptor.nodeRoutingId,
|
|
1405
|
-
connection.connectionId
|
|
1406
|
-
);
|
|
1367
|
+
this.removeConnectionCandidate(descriptor.nodeRoutingId, connection.connectionId);
|
|
1407
1368
|
}
|
|
1408
1369
|
}
|
|
1409
1370
|
return result;
|
|
@@ -1414,32 +1375,30 @@ export class RawServiceMeshRuntime {
|
|
|
1414
1375
|
advertisedEndpoint: string
|
|
1415
1376
|
): PhysicalConnectionCandidate {
|
|
1416
1377
|
let connectionId = this.connectionIds.get(nodeRoutingId);
|
|
1417
|
-
let candidate =
|
|
1418
|
-
|
|
1419
|
-
|
|
1378
|
+
let candidate =
|
|
1379
|
+
connectionId === undefined
|
|
1380
|
+
? undefined
|
|
1381
|
+
: this.connectionCandidates.get(nodeRoutingId)?.get(connectionId);
|
|
1420
1382
|
if (candidate === undefined) {
|
|
1421
|
-
candidate = this.promoteUnresolvedConnectionCandidate(
|
|
1422
|
-
nodeRoutingId,
|
|
1423
|
-
advertisedEndpoint
|
|
1424
|
-
);
|
|
1383
|
+
candidate = this.promoteUnresolvedConnectionCandidate(nodeRoutingId, advertisedEndpoint);
|
|
1425
1384
|
connectionId = candidate?.connectionId;
|
|
1426
1385
|
}
|
|
1427
1386
|
if (candidate === undefined) {
|
|
1428
1387
|
const localRid = this.topology.localDescriptor().nodeRoutingId;
|
|
1429
1388
|
const endpointOnly = this.endpointOnlyPeers.has(advertisedEndpoint);
|
|
1430
|
-
const direction: PhysicalConnectionDirection =
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
?
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1389
|
+
const direction: PhysicalConnectionDirection = this.expectedPeers.has(nodeRoutingId)
|
|
1390
|
+
? 'outbound'
|
|
1391
|
+
: endpointOnly
|
|
1392
|
+
? localRid.localeCompare(nodeRoutingId) <= 0
|
|
1393
|
+
? 'outbound'
|
|
1394
|
+
: 'inbound'
|
|
1395
|
+
: 'inbound';
|
|
1396
|
+
const initiator =
|
|
1397
|
+
endpointOnly && localRid.localeCompare(nodeRoutingId) > 0
|
|
1398
|
+
? nodeRoutingId
|
|
1399
|
+
: direction === 'outbound'
|
|
1400
|
+
? localRid
|
|
1401
|
+
: nodeRoutingId;
|
|
1443
1402
|
connectionId = `unmonitored:${direction}:${randomUUID()}`;
|
|
1444
1403
|
candidate = {
|
|
1445
1404
|
connectionId,
|
|
@@ -1473,17 +1432,19 @@ export class RawServiceMeshRuntime {
|
|
|
1473
1432
|
: this.endpointOnlyPeers.has(event.remoteAddress)
|
|
1474
1433
|
? 'outbound'
|
|
1475
1434
|
: 'unknown';
|
|
1476
|
-
const initiator =
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1435
|
+
const initiator =
|
|
1436
|
+
direction === 'outbound'
|
|
1437
|
+
? local.nodeRoutingId
|
|
1438
|
+
: direction === 'inbound'
|
|
1439
|
+
? nodeRoutingId
|
|
1440
|
+
: undefined;
|
|
1481
1441
|
return {
|
|
1482
1442
|
connectionId: monitorConnectionId(event, nodeRoutingId),
|
|
1483
1443
|
direction,
|
|
1484
|
-
discriminator:
|
|
1485
|
-
|
|
1486
|
-
|
|
1444
|
+
discriminator:
|
|
1445
|
+
initiator === undefined
|
|
1446
|
+
? `unknown:${monitorConnectionId(event, nodeRoutingId)}`
|
|
1447
|
+
: `initiator:${initiator}`,
|
|
1487
1448
|
localAddress: event.localAddress,
|
|
1488
1449
|
remoteAddress: event.remoteAddress
|
|
1489
1450
|
};
|
|
@@ -1495,8 +1456,8 @@ export class RawServiceMeshRuntime {
|
|
|
1495
1456
|
const connectionId = monitorConnectionId(event);
|
|
1496
1457
|
const local = this.topology.localDescriptor();
|
|
1497
1458
|
const direction: PhysicalConnectionDirection =
|
|
1498
|
-
this.endpointOnlyPeers.has(event.remoteAddress)
|
|
1499
|
-
|
|
1459
|
+
this.endpointOnlyPeers.has(event.remoteAddress) ||
|
|
1460
|
+
this.expectedPeerRoutingId(event.remoteAddress) !== undefined
|
|
1500
1461
|
? 'outbound'
|
|
1501
1462
|
: event.localAddress === local.advertisedEndpoint
|
|
1502
1463
|
? 'inbound'
|
|
@@ -1516,11 +1477,12 @@ export class RawServiceMeshRuntime {
|
|
|
1516
1477
|
): PhysicalConnectionCandidate | undefined {
|
|
1517
1478
|
const relevant = this.unresolvedConnectionCandidates
|
|
1518
1479
|
.map((candidate, index) => ({ candidate, index }))
|
|
1519
|
-
.filter(
|
|
1520
|
-
candidate
|
|
1521
|
-
|
|
1480
|
+
.filter(
|
|
1481
|
+
({ candidate }) =>
|
|
1482
|
+
candidate.remoteAddress === advertisedEndpoint || candidate.direction === 'inbound'
|
|
1483
|
+
);
|
|
1522
1484
|
if (relevant.length === 0) return undefined;
|
|
1523
|
-
const directions = new Set(relevant.map(value => value.candidate.direction));
|
|
1485
|
+
const directions = new Set(relevant.map((value) => value.candidate.direction));
|
|
1524
1486
|
const localRid = this.topology.localDescriptor().nodeRoutingId;
|
|
1525
1487
|
const preferredDirection: PhysicalConnectionDirection =
|
|
1526
1488
|
directions.has('inbound') && directions.has('outbound')
|
|
@@ -1528,21 +1490,22 @@ export class RawServiceMeshRuntime {
|
|
|
1528
1490
|
? 'outbound'
|
|
1529
1491
|
: 'inbound'
|
|
1530
1492
|
: relevant.at(-1)!.candidate.direction;
|
|
1531
|
-
const selected =
|
|
1532
|
-
.reverse()
|
|
1533
|
-
.
|
|
1534
|
-
?? relevant.at(-1)!;
|
|
1493
|
+
const selected =
|
|
1494
|
+
[...relevant].reverse().find((value) => value.candidate.direction === preferredDirection) ??
|
|
1495
|
+
relevant.at(-1)!;
|
|
1535
1496
|
this.unresolvedConnectionCandidates.splice(selected.index, 1);
|
|
1536
|
-
const initiator =
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1497
|
+
const initiator =
|
|
1498
|
+
selected.candidate.direction === 'outbound'
|
|
1499
|
+
? localRid
|
|
1500
|
+
: selected.candidate.direction === 'inbound'
|
|
1501
|
+
? nodeRoutingId
|
|
1502
|
+
: undefined;
|
|
1541
1503
|
const candidate: PhysicalConnectionCandidate = {
|
|
1542
1504
|
...selected.candidate,
|
|
1543
|
-
discriminator:
|
|
1544
|
-
|
|
1545
|
-
|
|
1505
|
+
discriminator:
|
|
1506
|
+
initiator === undefined
|
|
1507
|
+
? `unknown:${selected.candidate.connectionId}`
|
|
1508
|
+
: `initiator:${initiator}`
|
|
1546
1509
|
};
|
|
1547
1510
|
let candidates = this.connectionCandidates.get(nodeRoutingId);
|
|
1548
1511
|
if (candidates === undefined) {
|
|
@@ -1571,10 +1534,12 @@ export class RawServiceMeshRuntime {
|
|
|
1571
1534
|
// A same-RID replacement is permitted only from a complete discovery
|
|
1572
1535
|
// fence. Manual/endpoint-only intent has no authority to replace a ready
|
|
1573
1536
|
// peer, and lifecycle generations are opaque equality tokens.
|
|
1574
|
-
return
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1537
|
+
return (
|
|
1538
|
+
expected?.endpoint !== undefined &&
|
|
1539
|
+
expected.securityIdentity !== undefined &&
|
|
1540
|
+
expected.lifecycleGeneration !== undefined &&
|
|
1541
|
+
admitted.descriptor.lifecycleGeneration !== expected.lifecycleGeneration
|
|
1542
|
+
);
|
|
1578
1543
|
}
|
|
1579
1544
|
|
|
1580
1545
|
private expectedPeerRoutingId(endpoint: string): string | undefined {
|
|
@@ -1594,22 +1559,20 @@ export class RawServiceMeshRuntime {
|
|
|
1594
1559
|
// discovery advertised endpoint would reject valid READY events.
|
|
1595
1560
|
if (event.routingId === nodeRoutingId) return true;
|
|
1596
1561
|
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1597
|
-
return
|
|
1598
|
-
|
|
1562
|
+
return (
|
|
1563
|
+
expected === undefined ||
|
|
1564
|
+
expected.endpoint === undefined ||
|
|
1565
|
+
expected.endpoint === event.remoteAddress
|
|
1566
|
+
);
|
|
1599
1567
|
}
|
|
1600
1568
|
|
|
1601
|
-
private retireNotRequiredExpectedPeer(
|
|
1602
|
-
nodeRoutingId: string,
|
|
1603
|
-
advertisedEndpoint?: string
|
|
1604
|
-
): void {
|
|
1569
|
+
private retireNotRequiredExpectedPeer(nodeRoutingId: string, advertisedEndpoint?: string): void {
|
|
1605
1570
|
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
1606
|
-
const endpoint =
|
|
1607
|
-
??
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
: undefined
|
|
1612
|
-
);
|
|
1571
|
+
const endpoint =
|
|
1572
|
+
expected?.endpoint ??
|
|
1573
|
+
(advertisedEndpoint !== undefined && this.endpointOnlyPeers.has(advertisedEndpoint)
|
|
1574
|
+
? advertisedEndpoint
|
|
1575
|
+
: undefined);
|
|
1613
1576
|
if (endpoint !== undefined) {
|
|
1614
1577
|
this.requireStarted().disconnect(endpoint);
|
|
1615
1578
|
this.endpointOnlyPeers.delete(endpoint);
|
|
@@ -1647,8 +1610,7 @@ export class RawServiceMeshRuntime {
|
|
|
1647
1610
|
}
|
|
1648
1611
|
|
|
1649
1612
|
private observeMonitorEvent(event: ZLinkRawMonitorRecord): void {
|
|
1650
|
-
const nodeRoutingId = event.routingId
|
|
1651
|
-
?? this.expectedPeerRoutingId(event.remoteAddress);
|
|
1613
|
+
const nodeRoutingId = event.routingId ?? this.expectedPeerRoutingId(event.remoteAddress);
|
|
1652
1614
|
if (nodeRoutingId === undefined) return;
|
|
1653
1615
|
const connectionId = monitorConnectionId(event, nodeRoutingId);
|
|
1654
1616
|
if (event.event === MONITOR_CONNECTION_READY && isConnectionReadyEdge(event)) {
|
|
@@ -1657,9 +1619,11 @@ export class RawServiceMeshRuntime {
|
|
|
1657
1619
|
// allow a late stale READY to overwrite the admitted replacement.
|
|
1658
1620
|
return;
|
|
1659
1621
|
}
|
|
1660
|
-
if (
|
|
1661
|
-
|
|
1662
|
-
|
|
1622
|
+
if (
|
|
1623
|
+
event.event === MONITOR_DISCONNECTED &&
|
|
1624
|
+
this.monitorConnectionStates.get(nodeRoutingId) === connectionId &&
|
|
1625
|
+
this.topology.peer(nodeRoutingId)?.connectionId === connectionId
|
|
1626
|
+
) {
|
|
1663
1627
|
this.monitorConnectionStates.set(nodeRoutingId, null);
|
|
1664
1628
|
}
|
|
1665
1629
|
}
|
|
@@ -1669,10 +1633,7 @@ export class RawServiceMeshRuntime {
|
|
|
1669
1633
|
return this.router;
|
|
1670
1634
|
}
|
|
1671
1635
|
|
|
1672
|
-
private async send(
|
|
1673
|
-
targetNodeRoutingId: string,
|
|
1674
|
-
parts: readonly Uint8Array[]
|
|
1675
|
-
): Promise<boolean> {
|
|
1636
|
+
private async send(targetNodeRoutingId: string, parts: readonly Uint8Array[]): Promise<boolean> {
|
|
1676
1637
|
try {
|
|
1677
1638
|
await this.requireStarted().send(targetNodeRoutingId, parts);
|
|
1678
1639
|
return true;
|
|
@@ -1680,7 +1641,6 @@ export class RawServiceMeshRuntime {
|
|
|
1680
1641
|
return false;
|
|
1681
1642
|
}
|
|
1682
1643
|
}
|
|
1683
|
-
|
|
1684
1644
|
}
|
|
1685
1645
|
|
|
1686
1646
|
/**
|
|
@@ -1725,11 +1685,7 @@ function monitorConnectionId(
|
|
|
1725
1685
|
resolvedNodeRoutingId = event.routingId ?? ''
|
|
1726
1686
|
): string {
|
|
1727
1687
|
if (event.connectionId !== undefined && event.connectionId !== 0n) {
|
|
1728
|
-
return JSON.stringify([
|
|
1729
|
-
resolvedNodeRoutingId,
|
|
1730
|
-
'connection',
|
|
1731
|
-
event.connectionId.toString()
|
|
1732
|
-
]);
|
|
1688
|
+
return JSON.stringify([resolvedNodeRoutingId, 'connection', event.connectionId.toString()]);
|
|
1733
1689
|
}
|
|
1734
1690
|
return JSON.stringify([
|
|
1735
1691
|
// Monitor `value` is event-specific: CONNECTION_READY reports the
|
|
@@ -1742,12 +1698,11 @@ function monitorConnectionId(
|
|
|
1742
1698
|
]);
|
|
1743
1699
|
}
|
|
1744
1700
|
|
|
1745
|
-
function sameMonitorConnection(
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
&& left.remoteAddress === right.remoteAddress;
|
|
1701
|
+
function sameMonitorConnection(left: ZLinkRawMonitorRecord, right: ZLinkRawMonitorRecord): boolean {
|
|
1702
|
+
return (
|
|
1703
|
+
monitorConnectionId(left) === monitorConnectionId(right) &&
|
|
1704
|
+
left.remoteAddress === right.remoteAddress
|
|
1705
|
+
);
|
|
1751
1706
|
}
|
|
1752
1707
|
|
|
1753
1708
|
function isConnectionReadyEdge(event: ZLinkRawMonitorRecord): boolean {
|
|
@@ -1766,21 +1721,26 @@ function describeInvalidAdmissionDescriptor(
|
|
|
1766
1721
|
} catch (error) {
|
|
1767
1722
|
return `descriptor validation: ${error instanceof Error ? error.message : String(error)}`;
|
|
1768
1723
|
}
|
|
1769
|
-
if (expected?.endpoint !== undefined
|
|
1770
|
-
&& descriptor.advertisedEndpoint !== expected.endpoint) {
|
|
1724
|
+
if (expected?.endpoint !== undefined && descriptor.advertisedEndpoint !== expected.endpoint) {
|
|
1771
1725
|
return `advertisedEndpoint expected='${expected.endpoint}' actual='${descriptor.advertisedEndpoint}'`;
|
|
1772
1726
|
}
|
|
1773
|
-
if (
|
|
1774
|
-
|
|
1727
|
+
if (
|
|
1728
|
+
expected?.securityIdentity !== undefined &&
|
|
1729
|
+
descriptor.securityIdentity !== expected.securityIdentity
|
|
1730
|
+
) {
|
|
1775
1731
|
return `securityIdentity expected='${expected.securityIdentity}' actual='${descriptor.securityIdentity}'`;
|
|
1776
1732
|
}
|
|
1777
|
-
if (
|
|
1778
|
-
|
|
1733
|
+
if (
|
|
1734
|
+
expected?.lifecycleGeneration !== undefined &&
|
|
1735
|
+
descriptor.lifecycleGeneration !== expected.lifecycleGeneration
|
|
1736
|
+
) {
|
|
1779
1737
|
return `lifecycleGeneration expected=${expected.lifecycleGeneration} actual=${descriptor.lifecycleGeneration}`;
|
|
1780
1738
|
}
|
|
1781
|
-
if (
|
|
1782
|
-
|
|
1783
|
-
|
|
1739
|
+
if (
|
|
1740
|
+
current !== undefined &&
|
|
1741
|
+
current.lifecycleGeneration === descriptor.lifecycleGeneration &&
|
|
1742
|
+
descriptor.descriptorRevision > current.descriptorRevision
|
|
1743
|
+
) {
|
|
1784
1744
|
const immutableField = immutableDescriptorMismatch(current, descriptor);
|
|
1785
1745
|
if (immutableField !== undefined) return immutableField;
|
|
1786
1746
|
}
|
|
@@ -1792,19 +1752,27 @@ function immutableDescriptorMismatch(
|
|
|
1792
1752
|
descriptor: ServiceNodeDescriptor
|
|
1793
1753
|
): string | undefined {
|
|
1794
1754
|
const fields: ReadonlyArray<keyof ServiceNodeDescriptor> = [
|
|
1795
|
-
'advertisedEndpoint',
|
|
1796
|
-
'
|
|
1755
|
+
'advertisedEndpoint',
|
|
1756
|
+
'securityIdentity',
|
|
1757
|
+
'applicationVersion',
|
|
1758
|
+
'objectRole',
|
|
1759
|
+
'activeCapacityLimit',
|
|
1760
|
+
'pendingCapacityLimit'
|
|
1797
1761
|
];
|
|
1798
1762
|
for (const field of fields) {
|
|
1799
1763
|
if (current[field] !== descriptor[field]) {
|
|
1800
1764
|
return `${field} changed within lifecycle expected=${String(current[field])} actual=${String(descriptor[field])}`;
|
|
1801
1765
|
}
|
|
1802
1766
|
}
|
|
1803
|
-
if (
|
|
1767
|
+
if (
|
|
1768
|
+
JSON.stringify(current.protocolCapabilities) !== JSON.stringify(descriptor.protocolCapabilities)
|
|
1769
|
+
) {
|
|
1804
1770
|
return `protocolCapabilities changed within lifecycle expected=${JSON.stringify(current.protocolCapabilities)} actual=${JSON.stringify(descriptor.protocolCapabilities)}`;
|
|
1805
1771
|
}
|
|
1806
|
-
if (
|
|
1807
|
-
|
|
1772
|
+
if (
|
|
1773
|
+
JSON.stringify(current.channels.map((channel) => channel.name)) !==
|
|
1774
|
+
JSON.stringify(descriptor.channels.map((channel) => channel.name))
|
|
1775
|
+
) {
|
|
1808
1776
|
return 'channels changed within lifecycle';
|
|
1809
1777
|
}
|
|
1810
1778
|
return undefined;
|