@zlink-systems/framework 0.24.0 → 0.26.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.
Files changed (215) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
  3. package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
  4. package/dist/internal.d.ts +1 -0
  5. package/dist/internal.js +1 -0
  6. package/dist/runtime/activation-admission.d.ts +29 -0
  7. package/dist/runtime/activation-admission.js +61 -0
  8. package/dist/runtime/actors/actor-context.js +6 -6
  9. package/dist/runtime/actors/actor-handoff.d.ts +9 -3
  10. package/dist/runtime/actors/actor-handoff.js +28 -17
  11. package/dist/runtime/actors/actor-local-native-join.js +2 -18
  12. package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
  13. package/dist/runtime/actors/actor-remote-joiner.js +6 -8
  14. package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
  15. package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
  16. package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
  17. package/dist/runtime/actors/deferred-join-completion.js +20 -0
  18. package/dist/runtime/actors/index.d.ts +1 -1
  19. package/dist/runtime/actors/index.js +15 -5
  20. package/dist/runtime/admission.d.ts +5 -1
  21. package/dist/runtime/admission.js +4 -0
  22. package/dist/runtime/backend/contracts/index.d.ts +2 -10
  23. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
  24. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
  25. package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
  26. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
  27. package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
  28. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
  29. package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
  31. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
  33. package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
  34. package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
  35. package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
  36. package/dist/runtime/channels/channel-clients.d.ts +0 -1
  37. package/dist/runtime/channels/channel-clients.js +0 -8
  38. package/dist/runtime/channels/channel-outbound-operations.js +2 -10
  39. package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
  40. package/dist/runtime/channels/channel-runtime-manager.js +1 -12
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
  42. package/dist/runtime/channels/channel-socket-registry.js +49 -62
  43. package/dist/runtime/channels/channel-transports.d.ts +0 -3
  44. package/dist/runtime/channels/fanout-location-runtime.js +3 -9
  45. package/dist/runtime/execution/index.d.ts +18 -8
  46. package/dist/runtime/execution/index.js +55 -29
  47. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
  48. package/dist/runtime/execution/serial-execution-queue.js +49 -15
  49. package/dist/runtime/foundation/listener-records.d.ts +11 -0
  50. package/dist/runtime/foundation/listener-records.js +20 -0
  51. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
  52. package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
  53. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
  54. package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
  55. package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
  56. package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
  57. package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
  58. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
  59. package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
  60. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
  61. package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
  62. package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
  63. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
  64. package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
  65. package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
  66. package/dist/runtime/foundation/service-topology-registry.js +6 -30
  67. package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
  68. package/dist/runtime/host/actor-transfer-runtime.js +73 -86
  69. package/dist/runtime/host/index.d.ts +6 -2
  70. package/dist/runtime/host/index.js +63 -37
  71. package/dist/runtime/host/remote-bound-session-relay.js +4 -3
  72. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
  73. package/dist/runtime/host/route-mesh-runtime.js +7 -5
  74. package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
  75. package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
  76. package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
  77. package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
  78. package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
  79. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
  80. package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
  81. package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
  82. package/dist/runtime/locations/lifecycle.d.ts +1 -1
  83. package/dist/runtime/locations/lifecycle.js +2 -2
  84. package/dist/runtime/locations/resolvers.js +7 -2
  85. package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
  86. package/dist/runtime/locations/spot-location-claims.js +3 -27
  87. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
  88. package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
  89. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
  90. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
  91. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
  92. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
  93. package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
  94. package/dist/runtime/spots/index.d.ts +25 -19
  95. package/dist/runtime/spots/index.js +207 -205
  96. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  97. package/dist/runtime/spots/spot-activation-registry.js +34 -31
  98. package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
  99. package/dist/runtime/spots/spot-activation-state.js +4 -17
  100. package/dist/runtime/spots/spot-activation.d.ts +8 -6
  101. package/dist/runtime/spots/spot-activation.js +54 -49
  102. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
  103. package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
  104. package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
  105. package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
  106. package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
  107. package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
  108. package/dist/runtime/spots/spot-actor-membership.js +26 -12
  109. package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
  110. package/dist/runtime/spots/spot-entry-activation.js +0 -1
  111. package/dist/runtime/spots/spot-manager-public.js +1 -1
  112. package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
  113. package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
  114. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
  115. package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
  116. package/dist/runtime/spots/spot-outbound.js +1 -29
  117. package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
  118. package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
  119. package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
  120. package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
  121. package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
  122. package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
  123. package/dist/runtime/spots/spot-serial-executor.js +8 -1
  124. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
  125. package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
  126. package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
  127. package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
  128. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
  129. package/dist/runtime/streams/bound-session-service.js +1 -18
  130. package/dist/runtime/streams/index.d.ts +2 -0
  131. package/dist/runtime/streams/index.js +19 -19
  132. package/dist/runtime/streams/session-serial-executor.js +2 -2
  133. package/package.json +3 -3
  134. package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
  135. package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
  136. package/src/internal.ts +1 -0
  137. package/src/runtime/activation-admission.ts +78 -0
  138. package/src/runtime/actors/actor-context.ts +6 -6
  139. package/src/runtime/actors/actor-handoff.ts +31 -23
  140. package/src/runtime/actors/actor-local-native-join.ts +3 -42
  141. package/src/runtime/actors/actor-remote-joiner.ts +6 -25
  142. package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
  143. package/src/runtime/actors/actor-source-transfer.ts +5 -18
  144. package/src/runtime/actors/deferred-join-completion.ts +40 -0
  145. package/src/runtime/actors/index.ts +22 -9
  146. package/src/runtime/admission.ts +5 -1
  147. package/src/runtime/backend/contracts/index.ts +2 -13
  148. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
  149. package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
  150. package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
  151. package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
  152. package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
  153. package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
  154. package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
  155. package/src/runtime/backend/raw-binding-port.ts +13 -0
  156. package/src/runtime/channels/channel-clients.ts +0 -11
  157. package/src/runtime/channels/channel-outbound-operations.ts +3 -11
  158. package/src/runtime/channels/channel-runtime-manager.ts +4 -15
  159. package/src/runtime/channels/channel-socket-registry.ts +69 -71
  160. package/src/runtime/channels/channel-transports.ts +0 -3
  161. package/src/runtime/channels/fanout-location-runtime.ts +4 -16
  162. package/src/runtime/execution/index.ts +68 -30
  163. package/src/runtime/execution/serial-execution-queue.ts +52 -20
  164. package/src/runtime/foundation/listener-records.ts +21 -0
  165. package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
  166. package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
  167. package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
  168. package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
  169. package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
  170. package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
  171. package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
  172. package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
  173. package/src/runtime/foundation/service-topology-registry.ts +8 -48
  174. package/src/runtime/host/actor-transfer-runtime.ts +94 -166
  175. package/src/runtime/host/index.ts +119 -54
  176. package/src/runtime/host/remote-bound-session-relay.ts +4 -3
  177. package/src/runtime/host/route-mesh-runtime.ts +9 -5
  178. package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
  179. package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
  180. package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
  181. package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
  182. package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
  183. package/src/runtime/locations/lifecycle.ts +3 -2
  184. package/src/runtime/locations/resolvers.ts +19 -13
  185. package/src/runtime/locations/spot-location-claims.ts +5 -34
  186. package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
  187. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  188. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
  189. package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
  190. package/src/runtime/spots/index.ts +341 -295
  191. package/src/runtime/spots/spot-activation-registry.ts +41 -31
  192. package/src/runtime/spots/spot-activation-state.ts +4 -16
  193. package/src/runtime/spots/spot-activation.ts +102 -80
  194. package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
  195. package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
  196. package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
  197. package/src/runtime/spots/spot-actor-membership.ts +81 -17
  198. package/src/runtime/spots/spot-entry-activation.ts +0 -3
  199. package/src/runtime/spots/spot-manager-public.ts +8 -4
  200. package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
  201. package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
  202. package/src/runtime/spots/spot-outbound.ts +4 -47
  203. package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
  204. package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
  205. package/src/runtime/spots/spot-runtime-ports.ts +6 -17
  206. package/src/runtime/spots/spot-serial-executor.ts +9 -1
  207. package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
  208. package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
  209. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
  210. package/src/runtime/streams/bound-session-service.ts +2 -36
  211. package/src/runtime/streams/index.ts +29 -27
  212. package/src/runtime/streams/session-serial-executor.ts +2 -2
  213. package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
  214. package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
  215. package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
@@ -53,25 +53,27 @@ export class ZLinkSpotActorLifecycleDrain {
53
53
  continue;
54
54
  }
55
55
  if (actorRef === null || actorRef === undefined) continue;
56
- await this.options.serial.execute(() => {
57
- const actor = this.options.resolveActor(actorId);
58
- if (actor === undefined) {
56
+ await this.options.serial.executeLifecycleOperation(() =>
57
+ this.options.serial.execute(() => {
58
+ const actor = this.options.resolveActor(actorId);
59
+ if (actor === undefined) {
60
+ return undefined;
61
+ }
62
+ const target = this.options.getTarget();
63
+ if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_JOINED) {
64
+ return target.onJoinedActor?.(actor);
65
+ }
66
+ if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_LEFT) {
67
+ return Promise.resolve(target.onLeaveActor?.(actor)).then(() => {
68
+ this.options.commitActorDeparture?.(actorId);
69
+ });
70
+ }
71
+ if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_DISCONNECTED) {
72
+ return target.onDisconnectActor?.(actor);
73
+ }
59
74
  return undefined;
60
- }
61
- const target = this.options.getTarget();
62
- if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_JOINED) {
63
- return target.onJoinedActor?.(actor);
64
- }
65
- if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_LEFT) {
66
- return Promise.resolve(target.onLeaveActor?.(actor)).then(() => {
67
- this.options.commitActorDeparture?.(actorId);
68
- });
69
- }
70
- if (event.kind === ZLINK_SPOT_ACTOR_LIFECYCLE_DISCONNECTED) {
71
- return target.onDisconnectActor?.(actor);
72
- }
73
- return undefined;
74
- });
75
+ })
76
+ );
75
77
  }
76
78
  }
77
79
  }
@@ -11,6 +11,10 @@ import { throwIfAborted } from '../abort';
11
11
  import type { Message } from '../../contracts/Common/Message';
12
12
  import { ZLinkBufferMessage as RuntimeMessage } from '../backend/runtime-message';
13
13
  import { ZLinkConfigurationException } from '../configuration';
14
+ import {
15
+ ZLinkFrameworkInternalErrorKind,
16
+ createInternalFrameworkException
17
+ } from '../framework-errors-internal';
14
18
  import { ZLinkDispatchErrorReporter } from '../channels';
15
19
  import { ZLINK_ACTOR_JOIN_ENTRY_SPOT_RUNTIME, ZLinkSpotActorDispatcher } from '../actors';
16
20
  import { encodeFrameworkPayloadMessage } from '../messaging/payload-codec';
@@ -37,6 +41,7 @@ export interface ZLinkSpotActorMembershipOptions {
37
41
  readonly entrySpotIdProvider?: (meshName: string) => string | undefined;
38
42
  readonly spotRouteResolver?: ZLinkSpotRouteResolver;
39
43
  readonly actorTransferRuntime?: ZLinkSpotActorTransferRuntime;
44
+ readonly isSpotClosing?: (activation: ZLinkSpotActivation) => boolean;
40
45
  }
41
46
 
42
47
  export type ZLinkActorJoinRollback = () => Promise<void> | void;
@@ -57,6 +62,36 @@ export class ZLinkSpotActorMembership {
57
62
  ): Promise<ZLinkSpotActorJoinResult> {
58
63
  throwIfAborted(signal);
59
64
  const activation = this.requireActivation(spotId);
65
+ return await this.runLifecycleOperation(activation, async () => {
66
+ if (this.options.isSpotClosing?.(activation) === true) {
67
+ throw createInternalFrameworkException(
68
+ ZLinkFrameworkInternalErrorKind.RequestRejected,
69
+ `User Spot '${String(spotId)}' is closing.`
70
+ );
71
+ }
72
+ return await this.admitActorJoinCore(
73
+ activation,
74
+ actor,
75
+ request,
76
+ commit,
77
+ signal,
78
+ leaveSource,
79
+ contentType
80
+ );
81
+ });
82
+ }
83
+
84
+ private async admitActorJoinCore(
85
+ activation: ZLinkSpotActivation,
86
+ actor: ZLinkActor,
87
+ request: Message,
88
+ commit: (
89
+ spot: ZLinkSpot
90
+ ) => Promise<ZLinkActorJoinRollback | void> | ZLinkActorJoinRollback | void,
91
+ signal: AbortSignal | undefined,
92
+ leaveSource: (() => Promise<void>) | undefined,
93
+ contentType: string
94
+ ): Promise<ZLinkSpotActorJoinResult> {
60
95
  const dispatcher = this.createActorDispatcher(activation);
61
96
  const transaction: {
62
97
  rollbackExternal?: ZLinkActorJoinRollback;
@@ -103,6 +138,17 @@ export class ZLinkSpotActorMembership {
103
138
  ): Promise<void> {
104
139
  throwIfAborted(signal);
105
140
  const activation = this.requireActivation(spotId, meshName);
141
+ await this.runLifecycleOperation(activation, () =>
142
+ this.leaveActorCore(activation, actor, signal, meshName)
143
+ );
144
+ }
145
+
146
+ private async leaveActorCore(
147
+ activation: ZLinkSpotActivation,
148
+ actor: ZLinkActor,
149
+ signal?: AbortSignal,
150
+ meshName?: string
151
+ ): Promise<void> {
106
152
  const localEntryNodeRid =
107
153
  (meshName === undefined ? undefined : this.options.nodeRidProvider?.(meshName)) ??
108
154
  this.options.entryNodeRidProvider?.() ??
@@ -177,11 +223,13 @@ export class ZLinkSpotActorMembership {
177
223
  ): Promise<void> {
178
224
  throwIfAborted(signal);
179
225
  const activation = this.requireActivation(spotId);
180
- await activation.serial.execute(async () => {
181
- activation.beginActorTransfer(actor.context.actorId);
182
- await activation.spot.onLeaveActor(actor);
183
- activation.commitActorDeparture(actor.context.actorId);
184
- });
226
+ await this.runLifecycleOperation(activation, () =>
227
+ activation.serial.execute(async () => {
228
+ activation.beginActorTransfer(actor.context.actorId);
229
+ await activation.spot.onLeaveActor(actor);
230
+ activation.commitActorDeparture(actor.context.actorId);
231
+ })
232
+ );
185
233
  }
186
234
 
187
235
  async prepareActorLeaveForTransfer(
@@ -191,12 +239,16 @@ export class ZLinkSpotActorMembership {
191
239
  ): Promise<void> {
192
240
  throwIfAborted(signal);
193
241
  const activation = this.requireActivation(spotId);
194
- await activation.serial.execute(() => activation.spot.onLeaveActor(actor));
242
+ await this.runLifecycleOperation(activation, () =>
243
+ activation.serial.execute(() => activation.spot.onLeaveActor(actor))
244
+ );
195
245
  }
196
246
 
197
247
  async commitActorLeaveAfterTransfer(spotId: RoutingId, actorId: string): Promise<void> {
198
248
  const activation = this.requireActivation(spotId);
199
- await activation.serial.execute(() => activation.commitActorDeparture(actorId));
249
+ await this.runLifecycleOperation(activation, () =>
250
+ activation.serial.execute(() => activation.commitActorDeparture(actorId))
251
+ );
200
252
  }
201
253
 
202
254
  async restoreActorAfterFailedTransfer(
@@ -206,24 +258,26 @@ export class ZLinkSpotActorMembership {
206
258
  ): Promise<void> {
207
259
  throwIfAborted(signal);
208
260
  const activation = this.requireActivation(spotId);
209
- await activation.serial.execute(async () => {
210
- activation.cancelActorTransfer(actor.context.actorId);
211
- await activation.spot.onJoinedActor(actor);
212
- });
261
+ await this.runLifecycleOperation(activation, () =>
262
+ activation.serial.execute(async () => {
263
+ activation.cancelActorTransfer(actor.context.actorId);
264
+ await activation.spot.onJoinedActor(actor);
265
+ })
266
+ );
213
267
  }
214
268
 
215
269
  async beginActorTransfer(spotId: RoutingId, actorId: string): Promise<void> {
216
270
  const activation = this.requireActivation(spotId);
217
- await activation.serial.execute(() => {
218
- activation.beginActorTransfer(actorId);
219
- });
271
+ await this.runLifecycleOperation(activation, () =>
272
+ activation.serial.execute(() => activation.beginActorTransfer(actorId))
273
+ );
220
274
  }
221
275
 
222
276
  async cancelActorTransfer(spotId: RoutingId, actorId: string): Promise<void> {
223
277
  const activation = this.requireActivation(spotId);
224
- await activation.serial.execute(() => {
225
- activation.cancelActorTransfer(actorId);
226
- });
278
+ await this.runLifecycleOperation(activation, () =>
279
+ activation.serial.execute(() => activation.cancelActorTransfer(actorId))
280
+ );
227
281
  }
228
282
 
229
283
  async notifyJoinedActorDisconnected(
@@ -252,6 +306,16 @@ export class ZLinkSpotActorMembership {
252
306
  return activation;
253
307
  }
254
308
 
309
+ private async runLifecycleOperation<T>(
310
+ activation: ZLinkSpotActivation,
311
+ operation: () => Promise<T> | T
312
+ ): Promise<T> {
313
+ const pending = activation.serial.executeLifecycleOperation(operation);
314
+ return activation.serial.isCurrentTurn
315
+ ? await activation.serial.currentTurn!.yieldFrameworkPromise(pending)
316
+ : await pending;
317
+ }
318
+
255
319
  private createActorDispatcher(activation: ZLinkSpotActivation): ZLinkSpotActorDispatcher {
256
320
  return new ZLinkSpotActorDispatcher({
257
321
  registry: activation.actorHandlers,
@@ -29,7 +29,6 @@ import { routingIdsEqual } from '../routing-id';
29
29
  import { ZLinkSpotActorHandlerRegistryRuntime } from '../actors';
30
30
  import type {
31
31
  ZLinkBackendActorRecvInfo,
32
- ZLinkBackendReceived,
33
32
  ZLinkBackendSpot,
34
33
  ZLinkBackendSpotNode,
35
34
  ZLinkBackendTopicMessage
@@ -81,7 +80,6 @@ interface ZLinkEntrySpotActivationOptions {
81
80
  readonly actorRequestHandlers?: readonly ZLinkEntrySpotActorRequestHandlerRegistration[];
82
81
  readonly nativeSpot: ZLinkBackendSpot;
83
82
  readonly nativeNode: ZLinkBackendSpotNode;
84
- readonly createReceived: () => ZLinkBackendReceived;
85
83
  readonly createTopicMessage: () => ZLinkBackendTopicMessage;
86
84
  readonly nodeRid: RoutingId;
87
85
  readonly spotNodeName: string;
@@ -382,7 +380,6 @@ export class ZLinkEntrySpotActivation {
382
380
  private attachActorJoinDispatch(): void {
383
381
  const dispatch = new ZLinkSpotActorJoinDispatch({
384
382
  nativeSpot: this.options.nativeSpot,
385
- createReceived: this.options.createReceived,
386
383
  createTopicMessage: this.options.createTopicMessage,
387
384
  serial: this.serial,
388
385
  actors: {
@@ -100,10 +100,14 @@ export class ZLinkPublicSpotManager implements ZLinkSpotManager {
100
100
  if (this.options.isLocalNode(current.meshName, current.nodeRid)) {
101
101
  const closed = await this.options.coordinator.close(
102
102
  spot,
103
- (local) => this.options.local.close(local.meshName, local.spotId, signal),
104
- signal,
105
- (local) => this.options.local.hasActiveSpot(local.spotId),
106
- (local) => this.options.local.canCloseUserSpot(local.meshName, local.spotId)
103
+ (local, beginAuthority) =>
104
+ this.options.local.closeUserWithAuthority(
105
+ local.meshName,
106
+ local.spotId,
107
+ beginAuthority,
108
+ signal
109
+ ),
110
+ signal
107
111
  );
108
112
  if (closed) this.options.resolver()?.invalidate?.(spot.spotId);
109
113
  return closed;
@@ -40,7 +40,7 @@ interface ZLinkSpotNativeActorJoinAdmissionOptions {
40
40
  export class ZLinkSpotNativeActorJoinAdmission {
41
41
  constructor(private readonly options: ZLinkSpotNativeActorJoinAdmissionOptions) {}
42
42
 
43
- async admit(request: ZLinkBackendActorJoinRequest): Promise<void> {
43
+ async admit(request: ZLinkBackendActorJoinRequest, rejectClosing = false): Promise<void> {
44
44
  const actorId = request.info.targetActor.actorId;
45
45
  let accepted = false;
46
46
  let acceptedActor: ZLinkActor | undefined;
@@ -51,7 +51,7 @@ export class ZLinkSpotNativeActorJoinAdmission {
51
51
  throw new Error('Remote actor join requires the two-phase routed transfer protocol.');
52
52
  }
53
53
  const actor = this.options.resolveActor(actorId);
54
- if (actor !== undefined) {
54
+ if (!rejectClosing && actor !== undefined) {
55
55
  const target = this.options.getTarget();
56
56
  const joinRequest = request.message;
57
57
  const joinPayload = wrapFrameworkPayloadMessage(
@@ -1,3 +1,4 @@
1
+ import type { ZLinkListenerRecords } from '../foundation/listener-records';
1
2
  import {
2
3
  ZLinkFrameworkInternalErrorKind,
3
4
  createInternalFrameworkException
@@ -88,6 +89,7 @@ import type {
88
89
  ZLinkSpotBoundSessionRuntime
89
90
  } from './spot-runtime-ports';
90
91
  import { createAbortError } from '../abort';
92
+ import type { ZLinkActivationConcurrency } from '../activation-admission';
91
93
  import type { ServiceMessageFollowRecord } from '../foundation/service-stateful-wire-codec';
92
94
  import {
93
95
  ApplicationJobQueue,
@@ -101,6 +103,7 @@ const ZLINK_SEND_DONT_WAIT = 1;
101
103
  const EMPTY_SPOT_METADATA: ReadonlyMap<string, string> = new Map();
102
104
 
103
105
  export interface ZLinkSpotNodeRuntimeManagerOptions {
106
+ readonly listenerRecords?: ZLinkListenerRecords;
104
107
  readonly registration: ZLinkFrameworkRegistration;
105
108
  readonly primaryMeshName?: string;
106
109
  readonly backendAdapterFactory: ZLinkBackendAdapterFactory;
@@ -130,10 +133,8 @@ export interface ZLinkSpotNodeRuntimeManagerOptions {
130
133
  record: ReceiveRecord
131
134
  ) => void | Promise<void>;
132
135
  readonly messageFollowReceiver?: (record: ServiceMessageFollowRecord) => void;
133
- readonly instanceActivationConcurrencyProvider?: (meshName: string) => {
134
- readonly active: number;
135
- readonly limit: number;
136
- };
136
+ /** MeshNode §5.1 activation admission record; the descriptor projects it for placement. */
137
+ readonly activationConcurrency?: (meshName: string) => ZLinkActivationConcurrency;
137
138
  }
138
139
 
139
140
  export class ZLinkSpotNodeRuntimeManager {
@@ -168,10 +169,6 @@ export class ZLinkSpotNodeRuntimeManager {
168
169
  new ApplicationJobQueue(resolveApplicationJobQueueConfiguration());
169
170
  }
170
171
 
171
- createReceived() {
172
- return this.options.backendAdapterFactory.createReceived();
173
- }
174
-
175
172
  createTopicMessage() {
176
173
  return this.options.backendAdapterFactory.createTopicMessage();
177
174
  }
@@ -378,6 +375,10 @@ export class ZLinkSpotNodeRuntimeManager {
378
375
  this.meshNodes.set(spotNodeName, node);
379
376
  this.meshPumps.set(spotNodeName, pump);
380
377
  this.meshCompletions.set(spotNodeName, completions);
378
+ const listenerEndpoint = node.status().localEndpoint;
379
+ if (listenerEndpoint.length > 0) {
380
+ this.options.listenerRecords?.record('routeMesh', spotNodeName, listenerEndpoint);
381
+ }
381
382
  } catch (error) {
382
383
  this.entryActivations.delete(spotNodeName);
383
384
  this.publishers.get(spotNodeName)?.close();
@@ -488,15 +489,9 @@ export class ZLinkSpotNodeRuntimeManager {
488
489
  };
489
490
  })
490
491
  },
491
- activationConcurrency: {
492
- active:
493
- this.options.instanceActivationConcurrencyProvider?.(meshName).active ??
494
- current?.activationConcurrency.active ??
495
- 0,
496
- limit:
497
- this.options.instanceActivationConcurrencyProvider?.(meshName).limit ??
498
- registration.activationConcurrencyLimit ??
499
- 128
492
+ activationConcurrency: this.options.activationConcurrency?.(meshName) ?? {
493
+ active: 0,
494
+ limit: registration.activationConcurrencyLimit ?? 128
500
495
  },
501
496
  channelWeights: Object.fromEntries(
502
497
  this.serverChannels(meshName).map(([channelName, channel]) => [
@@ -975,7 +970,6 @@ export class ZLinkSpotNodeRuntimeManager {
975
970
  entrySpotType: spotNode.entrySpotType,
976
971
  nativeSpot: node.entrySpot() as never,
977
972
  nativeNode: node as unknown as ZLinkBackendSpotNode,
978
- createReceived: () => this.options.backendAdapterFactory.createReceived(),
979
973
  createTopicMessage: () => this.options.backendAdapterFactory.createTopicMessage(),
980
974
  nodeRid: String(node.status().routingId),
981
975
  spotNodeName,
@@ -1,10 +1,8 @@
1
1
  import {
2
2
  ZLinkFrameworkInternalErrorKind,
3
- createInternalFrameworkException,
4
- internalFrameworkErrorKind
3
+ createInternalFrameworkException
5
4
  } from '../framework-errors-internal';
6
- import { ZLinkFrameworkRuntimeState, ZLinkSpotKind } from '../../contracts';
7
- import { ZLinkFrameworkException } from '../../contracts/Errors';
5
+ import { ZLinkSpotKind } from '../../contracts';
8
6
  import type {
9
7
  RoutingId,
10
8
  ZLinkChannelClient,
@@ -31,12 +29,7 @@ import { requireZLinkYieldTurn } from '../execution';
31
29
  import { resolveFrameworkPacketName } from '../messaging/packet-name';
32
30
  import type { ZLinkSpotRouteTarget } from './spot-routing-internal';
33
31
  import { ZLinkSpotSerialTurnExecutor } from './spot-serial-turn-executor';
34
- import {
35
- resolveSpotHandle,
36
- refreshSpotHandle,
37
- type SpotHandle,
38
- type ResolvedSpotHandle
39
- } from './spot-handle';
32
+ import { resolveSpotHandle, type SpotHandle, type ResolvedSpotHandle } from './spot-handle';
40
33
 
41
34
  export interface DefaultZLinkSpotOutboundOptions {
42
35
  readonly serial: ZLinkSpotSerialTurnExecutor;
@@ -680,29 +673,7 @@ export async function requestToSpotHandle<TReply = unknown>(
680
673
  return transport.requestToSpot<TReply>(target, request, transportOptions);
681
674
  };
682
675
 
683
- const resolved = await requireSpotRef(spot, options.signal);
684
- try {
685
- return await requestResolved(resolved);
686
- } catch (error) {
687
- if (!shouldRefreshAfterRouteDisconnect(resolved, error)) {
688
- throw error;
689
- }
690
- let refreshed: ResolvedSpotHandle | undefined;
691
- try {
692
- refreshed = await refreshSpotHandle(spot, options.signal);
693
- } catch {
694
- throw error;
695
- }
696
- if (isShutdownTargetState(refreshed?.targetNodeState)) {
697
- throw createInternalFrameworkException(
698
- ZLinkFrameworkInternalErrorKind.RuntimeShutdown,
699
- `Spot '${String(spot.spotId)}' target host is shutting down.`,
700
- false,
701
- error
702
- );
703
- }
704
- throw error;
705
- }
676
+ return requestResolved(await requireSpotRef(spot, options.signal));
706
677
  }
707
678
 
708
679
  async function requireSpotRef(
@@ -730,20 +701,6 @@ function spotRefToSpotRouteTarget(
730
701
  };
731
702
  }
732
703
 
733
- function shouldRefreshAfterRouteDisconnect(target: ResolvedSpotHandle, error: unknown): boolean {
734
- return (
735
- target.targetNodeState === ZLinkFrameworkRuntimeState.Serving &&
736
- error instanceof ZLinkFrameworkException &&
737
- internalFrameworkErrorKind(error) === ZLinkFrameworkInternalErrorKind.RouteNotConnected
738
- );
739
- }
740
-
741
- function isShutdownTargetState(state: ResolvedSpotHandle['targetNodeState']): boolean {
742
- return (
743
- state === ZLinkFrameworkRuntimeState.Draining || state === ZLinkFrameworkRuntimeState.Stopped
744
- );
745
- }
746
-
747
704
  function normalizeSpotRefRoutingId(routingId: RoutingId): RoutingId {
748
705
  return normalizeOpaqueRoutingId(routingId);
749
706
  }
@@ -29,6 +29,10 @@ import {
29
29
  import { submitRoutedActorJoinError, submitRoutedActorJoinReply } from './spot-route-replies';
30
30
  import type { ZLinkSpotSerialTurnExecutor } from './spot-serial-turn-executor';
31
31
  import type { ZLinkActorHandoffPacket, ZLinkActorHandoffResult } from '../actors/actor-handoff';
32
+ import {
33
+ ZLinkFrameworkInternalErrorKind,
34
+ createInternalFrameworkException
35
+ } from '../framework-errors-internal';
32
36
 
33
37
  interface ZLinkRoutedActorAdmissionTarget {
34
38
  onActorJoin?(actorId: string, request: ZLinkMessage): Promise<ZLinkSpotActorJoinResult>;
@@ -36,6 +40,7 @@ interface ZLinkRoutedActorAdmissionTarget {
36
40
 
37
41
  interface ZLinkSpotRoutedActorAdmissionOptions {
38
42
  readonly serial: ZLinkSpotSerialTurnExecutor;
43
+ readonly isSpotClosing?: () => boolean;
39
44
  readonly getTarget: () => ZLinkRoutedActorAdmissionTarget;
40
45
  readonly defaultAccept: boolean;
41
46
  readonly routedActorTransferProvider?: ZLinkRoutedActorTransferProvider;
@@ -73,6 +78,21 @@ export class ZLinkSpotRoutedActorAdmission {
73
78
  if (decoded === undefined) {
74
79
  return false;
75
80
  }
81
+ if (this.options.isSpotClosing?.() === true) {
82
+ try {
83
+ submitRoutedActorJoinError(
84
+ received,
85
+ decoded,
86
+ createInternalFrameworkException(
87
+ ZLinkFrameworkInternalErrorKind.RequestRejected,
88
+ `Actor '${decoded.actorId}' target Spot is closing.`
89
+ )
90
+ );
91
+ } finally {
92
+ this.closeDecoded(decoded);
93
+ }
94
+ return true;
95
+ }
76
96
  if (decoded.phase === 'admission') {
77
97
  await this.admitTransfer(decoded, received);
78
98
  return true;
@@ -9,11 +9,10 @@ import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProvider
9
9
  import type { RoutingId } from '../../contracts';
10
10
  import type { ActorRef } from '../../contracts/Common/ActorRef';
11
11
  import type { ZLinkRemoteActorPacketTarget, ZLinkRemoteBoundSessionTarget } from '../actors';
12
- import type { ZLinkBackendReceived, ZLinkBackendSpot } from '../backend/contracts';
12
+ import type { ZLinkBackendReceived } from '../backend/contracts';
13
13
  import type { ZLinkDispatchErrorReporter } from '../channels';
14
14
  import type { ZLinkChannelEnvelopeCodecRegistry } from '../channels/channel-envelope';
15
15
  import { decodeRemoteActorPacketRelay } from './spot-remote-route-codec';
16
- import { ZLINK_RECV_DONT_WAIT } from './spot-native-flags';
17
16
  import { ZLinkSpotActorPacketRelayDispatch } from './spot-actor-packet-relay-dispatch';
18
17
  import type {
19
18
  ZLinkActorPacketDelivery,
@@ -33,10 +32,9 @@ interface ZLinkRoutedFrameAdmissionTarget {
33
32
  }
34
33
 
35
34
  interface ZLinkSpotRoutedFrameDispatchOptions {
36
- readonly nativeSpot: ZLinkBackendSpot;
37
- readonly createReceived: () => ZLinkBackendReceived;
38
35
  readonly nativeSpotId: string;
39
36
  readonly serial: ZLinkSpotSerialTurnExecutor;
37
+ readonly isSpotClosing?: () => boolean;
40
38
  readonly resolveActor: (actorId: string) => ZLinkActor | undefined;
41
39
  readonly getTarget: () => ZLinkRoutedFrameAdmissionTarget & ZLinkSpot;
42
40
  readonly defaultAccept: boolean;
@@ -86,11 +84,9 @@ interface ZLinkSpotRoutedFrameDispatchOptions {
86
84
  readonly providerResolver?: ZLinkProviderResolver;
87
85
  readonly dispatchErrors?: ZLinkDispatchErrorReporter;
88
86
  readonly claimApplicationWork?: () => ZLinkApplicationWorkClaim;
89
- readonly waitIdle: () => Promise<void>;
90
87
  }
91
88
 
92
89
  export class ZLinkSpotRoutedFrameDispatch {
93
- private routeDraining = false;
94
90
  private readonly packetHandlers = new Map<string, ZLinkSpotHandlerRegistration[]>();
95
91
  private readonly routedBoundSessionDispatch: ZLinkSpotRoutedBoundSessionDispatch;
96
92
  private readonly actorPacketRelayDispatch: ZLinkSpotActorPacketRelayDispatch;
@@ -123,6 +119,7 @@ export class ZLinkSpotRoutedFrameDispatch {
123
119
  });
124
120
  this.routedActorAdmission = new ZLinkSpotRoutedActorAdmission({
125
121
  serial: options.serial,
122
+ isSpotClosing: options.isSpotClosing,
126
123
  getTarget: options.getTarget,
127
124
  defaultAccept: options.defaultAccept,
128
125
  routedActorTransferProvider: options.routedActorTransferProvider,
@@ -144,61 +141,6 @@ export class ZLinkSpotRoutedFrameDispatch {
144
141
  }
145
142
  }
146
143
 
147
- async drain(
148
- received: ZLinkBackendReceived | undefined = undefined,
149
- retryDeadlineMs = performance.now()
150
- ): Promise<void> {
151
- if (this.routeDraining) {
152
- if (received !== undefined) {
153
- try {
154
- await this.dispatch(received);
155
- } finally {
156
- received.close();
157
- }
158
- }
159
- return;
160
- }
161
- this.routeDraining = true;
162
- try {
163
- if (received !== undefined) {
164
- try {
165
- await this.dispatch(received);
166
- } finally {
167
- received.close();
168
- }
169
- received = undefined;
170
- }
171
- for (;;) {
172
- received ??= this.options.createReceived();
173
- try {
174
- if (!this.options.nativeSpot.recvRoute(received, ZLINK_RECV_DONT_WAIT)) {
175
- received.close();
176
- await this.options.waitIdle();
177
- return;
178
- }
179
- } catch (error) {
180
- if (isRouteRecvRetryable(error)) {
181
- closeReceivedQuietly(received);
182
- if (performance.now() < retryDeadlineMs) {
183
- setTimeout(() => void this.drain(undefined, retryDeadlineMs), 10);
184
- }
185
- return;
186
- }
187
- received.close();
188
- throw error;
189
- }
190
- try {
191
- await this.dispatch(received);
192
- } finally {
193
- received.close();
194
- }
195
- received = this.options.createReceived();
196
- }
197
- } finally {
198
- this.routeDraining = false;
199
- }
200
- }
201
-
202
144
  async dispatchFromEvent(received: ZLinkBackendReceived): Promise<void> {
203
145
  try {
204
146
  await this.dispatch(received);
@@ -234,20 +176,8 @@ export class ZLinkSpotRoutedFrameDispatch {
234
176
  if (await this.routePacketDispatch.dispatch(received)) {
235
177
  return;
236
178
  }
237
- await this.routedActorAdmission.admit(received);
179
+ await this.options.serial.executeLifecycleOperation(() =>
180
+ this.routedActorAdmission.admit(received)
181
+ );
238
182
  }
239
183
  }
240
-
241
- function isRouteRecvRetryable(error: unknown): boolean {
242
- return (
243
- typeof error === 'object' &&
244
- error !== null &&
245
- [201, 202, 204].includes(Number((error as { result?: unknown }).result))
246
- );
247
- }
248
-
249
- function closeReceivedQuietly(received: ZLinkBackendReceived): void {
250
- try {
251
- received.close();
252
- } catch {}
253
- }
@@ -10,7 +10,7 @@ import type { ZLinkMessageFollowOrigin } from '../foundation/service-runtime-con
10
10
  import type {
11
11
  ZLinkRemoteActorPacketTarget,
12
12
  ZLinkRemoteBoundSessionTarget,
13
- ZLinkDeferredJoinAcceptedRoot
13
+ ZLinkDeferredJoinCompletion
14
14
  } from '../actors';
15
15
  import type { ZLinkActorHandoffDispatch } from '../actors/actor-handoff';
16
16
  import type { ZLinkActorResponseOptions } from './spot-actor-packet-dispatch';
@@ -44,26 +44,15 @@ export interface ZLinkSpotActorTransferRuntime {
44
44
  operationId: ZLinkActorJoinOperationId,
45
45
  actorRef: ActorRef,
46
46
  rawReply: Uint8Array,
47
- replyContentType?: string,
48
- signal?: AbortSignal,
49
- canonicalInventoryDigest?: string
50
- ): Promise<ZLinkDeferredJoinAcceptedRoot>;
51
- discardDeferredJoinAccepted(
52
- root: ZLinkDeferredJoinAcceptedRoot,
53
- signal?: AbortSignal
54
- ): Promise<void>;
55
- markDeferredJoinAcceptedCommitted(
56
- root: ZLinkDeferredJoinAcceptedRoot,
57
- actorRef: ActorRef,
58
- signal?: AbortSignal
59
- ): Promise<ZLinkDeferredJoinAcceptedRoot>;
60
- commitAndDeliverDeferredJoinAccepted(
61
- root: ZLinkDeferredJoinAcceptedRoot,
47
+ replyContentType?: string
48
+ ): ZLinkDeferredJoinCompletion;
49
+ deliverDeferredJoinAccepted(
50
+ completion: ZLinkDeferredJoinCompletion,
62
51
  actor: ZLinkActor,
63
52
  actorRef: ActorRef,
64
53
  submitMailbox: <T>(operation: () => Promise<T>) => Promise<T>,
65
54
  signal?: AbortSignal
66
- ): Promise<ZLinkDeferredJoinAcceptedRoot>;
55
+ ): Promise<void>;
67
56
  getOrCreateRoutedActor(
68
57
  actorId: string,
69
58
  actorType: string,
@@ -107,6 +107,15 @@ export class ZLinkSpotSerialExecutor {
107
107
  * ownership turn. Already accepted work remains drainable.
108
108
  */
109
109
  close(): Promise<void> {
110
+ const children = this.closeChildren();
111
+ return Promise.all([children, this.spotSerial.close()]).then(() => undefined);
112
+ }
113
+
114
+ /**
115
+ * Closes the Actor and timer queues. The Spot queue stays open for the Spot
116
+ * Close lifecycle item that owns it; that Close closes it when it finishes.
117
+ */
118
+ closeChildren(): Promise<void> {
110
119
  if (this.closePromise !== undefined) return this.closePromise;
111
120
  this.closing = true;
112
121
  const childSerials = [...this.actorSerials.values(), ...this.timerSerials.values()];
@@ -115,7 +124,6 @@ export class ZLinkSpotSerialExecutor {
115
124
  this.timerSerials.clear();
116
125
  this.actorExecutors.clear();
117
126
  this.closePromise = Promise.all([
118
- this.spotSerial.close(),
119
127
  ...childSerials.map((serial) => serial.close()),
120
128
  ...actorExecutors.map((executor) => executor.close())
121
129
  ]).then(() => undefined);