@zlink-systems/framework 0.10.0 → 0.12.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 (125) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Configuration/EndpointNotation.d.ts +5 -4
  3. package/dist/contracts/Configuration/EndpointNotation.js +5 -4
  4. package/dist/contracts/Configuration/InternalDefaults.d.ts +0 -1
  5. package/dist/contracts/Configuration/InternalDefaults.js +1 -2
  6. package/dist/contracts/Configuration/RegistrationNormalizers.js +1 -2
  7. package/dist/contracts/Configuration/RegistrationTypes.d.ts +2 -5
  8. package/dist/contracts/Configuration/RegistrationValidators.js +0 -1
  9. package/dist/contracts/Errors/ZLinkFrameworkException.d.ts +6 -7
  10. package/dist/contracts/Errors/ZLinkFrameworkException.js +6 -7
  11. package/dist/runtime/actors/actor-client.js +1 -1
  12. package/dist/runtime/actors/actor-mailbox.js +1 -5
  13. package/dist/runtime/backend/contracts/index.d.ts +2 -0
  14. package/dist/runtime/backend/mesh-completion-table.d.ts +1 -3
  15. package/dist/runtime/backend/mesh-completion-table.js +11 -15
  16. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +11 -4
  17. package/dist/runtime/backend/mesh-dispatch-pump.js +201 -134
  18. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +3 -4
  19. package/dist/runtime/backend/node/node-backend-adapter-factory.js +51 -37
  20. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  21. package/dist/runtime/backend/node/node-backend-adapter-support.js +2 -2
  22. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +2 -2
  23. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +16 -0
  24. package/dist/runtime/backend/node/node-event-loop-poller.js +49 -0
  25. package/dist/runtime/backend/node/node-raw-binding-port.js +24 -41
  26. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +8 -8
  27. package/dist/runtime/backend/node/node-raw-mesh-backend.js +100 -107
  28. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +3 -2
  29. package/dist/runtime/backend/node/node-socket-backend-adapter.js +18 -67
  30. package/dist/runtime/backend/raw-binding-port.d.ts +1 -0
  31. package/dist/runtime/backend/runtime-values.d.ts +6 -1
  32. package/dist/runtime/backend/runtime-values.js +6 -0
  33. package/dist/runtime/channels/channel-dispatchers.js +2 -2
  34. package/dist/runtime/channels/channel-envelope.js +324 -121
  35. package/dist/runtime/channels/channel-multipart.d.ts +8 -1
  36. package/dist/runtime/channels/channel-outbound-operations.js +0 -2
  37. package/dist/runtime/channels/channel-receive-loops.d.ts +1 -3
  38. package/dist/runtime/channels/channel-receive-loops.js +25 -65
  39. package/dist/runtime/channels/channel-socket-registry.js +14 -1
  40. package/dist/runtime/channels/channel-transports.d.ts +2 -1
  41. package/dist/runtime/channels/channel-transports.js +12 -10
  42. package/dist/runtime/channels/client-server-location-runtime.js +15 -3
  43. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -18
  44. package/dist/runtime/execution/serial-execution-queue.js +16 -80
  45. package/dist/runtime/foundation/event-loop-resources.d.ts +0 -3
  46. package/dist/runtime/foundation/event-loop-resources.js +2 -11
  47. package/dist/runtime/foundation/operation-registry.d.ts +2 -8
  48. package/dist/runtime/foundation/operation-registry.js +3 -21
  49. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +19 -7
  50. package/dist/runtime/foundation/raw-service-mesh-runtime.js +56 -10
  51. package/dist/runtime/foundation/service-mailbox.d.ts +1 -7
  52. package/dist/runtime/foundation/service-mailbox.js +3 -2
  53. package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -1
  54. package/dist/runtime/foundation/service-stateful-registry.d.ts +1 -1
  55. package/dist/runtime/foundation/service-stateful-registry.js +2 -2
  56. package/dist/runtime/foundation/service-stateful-runtime.js +14 -14
  57. package/dist/runtime/framework-errors-internal.d.ts +4 -4
  58. package/dist/runtime/framework-errors-internal.js +8 -10
  59. package/dist/runtime/host/actor-placement-coordinator.js +1 -1
  60. package/dist/runtime/host/index.js +1 -1
  61. package/dist/runtime/host/service-relocation-host-runtime.js +0 -4
  62. package/dist/runtime/host/spot-address-transport.js +1 -1
  63. package/dist/runtime/host/user-spot-creation-coordinator.js +1 -1
  64. package/dist/runtime/locations/location-store-repository.d.ts +1 -0
  65. package/dist/runtime/locations/location-store-repository.js +64 -75
  66. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +0 -12
  67. package/dist/runtime/spots/spot-node-runtime-manager.js +6 -166
  68. package/dist/runtime/spots/spot-serial-turn-executor.js +1 -4
  69. package/dist/runtime/spots/spot-timer.d.ts +3 -0
  70. package/dist/runtime/spots/spot-timer.js +87 -18
  71. package/dist/runtime/streams/session-serial-executor.js +1 -3
  72. package/dist/runtime/streams/stream-session-runtime.d.ts +2 -2
  73. package/dist/runtime/streams/stream-session-runtime.js +13 -19
  74. package/dist/runtime/workers/index.d.ts +0 -1
  75. package/dist/runtime/workers/index.js +1 -9
  76. package/package.json +9 -3
  77. package/src/contracts/Configuration/EndpointNotation.ts +5 -4
  78. package/src/contracts/Configuration/InternalDefaults.ts +0 -1
  79. package/src/contracts/Configuration/RegistrationNormalizers.ts +2 -4
  80. package/src/contracts/Configuration/RegistrationTypes.ts +2 -5
  81. package/src/contracts/Configuration/RegistrationValidators.ts +0 -1
  82. package/src/contracts/Errors/ZLinkFrameworkException.ts +6 -7
  83. package/src/runtime/actors/actor-client.ts +1 -1
  84. package/src/runtime/actors/actor-mailbox.ts +1 -12
  85. package/src/runtime/backend/contracts/index.ts +2 -0
  86. package/src/runtime/backend/mesh-completion-table.ts +12 -23
  87. package/src/runtime/backend/mesh-dispatch-pump.ts +206 -138
  88. package/src/runtime/backend/node/node-backend-adapter-factory.ts +66 -35
  89. package/src/runtime/backend/node/node-backend-adapter-support.ts +4 -4
  90. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +2 -2
  91. package/src/runtime/backend/node/node-event-loop-poller.ts +55 -0
  92. package/src/runtime/backend/node/node-raw-binding-port.ts +30 -45
  93. package/src/runtime/backend/node/node-raw-mesh-backend.ts +97 -110
  94. package/src/runtime/backend/node/node-socket-backend-adapter.ts +23 -69
  95. package/src/runtime/backend/raw-binding-port.ts +1 -0
  96. package/src/runtime/backend/runtime-values.ts +13 -1
  97. package/src/runtime/channels/channel-dispatchers.ts +2 -2
  98. package/src/runtime/channels/channel-envelope.ts +379 -109
  99. package/src/runtime/channels/channel-multipart.ts +9 -1
  100. package/src/runtime/channels/channel-outbound-operations.ts +0 -1
  101. package/src/runtime/channels/channel-receive-loops.ts +24 -75
  102. package/src/runtime/channels/channel-socket-registry.ts +17 -1
  103. package/src/runtime/channels/channel-transports.ts +20 -10
  104. package/src/runtime/channels/client-server-location-runtime.ts +16 -2
  105. package/src/runtime/execution/serial-execution-queue.ts +16 -108
  106. package/src/runtime/foundation/event-loop-resources.ts +2 -11
  107. package/src/runtime/foundation/operation-registry.ts +2 -22
  108. package/src/runtime/foundation/raw-service-mesh-runtime.ts +74 -19
  109. package/src/runtime/foundation/service-mailbox.ts +3 -13
  110. package/src/runtime/foundation/service-runtime-contracts.ts +2 -1
  111. package/src/runtime/foundation/service-stateful-registry.ts +2 -2
  112. package/src/runtime/foundation/service-stateful-runtime.ts +14 -14
  113. package/src/runtime/framework-errors-internal.ts +8 -10
  114. package/src/runtime/host/actor-placement-coordinator.ts +1 -1
  115. package/src/runtime/host/index.ts +2 -1
  116. package/src/runtime/host/service-relocation-host-runtime.ts +0 -4
  117. package/src/runtime/host/spot-address-transport.ts +1 -1
  118. package/src/runtime/host/user-spot-creation-coordinator.ts +1 -1
  119. package/src/runtime/locations/location-store-repository.ts +118 -80
  120. package/src/runtime/spots/spot-node-runtime-manager.ts +13 -233
  121. package/src/runtime/spots/spot-serial-turn-executor.ts +1 -8
  122. package/src/runtime/spots/spot-timer.ts +109 -18
  123. package/src/runtime/streams/session-serial-executor.ts +1 -7
  124. package/src/runtime/streams/stream-session-runtime.ts +13 -17
  125. package/src/runtime/workers/index.ts +2 -17
@@ -1,3 +1,4 @@
1
+ import type { Socket } from '@zlink-systems/zlink';
1
2
  import type { ZLinkBackendObject } from '../contracts';
2
3
  import {
3
4
  closeWithBusyRetry,
@@ -17,14 +18,14 @@ import {
17
18
  type ZLinkBindingReplyOperation,
18
19
  type ZLinkBindingAsyncSendOperation
19
20
  } from './node-backend-adapter-support';
21
+ import { ZLinkNodeEventLoopPoller } from './node-event-loop-poller';
20
22
 
23
+ const eventLoopPollers = new WeakMap<object, ZLinkNodeEventLoopPoller>();
21
24
 
22
25
  export function wrapSocket<T extends { close(): void }>(
23
- nativeInstance: T
26
+ nativeInstance: T,
27
+ pollCompletion?: boolean
24
28
  ): T & ZLinkBackendObject {
25
- const boundEndpoints = new Set<string>();
26
- const connectedEndpoints = new Set<string>();
27
- const peerRoutingIds = new Set<unknown>();
28
29
  const socket = nativeInstance as T & {
29
30
  options?: {
30
31
  probe?: boolean;
@@ -40,32 +41,35 @@ export function wrapSocket<T extends { close(): void }>(
40
41
  const hasRoutedPeer = hasRequest
41
42
  && typeof (nativeInstance as { reply?: unknown }).reply === 'function';
42
43
  const hasStream = typeof (nativeInstance as { recvPacket?: unknown }).recvPacket === 'function';
44
+ const eventLoopPoller = pollCompletion === undefined
45
+ ? undefined
46
+ : new ZLinkNodeEventLoopPoller(
47
+ nativeInstance as unknown as Socket,
48
+ pollCompletion,
49
+ () => {}
50
+ );
43
51
  const adapter = {
44
52
  nativeInstance,
45
53
  async dispose(): Promise<void> {
54
+ eventLoopPoller?.dispose();
46
55
  disableSocketLinger(nativeInstance);
47
- closeSocketRoutes(nativeInstance, peerRoutingIds);
48
- closeSocketEndpoints(nativeInstance, boundEndpoints, connectedEndpoints);
49
56
  await closeWithBusyRetry(nativeInstance);
50
57
  },
51
58
  close(): void {
59
+ eventLoopPoller?.dispose();
52
60
  nativeInstance.close();
53
61
  },
54
62
  bind(endpoint: string): void {
55
63
  (nativeInstance as T & { bind(endpoint: string): void }).bind(endpoint);
56
- boundEndpoints.add(endpoint);
57
64
  },
58
65
  unbind(endpoint: string): void {
59
66
  (nativeInstance as T & { unbind(endpoint: string): void }).unbind(endpoint);
60
- boundEndpoints.delete(endpoint);
61
67
  },
62
68
  connect(endpoint: string): void {
63
69
  (nativeInstance as T & { connect(endpoint: string): void }).connect(endpoint);
64
- connectedEndpoints.add(endpoint);
65
70
  },
66
71
  disconnect(endpoint: string): void {
67
72
  (nativeInstance as T & { disconnect(endpoint: string): void }).disconnect(endpoint);
68
- connectedEndpoints.delete(endpoint);
69
73
  },
70
74
  setChannelName(channelName: string): void {
71
75
  const setChannelName = (nativeInstance as T & { setChannelName?: (value: string) => void }).setChannelName;
@@ -133,7 +137,6 @@ export function wrapSocket<T extends { close(): void }>(
133
137
  send(...args: unknown[]): unknown {
134
138
  if (hasStream) {
135
139
  const [routingId, payload] = args as [unknown, unknown];
136
- peerRoutingIds.add(routingId);
137
140
  const operation = (nativeInstance as T & {
138
141
  send(routingId: unknown): ZLinkBindingAsyncSendOperation;
139
142
  }).send(toNativeRoutingId(routingId));
@@ -142,7 +145,6 @@ export function wrapSocket<T extends { close(): void }>(
142
145
  }
143
146
  if (hasRoutedPeer) {
144
147
  const [routingId, payload] = args as [unknown, unknown];
145
- peerRoutingIds.add(routingId);
146
148
  return submitBindingAsyncSend(
147
149
  (nativeInstance as T & { send(routingId: unknown): ZLinkBindingAsyncSendOperation })
148
150
  .send(toNativeRoutingId(routingId)),
@@ -167,7 +169,6 @@ export function wrapSocket<T extends { close(): void }>(
167
169
  },
168
170
  submit(routingId: unknown, payload: unknown, _timeoutMs?: number): Promise<void> {
169
171
  if (!hasStream) throw new TypeError('Async stream send requires a STREAM socket.');
170
- peerRoutingIds.add(routingId);
171
172
  return submitBindingAsyncSend(
172
173
  (nativeInstance as T & { send(routingId: unknown): ZLinkBindingAsyncSendOperation })
173
174
  .send(toNativeRoutingId(routingId)),
@@ -177,7 +178,6 @@ export function wrapSocket<T extends { close(): void }>(
177
178
  request(...args: unknown[]): unknown {
178
179
  if (hasRoutedPeer) {
179
180
  const [routingId, payload, timeoutMs] = args as [unknown, unknown, number | undefined];
180
- peerRoutingIds.add(routingId);
181
181
  return submitBindingRequest(
182
182
  (nativeInstance as T & { request(routingId: unknown): ZLinkBindingRequestOperation })
183
183
  .request(toNativeRoutingId(routingId)),
@@ -197,7 +197,6 @@ export function wrapSocket<T extends { close(): void }>(
197
197
  },
198
198
  reply(...args: unknown[]): unknown {
199
199
  const [routingId, replyToken, payload] = args as [unknown, unknown, unknown];
200
- peerRoutingIds.add(routingId);
201
200
  const operation = (nativeInstance as T & {
202
201
  reply(routingId: unknown, replyToken: unknown): ZLinkBindingReplyOperation;
203
202
  }).reply(toNativeRoutingId(routingId), replyToken);
@@ -287,9 +286,18 @@ export function wrapSocket<T extends { close(): void }>(
287
286
  return false;
288
287
  }
289
288
  };
289
+ if (eventLoopPoller !== undefined) eventLoopPollers.set(adapter, eventLoopPoller);
290
290
  return adapter as unknown as T & ZLinkBackendObject;
291
291
  }
292
292
 
293
+ export function nodeEventLoopPollerOf(socket: object): ZLinkNodeEventLoopPoller {
294
+ const poller = eventLoopPollers.get(socket);
295
+ if (poller === undefined) {
296
+ throw new TypeError('Node backend socket does not own an event-loop poller.');
297
+ }
298
+ return poller;
299
+ }
300
+
293
301
  export function disconnectStreamPeer(
294
302
  socket: { disconnectRid(routingId: unknown): void },
295
303
  routingId: unknown
@@ -310,60 +318,6 @@ function requireSocketOptions<TOptions>(socket: { readonly options?: TOptions })
310
318
  return socket.options;
311
319
  }
312
320
 
313
- function closeSocketRoutes(target: unknown, peerRoutingIds: Set<unknown>): void {
314
- if (peerRoutingIds.size === 0 || !hasDisconnectRid(target)) {
315
- return;
316
- }
317
- for (const routingId of peerRoutingIds) {
318
- try {
319
- target.disconnectRid(toNativeRoutingId(routingId));
320
- } catch (error) {
321
- if (!isDisconnectRouteNotFoundError(error)) {
322
- throw error;
323
- }
324
- }
325
- peerRoutingIds.delete(routingId);
326
- }
327
- }
328
-
329
- export function isDisconnectRouteNotFoundError(error: unknown): boolean {
330
- return isBindingNotFound(error) || isContextTerminatedError(error) || (
331
- error instanceof Error && 'code' in error &&
332
- ((error as { code: unknown }).code === zlink.ConnectResult.NotFound ||
333
- (error as { code: unknown }).code === zlink.ConnectResult.Busy ||
334
- ((error as { code: unknown }).code === zlink.ConnectResult.InternalError &&
335
- /current state/i.test(error.message)))
336
- );
337
- }
338
-
339
- function hasDisconnectRid(target: unknown): target is { disconnectRid(routingId: unknown): void } {
340
- return target !== null && typeof target === 'object' && 'disconnectRid' in target &&
341
- typeof (target as { disconnectRid: unknown }).disconnectRid === 'function';
342
- }
343
-
344
- function closeSocketEndpoints(target: unknown, boundEndpoints: Set<string>, connectedEndpoints: Set<string>): void {
345
- for (const endpoint of connectedEndpoints) {
346
- try {
347
- (target as { disconnect(endpoint: string): void }).disconnect(endpoint);
348
- } catch (error) {
349
- if (!isEndpointCloseIgnorableError(error)) {
350
- throw error;
351
- }
352
- }
353
- connectedEndpoints.delete(endpoint);
354
- }
355
- for (const endpoint of boundEndpoints) {
356
- try {
357
- (target as { unbind(endpoint: string): void }).unbind(endpoint);
358
- } catch (error) {
359
- if (!isEndpointCloseIgnorableError(error)) {
360
- throw error;
361
- }
362
- }
363
- boundEndpoints.delete(endpoint);
364
- }
365
- }
366
-
367
321
  export function isEndpointCloseIgnorableError(error: unknown): boolean {
368
322
  return isContextTerminatedError(error) || (
369
323
  error instanceof Error && 'code' in error &&
@@ -21,6 +21,7 @@ export interface ZLinkRawMonitorRecord {
21
21
  }
22
22
 
23
23
  export interface ZLinkRawSocketPort {
24
+ setReadableHandler(handler: () => void): void;
24
25
  bind(endpoint: string): void;
25
26
  unbind(endpoint: string): void;
26
27
  connect(endpoint: string): void;
@@ -68,10 +68,22 @@ export function isBackendNotConnectedError(error: unknown): boolean {
68
68
  const result = error.result;
69
69
  return result === SubmitResult.NotConnected || result === RequestResult.NotConnected;
70
70
  }
71
+
72
+ export function isBackendRequestTimeoutError(error: unknown): boolean {
73
+ return isZLinkBackendResultError(error)
74
+ && error.operation === 'request'
75
+ && error.result === RequestResult.TimedOut;
76
+ }
71
77
  export type ZLinkBackendMessageLike = Message | Buffer | Uint8Array | string;
78
+ /** Binding의 SendSubmission과 구조적으로 호환된다. binding 타입을 import 하지 않는다. */
79
+ export interface ZLinkBackendSendSubmission {
80
+ readonly admitted: Promise<void>;
81
+ }
82
+
72
83
  export interface ZLinkBackendSendSubmitBuilder {
73
84
  message(message: ZLinkBackendMessageLike): ZLinkBackendSendSubmitBuilder;
74
- submit(): Promise<void>;
85
+ // 제출 스냅샷을 그대로 돌려준다. admission을 기다리려면 .admitted를 await 한다.
86
+ submit(): ZLinkBackendSendSubmission;
75
87
  }
76
88
 
77
89
  export interface ZLinkBackendSendBuilder {
@@ -115,7 +115,7 @@ export class ZLinkChannelRequestDispatcher {
115
115
  if (received.send === undefined) {
116
116
  throw new ZLinkConfigurationException('Routed SPOT packet is missing a local SPOT delivery context.');
117
117
  }
118
- await appendParts(received.send(), received.parts).submit();
118
+ await appendParts(received.send(), received.parts).submit().admitted;
119
119
  return true;
120
120
  }
121
121
  if (received.parts.length === 0 || received.parts[0].data().length === 0) {
@@ -523,7 +523,7 @@ export class ZLinkRoutePacketDispatcher {
523
523
  if (received.send === undefined) {
524
524
  throw new ZLinkConfigurationException('Routed SPOT packet is missing a local SPOT delivery context.');
525
525
  }
526
- return appendParts(received.send(), received.parts).submit();
526
+ return appendParts(received.send(), received.parts).submit().admitted;
527
527
  }
528
528
  return false;
529
529
  }