@zlink-systems/framework 0.29.1 → 0.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +150 -68
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
- package/dist/contracts/Channels/Calls.d.ts +2 -1
- package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
- package/dist/contracts/Configuration/Builders.d.ts +1 -2
- package/dist/contracts/Configuration/Configs.d.ts +0 -5
- package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
- package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
- package/dist/contracts/Configuration/index.d.ts +1 -1
- package/dist/contracts/Handlers/Attributes.d.ts +5 -13
- package/dist/contracts/Handlers/Attributes.js +7 -11
- package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
- package/dist/contracts/Handlers/JsonContract.js +4 -153
- package/dist/contracts/Spots/Contracts.d.ts +2 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.js +3 -1
- package/dist/nest-integration.d.ts +1 -1
- package/dist/nest-integration.js +2 -1
- package/dist/runtime/actors/actor-client.d.ts +1 -1
- package/dist/runtime/actors/actor-client.js +14 -12
- package/dist/runtime/actors/actor-handoff.d.ts +3 -2
- package/dist/runtime/actors/actor-handoff.js +15 -7
- package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
- package/dist/runtime/actors/actor-local-native-join.js +9 -12
- package/dist/runtime/actors/actor-remote-wire.js +15 -0
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
- package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
- package/dist/runtime/actors/index.d.ts +2 -1
- package/dist/runtime/actors/index.js +18 -6
- package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
- package/dist/runtime/admission.d.ts +1 -1
- package/dist/runtime/admission.js +15 -5
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +9 -9
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +45 -23
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +5 -2
- package/dist/runtime/application-jobs/application-job-queue-scope.js +41 -21
- package/dist/runtime/application-jobs/contracts.d.ts +15 -2
- package/dist/runtime/backend/contracts/index.d.ts +27 -27
- package/dist/runtime/backend/mesh-completion-table.d.ts +15 -5
- package/dist/runtime/backend/mesh-completion-table.js +160 -50
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
- package/dist/runtime/backend/mesh-dispatch-pump.js +53 -36
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
- package/dist/runtime/backend/node/node-backend-adapter-support.js +33 -31
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +50 -25
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +22 -16
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +133 -149
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +15 -10
- package/dist/runtime/backend/raw-binding-port.d.ts +10 -3
- package/dist/runtime/backend/runtime-message.d.ts +1 -0
- package/dist/runtime/backend/runtime-message.js +5 -0
- package/dist/runtime/backend/runtime-values.d.ts +1 -0
- package/dist/runtime/backend/runtime-values.js +2 -1
- package/dist/runtime/channels/channel-clients.d.ts +1 -0
- package/dist/runtime/channels/channel-clients.js +58 -21
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
- package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
- package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
- package/dist/runtime/channels/channel-dispatch-services.js +45 -0
- package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
- package/dist/runtime/channels/channel-dispatchers.js +27 -26
- package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
- package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
- package/dist/runtime/channels/channel-envelope.d.ts +1 -0
- package/dist/runtime/channels/channel-envelope.js +83 -8
- package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
- package/dist/runtime/channels/channel-outbound-operations.js +8 -8
- package/dist/runtime/channels/channel-receive-loops.js +3 -3
- package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
- package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
- package/dist/runtime/channels/channel-runtime-manager.js +12 -12
- package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
- package/dist/runtime/channels/channel-socket-registry.js +59 -82
- package/dist/runtime/channels/channel-transports.d.ts +18 -15
- package/dist/runtime/channels/channel-transports.js +48 -31
- package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.js +2 -1
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
- package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
- package/dist/runtime/channels/source-spot-router.d.ts +2 -2
- package/dist/runtime/channels/source-spot-router.js +4 -4
- package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-node-route-transport.js +4 -4
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
- package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
- package/dist/runtime/diagnostics/message-flow.js +3 -3
- package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
- package/dist/runtime/execution/serial-execution-queue.js +1 -0
- package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
- package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
- package/dist/runtime/foundation/durable-service-request.js +98 -0
- package/dist/runtime/foundation/operation-identity.d.ts +1 -0
- package/dist/runtime/foundation/operation-identity.js +5 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +37 -6
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +473 -220
- package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
- package/dist/runtime/foundation/service-liveness-registry.js +57 -44
- package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
- package/dist/runtime/foundation/service-mailbox.js +2 -1
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
- package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
- package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -9
- package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -7
- package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
- package/dist/runtime/foundation/service-topology-registry.d.ts +16 -4
- package/dist/runtime/foundation/service-topology-registry.js +69 -30
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
- package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
- package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
- package/dist/runtime/handlers/handler-instance-scope.js +54 -11
- package/dist/runtime/host/actor-packet-relay.js +7 -7
- package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
- package/dist/runtime/host/application-job-queue.d.ts +28 -9
- package/dist/runtime/host/application-job-queue.js +214 -50
- package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
- package/dist/runtime/host/entry-actor-runtime.js +4 -1
- package/dist/runtime/host/index.d.ts +7 -1
- package/dist/runtime/host/index.js +154 -126
- package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
- package/dist/runtime/host/instance-activation-authority.js +89 -25
- package/dist/runtime/host/remote-bound-session-relay.js +2 -18
- package/dist/runtime/host/route-mesh-runtime.js +1 -1
- package/dist/runtime/host/service-relocation-control.d.ts +1 -0
- package/dist/runtime/host/service-relocation-control.js +10 -4
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +215 -243
- package/dist/runtime/host/spot-address-transport.d.ts +1 -0
- package/dist/runtime/host/spot-address-transport.js +28 -14
- package/dist/runtime/host/spot-runtime-options-factory.js +3 -2
- package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
- package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
- package/dist/runtime/locations/actor-location-claims.js +34 -19
- package/dist/runtime/locations/domain-store-contract.d.ts +2 -2
- package/dist/runtime/locations/in-memory-authority-store.d.ts +4 -2
- package/dist/runtime/locations/in-memory-authority-store.js +80 -8
- package/dist/runtime/locations/in-memory-location-store.d.ts +2 -2
- package/dist/runtime/locations/in-memory-location-store.js +19 -3
- package/dist/runtime/locations/internal-location-contracts.d.ts +3 -0
- package/dist/runtime/locations/lifecycle.d.ts +1 -2
- package/dist/runtime/locations/lifecycle.js +2 -5
- package/dist/runtime/locations/location-store-repository.d.ts +3 -2
- package/dist/runtime/locations/location-store-repository.js +165 -22
- package/dist/runtime/locations/resolvers.d.ts +2 -1
- package/dist/runtime/locations/resolvers.js +10 -1
- package/dist/runtime/locations/runtime.d.ts +1 -1
- package/dist/runtime/locations/runtime.js +24 -23
- package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
- package/dist/runtime/messaging/framework-json-v1.js +38 -294
- package/dist/runtime/messaging/packet-name.d.ts +1 -1
- package/dist/runtime/messaging/packet-name.js +8 -24
- package/dist/runtime/messaging/request-result.d.ts +2 -0
- package/dist/runtime/messaging/request-result.js +54 -0
- package/dist/runtime/messaging/submission-result.d.ts +2 -1
- package/dist/runtime/messaging/submission-result.js +7 -4
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +9 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
- package/dist/runtime/spots/index.d.ts +7 -3
- package/dist/runtime/spots/index.js +23 -16
- package/dist/runtime/spots/spot-activation.d.ts +3 -1
- package/dist/runtime/spots/spot-activation.js +21 -12
- package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
- package/dist/runtime/spots/spot-entry-activation.js +9 -3
- package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
- package/dist/runtime/spots/spot-handler-registry.js +18 -8
- package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +2 -1
- package/dist/runtime/spots/spot-node-runtime-manager.js +4 -11
- package/dist/runtime/spots/spot-outbound.d.ts +3 -0
- package/dist/runtime/spots/spot-outbound.js +24 -15
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
- package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
- package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -1
- package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
- package/dist/runtime/spots/spot-timer.js +1 -0
- package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
- package/dist/runtime/streams/stream-session-runtime.js +14 -28
- package/package.json +3 -3
- package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
- package/src/contracts/Channels/Calls.ts +2 -1
- package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
- package/src/contracts/Configuration/Builders.ts +1 -2
- package/src/contracts/Configuration/Configs.ts +0 -6
- package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
- package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
- package/src/contracts/Configuration/index.ts +1 -6
- package/src/contracts/Handlers/Attributes.ts +14 -21
- package/src/contracts/Handlers/JsonContract.ts +8 -216
- package/src/contracts/Spots/Contracts.ts +2 -1
- package/src/internal.ts +1 -0
- package/src/nest-integration.ts +1 -0
- package/src/runtime/actors/actor-client.ts +40 -16
- package/src/runtime/actors/actor-handoff.ts +22 -8
- package/src/runtime/actors/actor-join-relocation.ts +1 -0
- package/src/runtime/actors/actor-local-native-join.ts +17 -26
- package/src/runtime/actors/actor-remote-wire.ts +17 -0
- package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
- package/src/runtime/actors/actor-routed-json-request.ts +10 -2
- package/src/runtime/actors/index.ts +19 -5
- package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
- package/src/runtime/admission.ts +18 -5
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +53 -27
- package/src/runtime/application-jobs/application-job-queue-scope.ts +56 -22
- package/src/runtime/application-jobs/contracts.ts +28 -2
- package/src/runtime/backend/contracts/index.ts +63 -32
- package/src/runtime/backend/mesh-completion-table.ts +175 -59
- package/src/runtime/backend/mesh-dispatch-pump.ts +59 -32
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
- package/src/runtime/backend/node/node-backend-adapter-support.ts +42 -31
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
- package/src/runtime/backend/node/node-raw-binding-port.ts +73 -37
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +209 -176
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +32 -13
- package/src/runtime/backend/raw-binding-port.ts +18 -3
- package/src/runtime/backend/runtime-message.ts +6 -0
- package/src/runtime/backend/runtime-values.ts +1 -0
- package/src/runtime/channels/channel-clients.ts +90 -41
- package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
- package/src/runtime/channels/channel-dispatch-services.ts +69 -1
- package/src/runtime/channels/channel-dispatchers.ts +29 -27
- package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
- package/src/runtime/channels/channel-envelope.ts +133 -8
- package/src/runtime/channels/channel-outbound-operations.ts +22 -8
- package/src/runtime/channels/channel-receive-loops.ts +3 -3
- package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
- package/src/runtime/channels/channel-runtime-manager.ts +29 -12
- package/src/runtime/channels/channel-socket-registry.ts +84 -130
- package/src/runtime/channels/channel-transports.ts +128 -60
- package/src/runtime/channels/local-spot-route-transport.ts +3 -1
- package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
- package/src/runtime/channels/source-spot-router.ts +8 -4
- package/src/runtime/channels/spot-node-route-transport.ts +8 -4
- package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
- package/src/runtime/diagnostics/message-flow.ts +1 -1
- package/src/runtime/execution/serial-execution-queue.ts +2 -0
- package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
- package/src/runtime/foundation/durable-service-request.ts +137 -0
- package/src/runtime/foundation/operation-identity.ts +5 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +642 -253
- package/src/runtime/foundation/service-liveness-registry.ts +68 -59
- package/src/runtime/foundation/service-mailbox.ts +7 -1
- package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
- package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
- package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +128 -160
- package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -84
- package/src/runtime/foundation/service-topology-registry.ts +103 -42
- package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
- package/src/runtime/handlers/handler-instance-scope.ts +67 -16
- package/src/runtime/host/actor-packet-relay.ts +7 -0
- package/src/runtime/host/actor-runtime-options-factory.ts +14 -2
- package/src/runtime/host/application-job-queue.ts +249 -48
- package/src/runtime/host/entry-actor-runtime.ts +5 -0
- package/src/runtime/host/index.ts +224 -160
- package/src/runtime/host/instance-activation-authority.ts +132 -27
- package/src/runtime/host/remote-bound-session-relay.ts +2 -23
- package/src/runtime/host/route-mesh-runtime.ts +1 -1
- package/src/runtime/host/service-relocation-control.ts +11 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +317 -291
- package/src/runtime/host/spot-address-transport.ts +49 -24
- package/src/runtime/host/spot-runtime-options-factory.ts +4 -0
- package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
- package/src/runtime/locations/actor-location-claims.ts +52 -30
- package/src/runtime/locations/domain-store-contract.ts +6 -2
- package/src/runtime/locations/in-memory-authority-store.ts +113 -9
- package/src/runtime/locations/in-memory-location-store.ts +25 -3
- package/src/runtime/locations/internal-location-contracts.ts +4 -0
- package/src/runtime/locations/lifecycle.ts +8 -26
- package/src/runtime/locations/location-store-repository.ts +220 -15
- package/src/runtime/locations/resolvers.ts +25 -2
- package/src/runtime/locations/runtime.ts +28 -24
- package/src/runtime/messaging/framework-json-v1.ts +5 -325
- package/src/runtime/messaging/packet-name.ts +5 -25
- package/src/runtime/messaging/request-result.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +7 -3
- package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +45 -23
- package/src/runtime/spots/index.ts +30 -2
- package/src/runtime/spots/spot-activation.ts +33 -10
- package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
- package/src/runtime/spots/spot-entry-activation.ts +12 -2
- package/src/runtime/spots/spot-handler-registry.ts +41 -8
- package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
- package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
- package/src/runtime/spots/spot-outbound.ts +36 -16
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
- package/src/runtime/spots/spot-routing-internal.ts +14 -0
- package/src/runtime/spots/spot-runtime-ports.ts +3 -0
- package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
- package/src/runtime/spots/spot-timer.ts +5 -1
- package/src/runtime/streams/stream-session-runtime.ts +13 -30
|
@@ -6,6 +6,7 @@ const application_ingress_record_owner_1 = require("../application-jobs/applicat
|
|
|
6
6
|
const submission_result_1 = require("../messaging/submission-result");
|
|
7
7
|
const runtime_values_1 = require("../backend/runtime-values");
|
|
8
8
|
const service_wire_codec_generated_1 = require("../protocol/service_wire_codec.generated");
|
|
9
|
+
const service_wire_binary_primitives_1 = require("./service-wire-binary-primitives");
|
|
9
10
|
const operation_registry_1 = require("./operation-registry");
|
|
10
11
|
const service_liveness_registry_1 = require("./service-liveness-registry");
|
|
11
12
|
const service_mailbox_1 = require("./service-mailbox");
|
|
@@ -17,6 +18,7 @@ const nativeErrnoValues = node_os_1.constants.errno;
|
|
|
17
18
|
// Framework error code 13 (RequestTargetNotFound) is encoded as 14 on a
|
|
18
19
|
// RequestResult.NotFound reply. Boundary transport results keep failureCode 0.
|
|
19
20
|
const RAW_MESH_RECEIVE_RECORD_BUDGET = 64;
|
|
21
|
+
const NODE_SEND_HEADER = (0, service_wire_m6a_codec_1.encodeNodeSendHeader)();
|
|
20
22
|
const RAW_MESH_RECEIVE_BYTE_BUDGET = 4 * 1024 * 1024;
|
|
21
23
|
exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS = 2;
|
|
22
24
|
const REQUEST_TARGET_NOT_FOUND_FAILURE_CODE = service_wire_constants_generated_1.ServiceWireFrameworkErrorCode.requestTargetNotFound;
|
|
@@ -37,6 +39,7 @@ class RawServiceMeshRuntime {
|
|
|
37
39
|
expectedPeers = new Map();
|
|
38
40
|
endpointOnlyPeers = new Set();
|
|
39
41
|
peerConnectionIntentRemoved = new Set();
|
|
42
|
+
peerRouteChanged = new Set();
|
|
40
43
|
/**
|
|
41
44
|
* The last observed Core selected route of each RID (Core ROUTER §10.1):
|
|
42
45
|
* RID -> route generation. Only `observeSelectedRoutes` replaces it.
|
|
@@ -44,8 +47,16 @@ class RawServiceMeshRuntime {
|
|
|
44
47
|
selectedRoutes = new Map();
|
|
45
48
|
bindingPort;
|
|
46
49
|
applicationJobQueue;
|
|
50
|
+
nodeMailboxOwner;
|
|
47
51
|
peerAdmissionSealed;
|
|
48
52
|
applicationJobStop = new AbortController();
|
|
53
|
+
receiveAcquisition;
|
|
54
|
+
receivePermit;
|
|
55
|
+
receiveRotation;
|
|
56
|
+
controlSends = new Map();
|
|
57
|
+
infrastructureFailure;
|
|
58
|
+
onReceiveReady;
|
|
59
|
+
infrastructureTaskRunner;
|
|
49
60
|
onPeerNotRequired;
|
|
50
61
|
onPeerDisconnected;
|
|
51
62
|
onProtocolError;
|
|
@@ -56,10 +67,14 @@ class RawServiceMeshRuntime {
|
|
|
56
67
|
router;
|
|
57
68
|
nextCorrelation = 1n;
|
|
58
69
|
serviceIngress;
|
|
70
|
+
serviceIngressAccepts;
|
|
59
71
|
closed = false;
|
|
60
72
|
constructor(options) {
|
|
73
|
+
this.onReceiveReady = options.onReceiveReady;
|
|
74
|
+
this.infrastructureTaskRunner = options.infrastructureTaskRunner;
|
|
61
75
|
this.operations = new operation_registry_1.OperationRegistry(undefined, options.onPendingOperationsChanged);
|
|
62
76
|
this.descriptor = options.descriptor;
|
|
77
|
+
this.nodeMailboxOwner = `node:${options.descriptor.nodeRoutingId}`;
|
|
63
78
|
this.topology = new service_topology_registry_1.ServiceTopologyRegistry(options.descriptor);
|
|
64
79
|
this.mailbox = new service_mailbox_1.ServiceMailbox(options.onMailboxReady);
|
|
65
80
|
this.liveness = new service_liveness_registry_1.ServiceLivenessRegistry(options.probeIntervalMs, options.peerTimeoutMs);
|
|
@@ -214,6 +229,30 @@ class RawServiceMeshRuntime {
|
|
|
214
229
|
this.peerConnectionIntentRemoved.delete(listener);
|
|
215
230
|
};
|
|
216
231
|
}
|
|
232
|
+
observePeerRoute(nodeRoutingId) {
|
|
233
|
+
const selected = this.selectedRoutes.get(nodeRoutingId);
|
|
234
|
+
const admitted = this.topology.admittedPeer(nodeRoutingId)?.liveness?.connectionId;
|
|
235
|
+
return {
|
|
236
|
+
generation: selected ?? (typeof admitted === 'bigint' ? admitted : undefined),
|
|
237
|
+
ready: admitted !== undefined && (selected === undefined || admitted === selected)
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
get requestStopSignal() {
|
|
241
|
+
return this.applicationJobStop.signal;
|
|
242
|
+
}
|
|
243
|
+
observePeerRouteChanged(listener) {
|
|
244
|
+
this.peerRouteChanged.add(listener);
|
|
245
|
+
return () => {
|
|
246
|
+
this.peerRouteChanged.delete(listener);
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
hasSelectedPeerRoute(nodeRoutingId) {
|
|
250
|
+
return this.selectedRoutes.has(nodeRoutingId);
|
|
251
|
+
}
|
|
252
|
+
notifyPeerRouteChanged(nodeRoutingId) {
|
|
253
|
+
for (const listener of this.peerRouteChanged)
|
|
254
|
+
listener(nodeRoutingId);
|
|
255
|
+
}
|
|
217
256
|
notifyPeerConnectionIntentRemoved(nodeRoutingId) {
|
|
218
257
|
// Only the logical owner's removal publishes lifecycle termination.
|
|
219
258
|
// A physical disconnect alone retains the connection expectation.
|
|
@@ -222,31 +261,35 @@ class RawServiceMeshRuntime {
|
|
|
222
261
|
for (const listener of this.peerConnectionIntentRemoved)
|
|
223
262
|
listener(nodeRoutingId);
|
|
224
263
|
}
|
|
225
|
-
|
|
226
|
-
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
264
|
+
announcePeer(nodeRoutingId) {
|
|
227
265
|
const generation = this.selectedRoutes.get(nodeRoutingId);
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this.
|
|
232
|
-
return
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
266
|
+
if (generation === undefined)
|
|
267
|
+
return Promise.resolve(false);
|
|
268
|
+
const current = () => {
|
|
269
|
+
const admission = this.topology.routeAdmission(nodeRoutingId);
|
|
270
|
+
return (this.selectedRoutes.get(nodeRoutingId) === generation &&
|
|
271
|
+
!(admission?.connectionId === routeConnectionId(generation) &&
|
|
272
|
+
admission.remoteAdmitReceived === true) &&
|
|
273
|
+
this.peerAdmissionSealed?.() !== true);
|
|
274
|
+
};
|
|
275
|
+
const key = controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
|
|
276
|
+
if (!current()) {
|
|
277
|
+
this.controlSends.delete(key);
|
|
278
|
+
return Promise.resolve(false);
|
|
279
|
+
}
|
|
280
|
+
const existing = this.controlSends.get(key);
|
|
281
|
+
const hello = existing?.current?.() === true
|
|
282
|
+
? existing.hello
|
|
283
|
+
: (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor());
|
|
284
|
+
return Promise.resolve(this.startControlSend(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, () => this.submitControl(nodeRoutingId, [hello]), current, hello));
|
|
241
285
|
}
|
|
242
286
|
isPeerRouteReady(nodeRoutingId, lifecycleGeneration) {
|
|
243
287
|
// Admission is bound to the observed selected route: the route observer
|
|
244
288
|
// removes the peer when that route ends or is replaced.
|
|
245
|
-
const peer = this.topology.
|
|
289
|
+
const peer = this.topology.admittedPeer(nodeRoutingId);
|
|
246
290
|
return (peer !== undefined &&
|
|
247
291
|
(lifecycleGeneration === undefined ||
|
|
248
|
-
peer.descriptor.lifecycleGeneration === lifecycleGeneration)
|
|
249
|
-
this.liveness.isReady(nodeRoutingId, peer.connectionId));
|
|
292
|
+
peer.descriptor.lifecycleGeneration === lifecycleGeneration));
|
|
250
293
|
}
|
|
251
294
|
async announceExpectedPeers() {
|
|
252
295
|
let accepted = 0;
|
|
@@ -280,22 +323,22 @@ class RawServiceMeshRuntime {
|
|
|
280
323
|
// placement and channel selectors therefore need the new mutable fields
|
|
281
324
|
// on that same connection before the next request is selected; waiting for
|
|
282
325
|
// a reconnect would leave a race where a drained node is selected again.
|
|
326
|
+
await this.publishLocalDescriptor(this.topology.peers().map((peer) => peer.descriptor.nodeRoutingId));
|
|
327
|
+
}
|
|
328
|
+
async publishLocalDescriptor(targets) {
|
|
283
329
|
const update = (0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.update, this.topology.localDescriptor());
|
|
284
|
-
for (const
|
|
285
|
-
await this.
|
|
330
|
+
for (const target of targets) {
|
|
331
|
+
await this.sendService(target, [update]);
|
|
286
332
|
}
|
|
287
333
|
}
|
|
288
334
|
replaceDiscoveredNotRequired(descriptors) {
|
|
289
335
|
this.topology.replaceDiscoveredNotRequired(descriptors);
|
|
290
336
|
}
|
|
291
337
|
isObjectClientNodeDirectTarget(nodeRoutingId) {
|
|
292
|
-
|
|
293
|
-
? this.topology.localDescriptor()
|
|
294
|
-
: this.topology.knownDescriptor(nodeRoutingId);
|
|
295
|
-
return descriptor?.objectRole === 'client';
|
|
338
|
+
return this.topology.isObjectClientNodeDirectTarget(nodeRoutingId);
|
|
296
339
|
}
|
|
297
|
-
|
|
298
|
-
return this.send(targetNodeRoutingId, [
|
|
340
|
+
sendToNode(targetNodeRoutingId, payload) {
|
|
341
|
+
return this.send(targetNodeRoutingId, [NODE_SEND_HEADER, this.applicationFrame(payload)]);
|
|
299
342
|
}
|
|
300
343
|
async sendToChannel(channelName, payload) {
|
|
301
344
|
const selection = this.selectChannelTarget(channelName);
|
|
@@ -310,17 +353,17 @@ class RawServiceMeshRuntime {
|
|
|
310
353
|
? runtime_values_1.SubmitResult.Ok
|
|
311
354
|
: runtime_values_1.SubmitResult.NotConnected;
|
|
312
355
|
}
|
|
313
|
-
requestToNode(targetNodeRoutingId, payload, timeoutMs) {
|
|
314
|
-
return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs);
|
|
356
|
+
requestToNode(targetNodeRoutingId, payload, timeoutMs, onAdmitted) {
|
|
357
|
+
return this.requestToTarget(targetNodeRoutingId, payload, timeoutMs, undefined, onAdmitted);
|
|
315
358
|
}
|
|
316
|
-
requestToChannel(channelName, payload, timeoutMs) {
|
|
359
|
+
requestToChannel(channelName, payload, timeoutMs, onAdmitted) {
|
|
317
360
|
const selection = this.selectChannelTarget(channelName);
|
|
318
361
|
if (selection.kind !== 'selected') {
|
|
319
362
|
const pending = this.operations.register(timeoutMs);
|
|
320
363
|
this.operations.complete(pending.id, selection.requestResult);
|
|
321
364
|
return pending;
|
|
322
365
|
}
|
|
323
|
-
return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName);
|
|
366
|
+
return this.requestToTarget(selection.peer.descriptor.nodeRoutingId, payload, timeoutMs, channelName, onAdmitted);
|
|
324
367
|
}
|
|
325
368
|
selectChannelTarget(channelName) {
|
|
326
369
|
const selected = this.topology.selectChannel(channelName, (peer) => this.isPeerRouteReady(peer.descriptor.nodeRoutingId));
|
|
@@ -341,24 +384,32 @@ class RawServiceMeshRuntime {
|
|
|
341
384
|
}
|
|
342
385
|
};
|
|
343
386
|
}
|
|
344
|
-
setServiceIngress(handler) {
|
|
387
|
+
setServiceIngress(handler, accepts) {
|
|
345
388
|
if (this.serviceIngress !== undefined && this.serviceIngress !== handler) {
|
|
346
389
|
throw new Error('Raw service ingress is already registered.');
|
|
347
390
|
}
|
|
348
391
|
this.serviceIngress = handler;
|
|
392
|
+
this.serviceIngressAccepts = accepts;
|
|
349
393
|
}
|
|
350
394
|
async reserveLocalIngress(signal) {
|
|
351
395
|
const waitSignal = signal === undefined
|
|
352
396
|
? this.applicationJobStop.signal
|
|
353
397
|
: AbortSignal.any([this.applicationJobStop.signal, signal]);
|
|
354
|
-
const permit = await this.applicationJobQueue.acquire(waitSignal);
|
|
398
|
+
const permit = await this.applicationJobQueue.acquire(waitSignal, 'local');
|
|
355
399
|
return application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, { close() { } });
|
|
356
400
|
}
|
|
357
401
|
async sendService(targetNodeRoutingId, parts) {
|
|
358
|
-
|
|
402
|
+
try {
|
|
403
|
+
await this.requireStarted().send(targetNodeRoutingId, parts);
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
return this.sendFailure(error);
|
|
408
|
+
}
|
|
359
409
|
}
|
|
360
|
-
requestService(targetNodeRoutingId, parts, timeoutMs) {
|
|
361
|
-
|
|
410
|
+
requestService(targetNodeRoutingId, parts, timeoutMs, onAdmitted) {
|
|
411
|
+
const admission = this.topology.admittedPeer(targetNodeRoutingId)?.liveness;
|
|
412
|
+
return this.requireStarted().request(targetNodeRoutingId, parts, timeoutMs, admission?.recordReceived, onAdmitted);
|
|
362
413
|
}
|
|
363
414
|
replyService(record, parts) {
|
|
364
415
|
if (record.requestSequence === undefined) {
|
|
@@ -383,6 +434,22 @@ class RawServiceMeshRuntime {
|
|
|
383
434
|
]);
|
|
384
435
|
}
|
|
385
436
|
async pumpOne(nowMs = performance.now(), observe) {
|
|
437
|
+
const result = await this.receiveOne(nowMs, observe);
|
|
438
|
+
const acquisition = this.receiveAcquisition;
|
|
439
|
+
if (acquisition === undefined)
|
|
440
|
+
return result;
|
|
441
|
+
// A single receive operation may await its FIFO grant. Infrastructure
|
|
442
|
+
// rounds use receiveOne directly and end while that grant is pending.
|
|
443
|
+
try {
|
|
444
|
+
await acquisition;
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
if (this.closed)
|
|
448
|
+
return 'noData';
|
|
449
|
+
throw error;
|
|
450
|
+
}
|
|
451
|
+
if (this.closed)
|
|
452
|
+
return 'noData';
|
|
386
453
|
return this.receiveOne(nowMs, observe);
|
|
387
454
|
}
|
|
388
455
|
setReadableHandler(handler) {
|
|
@@ -390,6 +457,7 @@ class RawServiceMeshRuntime {
|
|
|
390
457
|
}
|
|
391
458
|
/** Returns whether a receive budget ended before no-data; idle ticks only maintain peers. */
|
|
392
459
|
async pumpBatch(receiveReady = true, routeReady = false) {
|
|
460
|
+
this.observeInfrastructureFailure();
|
|
393
461
|
if (routeReady)
|
|
394
462
|
await this.observeSelectedRoutes();
|
|
395
463
|
const startedAtMs = performance.now();
|
|
@@ -398,38 +466,72 @@ class RawServiceMeshRuntime {
|
|
|
398
466
|
const observe = (_source, byteCount) => {
|
|
399
467
|
bytes += byteCount;
|
|
400
468
|
};
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
469
|
+
const rotation = (this.receiveRotation ??= this.applicationJobQueue.createReceiveRotation(RAW_MESH_RECEIVE_RECORD_BUDGET, 'remote'));
|
|
470
|
+
if (receiveReady)
|
|
471
|
+
rotation.reserve();
|
|
472
|
+
try {
|
|
473
|
+
while (receiveReady && messages < RAW_MESH_RECEIVE_RECORD_BUDGET && !this.closed) {
|
|
474
|
+
const received = this.receiveOne(performance.now(), observe, rotation);
|
|
475
|
+
const result = received instanceof Promise ? await received : received;
|
|
476
|
+
if (result === 'noData') {
|
|
477
|
+
receiveReady = false;
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
messages += 1;
|
|
481
|
+
// Core owns the per-peer fair-queue cursor. The Framework limit bounds
|
|
482
|
+
// the entire round, so changing peers does not renew its byte/count budget.
|
|
483
|
+
if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
|
|
484
|
+
performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
|
|
485
|
+
break;
|
|
406
486
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (bytes >= RAW_MESH_RECEIVE_BYTE_BUDGET ||
|
|
411
|
-
performance.now() - startedAtMs >= exports.RAW_MESH_RECEIVE_TIME_BUDGET_MS)
|
|
412
|
-
break;
|
|
487
|
+
}
|
|
488
|
+
finally {
|
|
489
|
+
rotation.releaseUnused();
|
|
413
490
|
}
|
|
414
491
|
if (!this.closed) {
|
|
415
|
-
|
|
416
|
-
await this.tickLiveness();
|
|
492
|
+
this.tickLiveness();
|
|
417
493
|
}
|
|
418
494
|
return receiveReady && messages > 0;
|
|
419
495
|
}
|
|
420
|
-
|
|
496
|
+
receiveOne(nowMs, observe, rotation) {
|
|
421
497
|
const router = this.requireStarted();
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
498
|
+
this.observeInfrastructureFailure();
|
|
499
|
+
let permit = this.receivePermit;
|
|
500
|
+
this.receivePermit = undefined;
|
|
501
|
+
permit ??= rotation?.take();
|
|
502
|
+
if (permit === undefined && this.receiveAcquisition === undefined) {
|
|
503
|
+
let resolveAcquisition;
|
|
504
|
+
let rejectAcquisition;
|
|
505
|
+
permit = this.applicationJobQueue.acquireOrResume((permit) => {
|
|
506
|
+
this.receiveAcquisition = undefined;
|
|
507
|
+
if (this.closed) {
|
|
508
|
+
permit.releaseAfterInternalProcessing();
|
|
509
|
+
permit.releaseStorage?.();
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
this.receivePermit = permit;
|
|
513
|
+
this.onReceiveReady?.();
|
|
514
|
+
}
|
|
515
|
+
resolveAcquisition?.(permit);
|
|
516
|
+
}, (error) => rejectAcquisition?.(error), this.applicationJobStop.signal, 'remote');
|
|
517
|
+
if (permit === undefined) {
|
|
518
|
+
const acquisition = new Promise((resolve, reject) => {
|
|
519
|
+
resolveAcquisition = resolve;
|
|
520
|
+
rejectAcquisition = reject;
|
|
521
|
+
});
|
|
522
|
+
this.receiveAcquisition = acquisition;
|
|
523
|
+
acquisition.catch((error) => {
|
|
524
|
+
this.receiveAcquisition = undefined;
|
|
525
|
+
if (!this.applicationJobStop.signal.aborted)
|
|
526
|
+
this.reportInfrastructureFailure(error);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
430
529
|
}
|
|
530
|
+
if (permit === undefined)
|
|
531
|
+
return 'noData';
|
|
431
532
|
if (this.closed) {
|
|
432
533
|
permit.releaseAfterInternalProcessing();
|
|
534
|
+
permit.releaseStorage?.();
|
|
433
535
|
return 'noData';
|
|
434
536
|
}
|
|
435
537
|
let received;
|
|
@@ -438,23 +540,44 @@ class RawServiceMeshRuntime {
|
|
|
438
540
|
}
|
|
439
541
|
catch (error) {
|
|
440
542
|
permit.releaseAfterInternalProcessing();
|
|
543
|
+
permit.releaseStorage?.();
|
|
441
544
|
throw error;
|
|
442
545
|
}
|
|
443
546
|
if (received === undefined) {
|
|
444
547
|
permit.releaseAfterInternalProcessing();
|
|
548
|
+
permit.releaseStorage?.();
|
|
445
549
|
return 'noData';
|
|
446
550
|
}
|
|
447
551
|
const applicationJobOwner = application_ingress_record_owner_1.ApplicationIngressRecordOwner.create(this.applicationJobQueue, permit, received);
|
|
552
|
+
let result;
|
|
553
|
+
try {
|
|
554
|
+
result = this.processReceived(received, nowMs, applicationJobOwner);
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
applicationJobOwner.close();
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
return result instanceof Promise
|
|
561
|
+
? result.then((value) => this.finishReceive(received, applicationJobOwner, observe, value), (error) => {
|
|
562
|
+
applicationJobOwner.close();
|
|
563
|
+
throw error;
|
|
564
|
+
})
|
|
565
|
+
: this.finishReceive(received, applicationJobOwner, observe, result);
|
|
566
|
+
}
|
|
567
|
+
finishReceive(received, owner, observe, result) {
|
|
448
568
|
try {
|
|
449
|
-
|
|
450
|
-
if (result === 'protocolError') {
|
|
569
|
+
if (result === 'protocolError')
|
|
451
570
|
this.reportProtocolError(received);
|
|
571
|
+
if (observe !== undefined) {
|
|
572
|
+
let bytes = 0;
|
|
573
|
+
for (const part of received.parts)
|
|
574
|
+
bytes += part.byteLength;
|
|
575
|
+
observe(received.sourceRid, bytes);
|
|
452
576
|
}
|
|
453
|
-
observe?.(received.sourceRid, received.parts.reduce((sum, part) => sum + part.byteLength, 0));
|
|
454
577
|
return result;
|
|
455
578
|
}
|
|
456
579
|
finally {
|
|
457
|
-
|
|
580
|
+
owner.close();
|
|
458
581
|
}
|
|
459
582
|
}
|
|
460
583
|
reportProtocolError(received) {
|
|
@@ -493,61 +616,19 @@ class RawServiceMeshRuntime {
|
|
|
493
616
|
throw error;
|
|
494
617
|
}
|
|
495
618
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return (await this.send(received.sourceRid, [
|
|
502
|
-
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.topology.localDescriptor())
|
|
503
|
-
]))
|
|
504
|
-
? 'infrastructure'
|
|
505
|
-
: 'dropped';
|
|
506
|
-
}
|
|
619
|
+
processReceived(received, nowMs, applicationJobOwner) {
|
|
620
|
+
const peer = this.topology.admittedPeer(received.sourceRid);
|
|
621
|
+
const currentSource = peer?.liveness !== undefined && peer.liveness.connectionId === received.routeGeneration;
|
|
622
|
+
if (received.parts.length === 0)
|
|
623
|
+
return currentSource ? 'protocolError' : 'dropped';
|
|
507
624
|
try {
|
|
508
625
|
const header = (0, service_wire_m6a_codec_1.decodeHeader)(received.parts[0]);
|
|
509
626
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello && this.peerAdmissionSealed?.() === true) {
|
|
510
627
|
return 'dropped';
|
|
511
628
|
}
|
|
512
629
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello ||
|
|
513
|
-
header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit
|
|
514
|
-
header.
|
|
515
|
-
if (received.parts.length !== 1)
|
|
516
|
-
return 'protocolError';
|
|
517
|
-
const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
|
|
518
|
-
const expected = this.expectedPeers.get(received.sourceRid);
|
|
519
|
-
if (expected !== undefined &&
|
|
520
|
-
(expected.meshName !== descriptor.meshName ||
|
|
521
|
-
expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
|
|
522
|
-
await this.send(received.sourceRid, [
|
|
523
|
-
(0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
|
|
524
|
-
]);
|
|
525
|
-
return 'infrastructure';
|
|
526
|
-
}
|
|
527
|
-
const result = this.admitPeer(descriptor, routeConnectionId(received.routeGeneration), nowMs, expected);
|
|
528
|
-
if (result !== 'admitted' && result !== 'notRequired') {
|
|
529
|
-
const detail = result === 'invalidDescriptor'
|
|
530
|
-
? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
|
|
531
|
-
: undefined;
|
|
532
|
-
console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
|
|
533
|
-
(detail === undefined ? '.' : ` (${detail}).`));
|
|
534
|
-
await this.send(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
|
|
535
|
-
return 'infrastructure';
|
|
536
|
-
}
|
|
537
|
-
if (result === 'admitted')
|
|
538
|
-
this.selectBilateralConnection(descriptor);
|
|
539
|
-
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
|
|
540
|
-
// Hello supplies only the sender's descriptor. Even NotRequired
|
|
541
|
-
// peers must receive ours before the intent owner closes transport;
|
|
542
|
-
// submitting a response does not guarantee delivery before close.
|
|
543
|
-
await this.send(received.sourceRid, [
|
|
544
|
-
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, this.topology.localDescriptor())
|
|
545
|
-
]);
|
|
546
|
-
}
|
|
547
|
-
else if (result === 'notRequired') {
|
|
548
|
-
this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
|
|
549
|
-
}
|
|
550
|
-
return 'infrastructure';
|
|
630
|
+
header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
|
|
631
|
+
return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
|
|
551
632
|
}
|
|
552
633
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.reject) {
|
|
553
634
|
if (received.parts.length !== 1)
|
|
@@ -555,45 +636,122 @@ class RawServiceMeshRuntime {
|
|
|
555
636
|
(0, service_wire_m6a_codec_1.decodeReject)(received.parts[0]);
|
|
556
637
|
return 'infrastructure';
|
|
557
638
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
639
|
+
if (!currentSource)
|
|
640
|
+
return 'dropped';
|
|
641
|
+
this.liveness.recordReceived(peer.liveness, nowMs);
|
|
642
|
+
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.update) {
|
|
643
|
+
return this.processAdmission(received, header, nowMs).catch((error) => this.receiveProtocolFailure(error));
|
|
644
|
+
}
|
|
561
645
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe ||
|
|
562
646
|
header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck) {
|
|
563
|
-
|
|
564
|
-
return 'protocolError';
|
|
565
|
-
const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
|
|
566
|
-
if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
|
|
567
|
-
const ack = this.liveness.acknowledgeProbe(received.sourceRid, peer.connectionId, record.probeId);
|
|
568
|
-
if (ack === undefined)
|
|
569
|
-
return 'protocolError';
|
|
570
|
-
const sent = await this.send(received.sourceRid, [
|
|
571
|
-
livenessCodec.encodeLivenessRecord({
|
|
572
|
-
command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
|
|
573
|
-
probeId: record.probeId
|
|
574
|
-
})
|
|
575
|
-
]);
|
|
576
|
-
if (!sent)
|
|
577
|
-
return 'dropped';
|
|
578
|
-
}
|
|
579
|
-
else {
|
|
580
|
-
this.liveness.acknowledge(received.sourceRid, peer.connectionId, record.probeId, nowMs);
|
|
581
|
-
}
|
|
582
|
-
return 'infrastructure';
|
|
647
|
+
return this.processLiveness(received, nowMs).catch((error) => this.receiveProtocolFailure(error));
|
|
583
648
|
}
|
|
584
|
-
const stateful =
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
649
|
+
const stateful = this.serviceIngress !== undefined && this.serviceIngressAccepts?.(header.command) !== false
|
|
650
|
+
? this.serviceIngress({
|
|
651
|
+
command: header.command,
|
|
652
|
+
flags: header.flags,
|
|
653
|
+
sourceRoutingId: received.sourceRid,
|
|
654
|
+
sourceNodeGeneration: peer.descriptor.lifecycleGeneration,
|
|
655
|
+
sourceRoute: received.sourceRoute,
|
|
656
|
+
...(received.reply === undefined ? {} : { reply: received.reply }),
|
|
657
|
+
...(received.requestSeq === undefined
|
|
658
|
+
? {}
|
|
659
|
+
: { requestSequence: received.requestSeq }),
|
|
660
|
+
parts: received.parts,
|
|
661
|
+
applicationJobOwner
|
|
662
|
+
})
|
|
663
|
+
: undefined;
|
|
664
|
+
if (stateful instanceof Promise)
|
|
665
|
+
return stateful.then((result) => result ?? this.processApplicationReceived(received, header, applicationJobOwner), (error) => this.receiveProtocolFailure(error));
|
|
595
666
|
if (stateful !== undefined)
|
|
596
667
|
return stateful;
|
|
668
|
+
return this.processApplicationReceived(received, header, applicationJobOwner);
|
|
669
|
+
}
|
|
670
|
+
catch (error) {
|
|
671
|
+
if (!currentSource && error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
|
|
672
|
+
return 'dropped';
|
|
673
|
+
return this.receiveProtocolFailure(error);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
receiveProtocolFailure(error) {
|
|
677
|
+
if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
|
|
678
|
+
return 'protocolError';
|
|
679
|
+
throw error;
|
|
680
|
+
}
|
|
681
|
+
async processAdmission(received, header, nowMs) {
|
|
682
|
+
if (received.parts.length !== 1)
|
|
683
|
+
return 'protocolError';
|
|
684
|
+
const descriptor = (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(received.parts[0], header.command, received.sourceRid);
|
|
685
|
+
const expected = this.expectedPeers.get(received.sourceRid);
|
|
686
|
+
if (expected !== undefined &&
|
|
687
|
+
(expected.meshName !== descriptor.meshName ||
|
|
688
|
+
expected.nodeRoutingId !== descriptor.nodeRoutingId)) {
|
|
689
|
+
await this.sendControl(received.sourceRid, [
|
|
690
|
+
(0, service_wire_m6a_codec_1.encodeReject)((0, service_wire_codec_generated_1.enumWireRejectReason)('identityMismatch'))
|
|
691
|
+
]);
|
|
692
|
+
return 'infrastructure';
|
|
693
|
+
}
|
|
694
|
+
const helloKey = controlSendKey(received.sourceRid, service_wire_m6a_codec_1.M6aServiceWireCommand.hello);
|
|
695
|
+
const exchange = this.controlSends.get(helloKey);
|
|
696
|
+
const result = this.admitPeer(descriptor, received.routeGeneration, nowMs, expected, header.command, received.parts[0].subarray(service_wire_binary_primitives_1.SERVICE_WIRE_PREFIX_SIZE));
|
|
697
|
+
if (result !== 'admitted' && result !== 'notRequired') {
|
|
698
|
+
const detail = result === 'invalidDescriptor'
|
|
699
|
+
? describeInvalidAdmissionDescriptor(descriptor, expected, this.topology.peer(descriptor.nodeRoutingId)?.descriptor)
|
|
700
|
+
: undefined;
|
|
701
|
+
console.warn(`RouteMesh admission rejected peer '${received.sourceRid}' as ${result}` +
|
|
702
|
+
(detail === undefined ? '.' : ` (${detail}).`));
|
|
703
|
+
await this.sendControl(received.sourceRid, [(0, service_wire_m6a_codec_1.encodeReject)(admissionReason(result))]);
|
|
704
|
+
return 'infrastructure';
|
|
705
|
+
}
|
|
706
|
+
if (result === 'admitted')
|
|
707
|
+
this.selectBilateralConnection(descriptor);
|
|
708
|
+
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
|
|
709
|
+
// Hello supplies only the sender's descriptor. Even NotRequired
|
|
710
|
+
// peers must receive ours before the intent owner closes transport;
|
|
711
|
+
// submitting a response does not guarantee delivery before close.
|
|
712
|
+
const local = exchange?.current?.() === true && exchange.hello !== undefined
|
|
713
|
+
? (0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId)
|
|
714
|
+
: this.topology.localDescriptor();
|
|
715
|
+
await this.sendControl(received.sourceRid, [
|
|
716
|
+
(0, service_wire_m6a_codec_1.encodeRouteMeshAdmission)(service_wire_m6a_codec_1.M6aServiceWireCommand.admit, local)
|
|
717
|
+
]);
|
|
718
|
+
}
|
|
719
|
+
else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.admit) {
|
|
720
|
+
this.controlSends.delete(helloKey);
|
|
721
|
+
if (result === 'notRequired') {
|
|
722
|
+
this.retireNotRequiredExpectedPeer(received.sourceRid, descriptor.advertisedEndpoint);
|
|
723
|
+
}
|
|
724
|
+
else if (exchange?.hello !== undefined &&
|
|
725
|
+
(0, service_wire_m6a_codec_1.decodeRouteMeshAdmission)(exchange.hello, service_wire_m6a_codec_1.M6aServiceWireCommand.hello, this.descriptor.nodeRoutingId).descriptorRevision < this.descriptor.descriptorRevision) {
|
|
726
|
+
await this.publishLocalDescriptor([received.sourceRid]);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return 'infrastructure';
|
|
730
|
+
}
|
|
731
|
+
async processLiveness(received, nowMs) {
|
|
732
|
+
if (received.parts.length !== 1)
|
|
733
|
+
return 'protocolError';
|
|
734
|
+
const record = livenessCodec.decodeLivenessRecord(received.parts[0]);
|
|
735
|
+
if (record.command === service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe) {
|
|
736
|
+
const ack = this.liveness.acknowledgeProbe(received.sourceRid, received.routeGeneration, record.probeId);
|
|
737
|
+
if (ack === undefined)
|
|
738
|
+
return 'protocolError';
|
|
739
|
+
const sent = await this.sendControl(received.sourceRid, [
|
|
740
|
+
livenessCodec.encodeLivenessRecord({
|
|
741
|
+
command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessAck,
|
|
742
|
+
probeId: record.probeId
|
|
743
|
+
})
|
|
744
|
+
]);
|
|
745
|
+
if (!sent)
|
|
746
|
+
return 'dropped';
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
this.liveness.acknowledge(received.sourceRid, received.routeGeneration, record.probeId, nowMs);
|
|
750
|
+
}
|
|
751
|
+
return 'infrastructure';
|
|
752
|
+
}
|
|
753
|
+
processApplicationReceived(received, header, applicationJobOwner) {
|
|
754
|
+
try {
|
|
597
755
|
if (header.flags === 0 &&
|
|
598
756
|
// A bare infrastructure control is normally exactly one frame, but a
|
|
599
757
|
// relocation Prepare now rides its bound-session journal as
|
|
@@ -609,7 +767,7 @@ class RawServiceMeshRuntime {
|
|
|
609
767
|
received.parts.length >= 1 &&
|
|
610
768
|
isBareInfrastructureControl(header.command)) {
|
|
611
769
|
const accepted = this.mailbox.tryEnqueue({
|
|
612
|
-
owner:
|
|
770
|
+
owner: this.nodeMailboxOwner,
|
|
613
771
|
domain: 'infrastructure',
|
|
614
772
|
parts: received.parts,
|
|
615
773
|
sourceRoutingId: received.sourceRid,
|
|
@@ -632,51 +790,54 @@ class RawServiceMeshRuntime {
|
|
|
632
790
|
let owner;
|
|
633
791
|
let correlation;
|
|
634
792
|
if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeSend) {
|
|
635
|
-
owner =
|
|
793
|
+
owner = this.nodeMailboxOwner;
|
|
636
794
|
}
|
|
637
795
|
else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.nodeRequest) {
|
|
638
|
-
owner =
|
|
639
|
-
correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0]);
|
|
796
|
+
owner = this.nodeMailboxOwner;
|
|
797
|
+
correlation = (0, service_wire_m6a_codec_1.decodeNodeRequestHeader)(received.parts[0], header);
|
|
640
798
|
}
|
|
641
799
|
else if (header.command === service_wire_m6a_codec_1.M6aServiceWireCommand.channelSend) {
|
|
642
|
-
owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0])}`;
|
|
800
|
+
owner = `channel:${(0, service_wire_m6a_codec_1.decodeChannelSendHeader)(received.parts[0], header)}`;
|
|
643
801
|
}
|
|
644
802
|
else {
|
|
645
|
-
const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0]);
|
|
803
|
+
const channel = (0, service_wire_m6a_codec_1.decodeChannelRequestHeader)(received.parts[0], header);
|
|
646
804
|
owner = `channel:${channel.channelName}`;
|
|
647
805
|
correlation = channel.correlation;
|
|
648
806
|
}
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
owner,
|
|
652
|
-
|
|
653
|
-
|
|
807
|
+
const job = applicationJobOwner.acquire('application');
|
|
808
|
+
return job instanceof Promise
|
|
809
|
+
? job.then((permit) => this.enqueueOrdinaryRecord(received, owner, correlation, permit))
|
|
810
|
+
: this.enqueueOrdinaryRecord(received, owner, correlation, job);
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
return this.receiveProtocolFailure(error);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
enqueueOrdinaryRecord(received, owner, correlation, applicationJob) {
|
|
817
|
+
const accepted = this.mailbox.tryEnqueue({
|
|
818
|
+
owner,
|
|
819
|
+
domain: 'application',
|
|
820
|
+
parts: received.parts,
|
|
821
|
+
sourceRoutingId: received.sourceRid,
|
|
822
|
+
sourceRoute: received.sourceRoute,
|
|
823
|
+
...(received.reply === undefined ? {} : { reply: received.reply }),
|
|
824
|
+
requestSequence: received.requestSeq,
|
|
825
|
+
...(correlation === undefined ? {} : { correlation }),
|
|
826
|
+
applicationJob
|
|
827
|
+
});
|
|
828
|
+
if (accepted)
|
|
829
|
+
return 'application';
|
|
830
|
+
applicationJob.close();
|
|
831
|
+
if (correlation !== undefined && received.requestSeq !== undefined) {
|
|
832
|
+
this.replyService({
|
|
654
833
|
sourceRoutingId: received.sourceRid,
|
|
655
834
|
sourceRoute: received.sourceRoute,
|
|
656
|
-
...(received.reply === undefined ? {} : { reply: received.reply }),
|
|
657
835
|
requestSequence: received.requestSeq,
|
|
658
|
-
...(
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (accepted)
|
|
662
|
-
return 'application';
|
|
663
|
-
applicationJob.close();
|
|
664
|
-
if (correlation !== undefined && received.requestSeq !== undefined) {
|
|
665
|
-
this.replyService({
|
|
666
|
-
sourceRoutingId: received.sourceRid,
|
|
667
|
-
sourceRoute: received.sourceRoute,
|
|
668
|
-
requestSequence: received.requestSeq,
|
|
669
|
-
...(received.reply === undefined ? {} : { reply: received.reply })
|
|
670
|
-
}, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
|
|
671
|
-
return 'infrastructure';
|
|
672
|
-
}
|
|
673
|
-
return 'dropped';
|
|
674
|
-
}
|
|
675
|
-
catch (error) {
|
|
676
|
-
if (error instanceof service_wire_m6a_codec_1.ServiceWireProtocolError)
|
|
677
|
-
return 'protocolError';
|
|
678
|
-
throw error;
|
|
836
|
+
...(received.reply === undefined ? {} : { reply: received.reply })
|
|
837
|
+
}, [(0, service_wire_m6a_codec_1.encodeReplyHeader)(correlation, runtime_values_1.RequestResult.NotConnected, 0)]);
|
|
838
|
+
return 'infrastructure';
|
|
679
839
|
}
|
|
840
|
+
return 'dropped';
|
|
680
841
|
}
|
|
681
842
|
expireOperations(nowMs, turnDeadlineMs) {
|
|
682
843
|
return this.operations.expire(nowMs, turnDeadlineMs);
|
|
@@ -684,22 +845,25 @@ class RawServiceMeshRuntime {
|
|
|
684
845
|
get pendingOperationCount() {
|
|
685
846
|
return this.operations.size;
|
|
686
847
|
}
|
|
687
|
-
|
|
848
|
+
tickLiveness(nowMs = performance.now()) {
|
|
688
849
|
const result = this.liveness.tick(nowMs);
|
|
689
850
|
this.requireStarted();
|
|
851
|
+
for (const nodeRoutingId of this.selectedRoutes.keys())
|
|
852
|
+
void this.announcePeer(nodeRoutingId);
|
|
690
853
|
for (const probe of result.probes) {
|
|
691
|
-
|
|
854
|
+
const parts = [
|
|
692
855
|
livenessCodec.encodeLivenessRecord({
|
|
693
856
|
command: service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe,
|
|
694
857
|
probeId: probe.probeId
|
|
695
858
|
})
|
|
696
|
-
]
|
|
859
|
+
];
|
|
860
|
+
this.startControlSend(probe.nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.livenessProbe, () => this.submitControl(probe.nodeRoutingId, parts));
|
|
697
861
|
}
|
|
698
862
|
for (const nodeRoutingId of result.timedOutNodes) {
|
|
699
863
|
const peer = this.topology.peer(nodeRoutingId);
|
|
700
864
|
if (peer === undefined)
|
|
701
865
|
continue;
|
|
702
|
-
|
|
866
|
+
this.requireStarted().disconnectRid(nodeRoutingId);
|
|
703
867
|
this.removePeer(peer);
|
|
704
868
|
}
|
|
705
869
|
return result;
|
|
@@ -722,12 +886,10 @@ class RawServiceMeshRuntime {
|
|
|
722
886
|
for (const [nodeRoutingId, generation] of this.selectedRoutes) {
|
|
723
887
|
if (observed.get(nodeRoutingId) === generation)
|
|
724
888
|
continue;
|
|
889
|
+
this.controlSends.delete(controlSendKey(nodeRoutingId, service_wire_m6a_codec_1.M6aServiceWireCommand.hello));
|
|
725
890
|
changes++;
|
|
726
|
-
const expected = this.expectedPeers.get(nodeRoutingId);
|
|
727
|
-
if (expected !== undefined)
|
|
728
|
-
delete expected.helloSubmittedGeneration;
|
|
729
891
|
const peer = this.topology.peer(nodeRoutingId);
|
|
730
|
-
if (peer
|
|
892
|
+
if (peer?.liveness?.connectionId === generation) {
|
|
731
893
|
this.removePeer(peer);
|
|
732
894
|
}
|
|
733
895
|
}
|
|
@@ -740,6 +902,8 @@ class RawServiceMeshRuntime {
|
|
|
740
902
|
selected.push(nodeRoutingId);
|
|
741
903
|
}
|
|
742
904
|
this.selectedRoutes = observed;
|
|
905
|
+
for (const nodeRoutingId of selected)
|
|
906
|
+
this.notifyPeerRouteChanged(nodeRoutingId);
|
|
743
907
|
// A new selected route admits only through a new handshake.
|
|
744
908
|
for (const nodeRoutingId of selected)
|
|
745
909
|
await this.announcePeer(nodeRoutingId);
|
|
@@ -748,7 +912,14 @@ class RawServiceMeshRuntime {
|
|
|
748
912
|
close() {
|
|
749
913
|
if (this.closed)
|
|
750
914
|
return;
|
|
915
|
+
this.closed = true;
|
|
751
916
|
this.applicationJobStop.abort(new Error('Raw service runtime application job admission stopped.'));
|
|
917
|
+
this.receivePermit?.releaseAfterInternalProcessing();
|
|
918
|
+
this.receivePermit?.releaseStorage?.();
|
|
919
|
+
this.receivePermit = undefined;
|
|
920
|
+
for (const send of this.controlSends.values())
|
|
921
|
+
delete send.next;
|
|
922
|
+
this.controlSends.clear();
|
|
752
923
|
this.mailbox.close();
|
|
753
924
|
this.operations.close('Raw service runtime closed.');
|
|
754
925
|
this.serviceIngress = undefined;
|
|
@@ -761,9 +932,8 @@ class RawServiceMeshRuntime {
|
|
|
761
932
|
host.close();
|
|
762
933
|
this.router = undefined;
|
|
763
934
|
this.host = undefined;
|
|
764
|
-
this.closed = true;
|
|
765
935
|
}
|
|
766
|
-
requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName) {
|
|
936
|
+
requestToTarget(targetNodeRoutingId, payload, timeoutMs, channelName, onAdmitted) {
|
|
767
937
|
const correlation = this.nextCorrelation++;
|
|
768
938
|
const header = channelName === undefined
|
|
769
939
|
? (0, service_wire_m6a_codec_1.encodeNodeRequestHeader)(correlation)
|
|
@@ -829,6 +999,9 @@ class RawServiceMeshRuntime {
|
|
|
829
999
|
failureCode: 0
|
|
830
1000
|
});
|
|
831
1001
|
}
|
|
1002
|
+
else {
|
|
1003
|
+
onAdmitted?.();
|
|
1004
|
+
}
|
|
832
1005
|
}
|
|
833
1006
|
finally {
|
|
834
1007
|
applicationJobOwner.close();
|
|
@@ -836,7 +1009,8 @@ class RawServiceMeshRuntime {
|
|
|
836
1009
|
})().catch((error) => this.operations.fail(pending.id, error));
|
|
837
1010
|
return pending;
|
|
838
1011
|
}
|
|
839
|
-
|
|
1012
|
+
const selectedPeer = this.topology.admittedPeer(selectedTargetNodeRoutingId);
|
|
1013
|
+
if (selectedPeer === undefined) {
|
|
840
1014
|
// Logical target selection is the requester's decision: an RID that is
|
|
841
1015
|
// not an admitted peer is not a target. Whether an admitted target's
|
|
842
1016
|
// route can carry the request is Core's REQUEST result.
|
|
@@ -847,11 +1021,9 @@ class RawServiceMeshRuntime {
|
|
|
847
1021
|
return pending;
|
|
848
1022
|
}
|
|
849
1023
|
const parts = [header, encodedPayload];
|
|
850
|
-
let router;
|
|
851
1024
|
let request;
|
|
852
1025
|
try {
|
|
853
|
-
|
|
854
|
-
request = router.request(selectedTargetNodeRoutingId, parts, timeoutMs);
|
|
1026
|
+
request = this.requireStarted().request(selectedTargetNodeRoutingId, parts, timeoutMs, selectedPeer.liveness?.recordReceived, onAdmitted);
|
|
855
1027
|
}
|
|
856
1028
|
catch (error) {
|
|
857
1029
|
this.operations.fail(pending.id, error);
|
|
@@ -900,23 +1072,22 @@ class RawServiceMeshRuntime {
|
|
|
900
1072
|
applicationPayload(payload) {
|
|
901
1073
|
return Buffer.isBuffer(payload) ? (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payload) : payload;
|
|
902
1074
|
}
|
|
903
|
-
admitPeer(descriptor, connectionId, nowMs, expected) {
|
|
1075
|
+
admitPeer(descriptor, connectionId, nowMs, expected, command = service_wire_m6a_codec_1.M6aServiceWireCommand.hello, descriptorBytes) {
|
|
904
1076
|
const previous = this.topology.peer(descriptor.nodeRoutingId);
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1077
|
+
const topologyConnectionId = typeof connectionId === 'bigint' ? routeConnectionId(connectionId) : connectionId;
|
|
1078
|
+
const result = this.topology.admit(descriptor, topologyConnectionId, expected, () => {
|
|
1079
|
+
const admission = this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
1080
|
+
this.liveness.recordReceived(admission, nowMs);
|
|
1081
|
+
return admission;
|
|
1082
|
+
}, command, descriptorBytes);
|
|
1083
|
+
if (result === 'staleDescriptor') {
|
|
910
1084
|
throw new service_wire_m6a_codec_1.ServiceWireProtocolError(`RouteMesh peer '${descriptor.nodeRoutingId}' descriptor revision is stale or conflicting.`);
|
|
911
1085
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
this.liveness.admit(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
915
|
-
this.liveness.requestProbe(descriptor.nodeRoutingId, connectionId, nowMs);
|
|
916
|
-
}
|
|
917
|
-
else if (result === 'notRequired' && previous !== undefined) {
|
|
918
|
-
this.liveness.disconnect(descriptor.nodeRoutingId, previous.connectionId);
|
|
1086
|
+
if (result === 'notRequired' && previous !== undefined) {
|
|
1087
|
+
this.liveness.disconnect(descriptor.nodeRoutingId, previous.liveness?.connectionId ?? previous.connectionId);
|
|
919
1088
|
}
|
|
1089
|
+
if (result === 'admitted')
|
|
1090
|
+
this.notifyPeerRouteChanged(descriptor.nodeRoutingId);
|
|
920
1091
|
return result;
|
|
921
1092
|
}
|
|
922
1093
|
retireNotRequiredExpectedPeer(nodeRoutingId, advertisedEndpoint) {
|
|
@@ -950,7 +1121,7 @@ class RawServiceMeshRuntime {
|
|
|
950
1121
|
}
|
|
951
1122
|
removePeer(peer) {
|
|
952
1123
|
this.topology.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
953
|
-
this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.connectionId);
|
|
1124
|
+
this.liveness.disconnect(peer.descriptor.nodeRoutingId, peer.liveness?.connectionId ?? peer.connectionId);
|
|
954
1125
|
this.onPeerDisconnected?.(peer.descriptor.nodeRoutingId, peer.descriptor.advertisedEndpoint, peer.descriptor.lifecycleGeneration);
|
|
955
1126
|
}
|
|
956
1127
|
requireStarted() {
|
|
@@ -958,22 +1129,111 @@ class RawServiceMeshRuntime {
|
|
|
958
1129
|
throw new Error('Raw service runtime is not started.');
|
|
959
1130
|
return this.router;
|
|
960
1131
|
}
|
|
961
|
-
async
|
|
1132
|
+
async sendControl(targetNodeRoutingId, parts) {
|
|
1133
|
+
return this.startControlSend(targetNodeRoutingId, (0, service_wire_m6a_codec_1.decodeHeader)(parts[0]).command, () => this.submitControl(targetNodeRoutingId, parts));
|
|
1134
|
+
}
|
|
1135
|
+
submitControl(target, parts) {
|
|
1136
|
+
let submission;
|
|
962
1137
|
try {
|
|
963
|
-
|
|
964
|
-
return true;
|
|
1138
|
+
submission = this.requireStarted().submitSend(target, parts);
|
|
965
1139
|
}
|
|
966
1140
|
catch (error) {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1141
|
+
return this.sendFailure(error);
|
|
1142
|
+
}
|
|
1143
|
+
if (submission.result === runtime_values_1.SubmitResult.Ok)
|
|
1144
|
+
return true;
|
|
1145
|
+
return submission.admitted.then(() => true, (error) => this.sendFailure(error));
|
|
1146
|
+
}
|
|
1147
|
+
startControlSend(target, command, attempt, current, hello) {
|
|
1148
|
+
const key = controlSendKey(target, command);
|
|
1149
|
+
const existing = this.controlSends.get(key);
|
|
1150
|
+
if (existing !== undefined &&
|
|
1151
|
+
existing.task !== undefined &&
|
|
1152
|
+
(command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello || existing.current?.() === true)) {
|
|
1153
|
+
if (command !== service_wire_m6a_codec_1.M6aServiceWireCommand.hello) {
|
|
1154
|
+
existing.next = attempt;
|
|
1155
|
+
existing.current = current;
|
|
971
1156
|
}
|
|
972
|
-
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
const first = attempt();
|
|
1160
|
+
if (typeof first === 'boolean') {
|
|
1161
|
+
if (hello !== undefined)
|
|
1162
|
+
this.controlSends.set(key, { current, hello });
|
|
1163
|
+
return first;
|
|
1164
|
+
}
|
|
1165
|
+
const owner = this;
|
|
1166
|
+
const state = { current, hello };
|
|
1167
|
+
const completeSend = () => {
|
|
1168
|
+
if (owner.controlSends.get(key) !== state)
|
|
1169
|
+
return;
|
|
1170
|
+
if (hello !== undefined && current?.() === true)
|
|
1171
|
+
delete state.task;
|
|
1172
|
+
else
|
|
1173
|
+
owner.controlSends.delete(key);
|
|
1174
|
+
};
|
|
1175
|
+
const task = first.then(function drain(accepted) {
|
|
1176
|
+
if (!owner.closed && state.next !== undefined) {
|
|
1177
|
+
const next = state.next;
|
|
1178
|
+
delete state.next;
|
|
1179
|
+
return Promise.resolve(next()).then(drain);
|
|
1180
|
+
}
|
|
1181
|
+
completeSend();
|
|
1182
|
+
return accepted;
|
|
1183
|
+
});
|
|
1184
|
+
state.task = task;
|
|
1185
|
+
this.controlSends.set(key, state);
|
|
1186
|
+
task.then(() => { }, (error) => {
|
|
1187
|
+
completeSend();
|
|
1188
|
+
if (this.infrastructureTaskRunner === undefined)
|
|
1189
|
+
this.reportInfrastructureFailure(error);
|
|
1190
|
+
});
|
|
1191
|
+
this.infrastructureTaskRunner?.runDetached('RouteMesh control SEND', async () => {
|
|
1192
|
+
await task;
|
|
1193
|
+
});
|
|
1194
|
+
return true;
|
|
1195
|
+
}
|
|
1196
|
+
reportInfrastructureFailure(error) {
|
|
1197
|
+
this.infrastructureFailure = {
|
|
1198
|
+
error: this.infrastructureFailure === undefined
|
|
1199
|
+
? error
|
|
1200
|
+
: new AggregateError([this.infrastructureFailure.error, error], 'RouteMesh infrastructure failed.')
|
|
1201
|
+
};
|
|
1202
|
+
this.onReceiveReady?.();
|
|
1203
|
+
}
|
|
1204
|
+
observeInfrastructureFailure() {
|
|
1205
|
+
const failure = this.infrastructureFailure;
|
|
1206
|
+
this.infrastructureFailure = undefined;
|
|
1207
|
+
if (failure !== undefined)
|
|
1208
|
+
throw failure.error;
|
|
1209
|
+
}
|
|
1210
|
+
send(targetNodeRoutingId, parts) {
|
|
1211
|
+
try {
|
|
1212
|
+
const submission = this.requireStarted().submitSend(targetNodeRoutingId, parts);
|
|
1213
|
+
if (submission.result === runtime_values_1.SubmitResult.Ok)
|
|
1214
|
+
return true;
|
|
1215
|
+
return submission.admitted.then(() => true, (error) => this.sendFailure(error));
|
|
973
1216
|
}
|
|
1217
|
+
catch (error) {
|
|
1218
|
+
return this.sendFailure(error);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
sendFailure(error) {
|
|
1222
|
+
if ((0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'submit') {
|
|
1223
|
+
const terminal = (0, submission_result_1.submitToRequestResult)(error.result, error.phase);
|
|
1224
|
+
if (terminal === runtime_values_1.RequestResult.NotConnected || terminal === runtime_values_1.RequestResult.NotFound)
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
throw error;
|
|
974
1228
|
}
|
|
975
1229
|
}
|
|
976
1230
|
exports.RawServiceMeshRuntime = RawServiceMeshRuntime;
|
|
1231
|
+
function controlSendKey(target, command) {
|
|
1232
|
+
return JSON.stringify([target, command]);
|
|
1233
|
+
}
|
|
1234
|
+
function routeConnectionId(generation) {
|
|
1235
|
+
return `route:${generation}`;
|
|
1236
|
+
}
|
|
977
1237
|
/**
|
|
978
1238
|
* Relocation and bound-Session controls are service-wire records themselves,
|
|
979
1239
|
* not application NodeSend(16) envelopes. Keep this list closed: a bare
|
|
@@ -1010,13 +1270,6 @@ function isAlreadyDisconnectedError(error) {
|
|
|
1010
1270
|
}
|
|
1011
1271
|
return error.nativeErrno === nativeErrnoValues.ENOENT;
|
|
1012
1272
|
}
|
|
1013
|
-
/**
|
|
1014
|
-
* An admission belongs to one Core selected route. Its connection identity is
|
|
1015
|
-
* that route's generation, an opaque token compared only for equality.
|
|
1016
|
-
*/
|
|
1017
|
-
function routeConnectionId(routeGeneration) {
|
|
1018
|
-
return `route:${routeGeneration.toString()}`;
|
|
1019
|
-
}
|
|
1020
1273
|
function describeInvalidAdmissionDescriptor(descriptor, expected, current) {
|
|
1021
1274
|
try {
|
|
1022
1275
|
(0, service_topology_registry_1.validateDescriptor)(descriptor);
|