@zlink-systems/framework 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Actors/ZLinkActorClient.d.ts +1 -1
- package/dist/contracts/Channels/Calls.d.ts +1 -1
- package/dist/contracts/Configuration/Builders.d.ts +0 -1
- package/dist/contracts/Configuration/Configs.d.ts +0 -1
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +0 -5
- package/dist/contracts/Configuration/RegistrationValidators.js +0 -2
- package/dist/contracts/Spots/Contracts.d.ts +1 -1
- package/dist/contracts/Streams/BoundSessionContracts.d.ts +1 -1
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -3
- package/dist/contracts/Streams/IZLinkSessionActor.d.ts +2 -2
- package/dist/runtime/actors/actor-client.js +7 -10
- package/dist/runtime/actors/actor-request-deadline.d.ts +1 -3
- package/dist/runtime/actors/actor-request-deadline.js +4 -29
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +2 -3
- package/dist/runtime/backend/contracts/index.d.ts +1 -4
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -0
- package/dist/runtime/backend/node/node-backend-adapter-support.js +35 -4
- 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 +1 -2
- package/dist/runtime/backend/node/node-raw-binding-port.js +10 -27
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
- package/dist/runtime/channels/channel-clients.js +8 -10
- package/dist/runtime/channels/channel-envelope.d.ts +1 -1
- package/dist/runtime/channels/channel-envelope.js +4 -10
- package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
- package/dist/runtime/channels/channel-outbound-operations.js +20 -36
- package/dist/runtime/channels/channel-runtime-manager.d.ts +4 -4
- package/dist/runtime/channels/channel-runtime-manager.js +8 -8
- package/dist/runtime/channels/channel-socket-options.js +0 -10
- package/dist/runtime/channels/channel-socket-registry.d.ts +1 -1
- package/dist/runtime/channels/channel-socket-registry.js +3 -14
- package/dist/runtime/channels/channel-transports.d.ts +10 -14
- package/dist/runtime/channels/channel-transports.js +11 -14
- package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.js +1 -3
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/router-socket-spot-route-transport.js +2 -2
- package/dist/runtime/channels/source-spot-router.d.ts +1 -1
- package/dist/runtime/channels/source-spot-router.js +2 -4
- package/dist/runtime/channels/spot-node-route-transport.d.ts +1 -1
- package/dist/runtime/channels/spot-node-route-transport.js +2 -3
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +1 -1
- package/dist/runtime/channels/spot-route-bridge-transport.js +2 -2
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +2 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +11 -12
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +17 -11
- package/dist/runtime/host/actor-packet-relay.d.ts +2 -2
- package/dist/runtime/host/actor-packet-relay.js +8 -10
- package/dist/runtime/host/index.js +1 -15
- package/dist/runtime/host/remote-bound-session-relay.js +8 -8
- package/dist/runtime/host/spot-address-transport.d.ts +1 -9
- package/dist/runtime/host/spot-address-transport.js +46 -86
- package/dist/runtime/locations/location-store-repository.js +6 -4
- package/dist/runtime/messaging/request-deadline.d.ts +3 -0
- package/dist/runtime/messaging/request-deadline.js +39 -0
- package/dist/runtime/messaging/submission-result.d.ts +2 -1
- package/dist/runtime/messaging/submission-result.js +11 -4
- package/dist/runtime/spots/spot-outbound.d.ts +3 -5
- package/dist/runtime/spots/spot-outbound.js +12 -15
- package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -2
- package/dist/runtime/streams/bound-actor-relay-sender.js +14 -14
- package/dist/runtime/streams/bound-session-service.js +1 -1
- package/dist/runtime/streams/index.d.ts +2 -2
- package/dist/runtime/streams/index.js +2 -2
- package/dist/runtime/streams/managed-stream.d.ts +2 -2
- package/dist/runtime/streams/managed-stream.js +3 -5
- package/dist/runtime/streams/native-fallback-bound-session.js +13 -16
- package/dist/runtime/streams/session-calls.d.ts +5 -7
- package/dist/runtime/streams/session-calls.js +6 -23
- package/dist/runtime/streams/session-context.d.ts +4 -4
- package/dist/runtime/streams/session-context.js +3 -6
- package/package.json +3 -3
- package/src/contracts/Actors/ZLinkActorClient.ts +1 -1
- package/src/contracts/Channels/Calls.ts +1 -1
- package/src/contracts/Configuration/Builders.ts +0 -1
- package/src/contracts/Configuration/Configs.ts +0 -1
- package/src/contracts/Configuration/RegistrationBuilders.ts +0 -3
- package/src/contracts/Configuration/RegistrationTypes.ts +0 -5
- package/src/contracts/Configuration/RegistrationValidators.ts +0 -4
- package/src/contracts/Spots/Contracts.ts +1 -1
- package/src/contracts/Streams/BoundSessionContracts.ts +1 -1
- package/src/contracts/Streams/IZLinkSession.ts +2 -3
- package/src/contracts/Streams/IZLinkSessionActor.ts +2 -6
- package/src/runtime/actors/actor-client.ts +9 -15
- package/src/runtime/actors/actor-request-deadline.ts +4 -49
- package/src/runtime/actors/actor-routed-join-transport.ts +3 -5
- package/src/runtime/backend/contracts/index.ts +1 -8
- package/src/runtime/backend/node/node-backend-adapter-support.ts +45 -5
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +0 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +15 -41
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +1 -1
- package/src/runtime/channels/channel-clients.ts +9 -19
- package/src/runtime/channels/channel-envelope.ts +16 -28
- package/src/runtime/channels/channel-outbound-operations.ts +36 -38
- package/src/runtime/channels/channel-runtime-manager.ts +6 -28
- package/src/runtime/channels/channel-socket-options.ts +0 -13
- package/src/runtime/channels/channel-socket-registry.ts +3 -17
- package/src/runtime/channels/channel-transports.ts +7 -33
- package/src/runtime/channels/local-spot-route-transport.ts +1 -5
- package/src/runtime/channels/router-socket-spot-route-transport.ts +2 -6
- package/src/runtime/channels/source-spot-router.ts +2 -9
- package/src/runtime/channels/spot-node-route-transport.ts +2 -7
- package/src/runtime/channels/spot-route-bridge-transport.ts +5 -12
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +11 -30
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +17 -14
- package/src/runtime/host/actor-packet-relay.ts +8 -15
- package/src/runtime/host/index.ts +2 -26
- package/src/runtime/host/remote-bound-session-relay.ts +8 -16
- package/src/runtime/host/spot-address-transport.ts +106 -165
- package/src/runtime/locations/location-store-repository.ts +7 -4
- package/src/runtime/messaging/request-deadline.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +18 -4
- package/src/runtime/spots/spot-outbound.ts +14 -24
- package/src/runtime/streams/bound-actor-relay-sender.ts +12 -26
- package/src/runtime/streams/bound-session-service.ts +1 -1
- package/src/runtime/streams/index.ts +2 -4
- package/src/runtime/streams/managed-stream.ts +3 -13
- package/src/runtime/streams/native-fallback-bound-session.ts +13 -25
- package/src/runtime/streams/session-calls.ts +8 -34
- package/src/runtime/streams/session-context.ts +6 -15
|
@@ -55,12 +55,6 @@ export interface ZLinkHostSpotAddressTransportOptions {
|
|
|
55
55
|
readonly completions: (meshName: string) => ZLinkMeshCompletionTable | undefined;
|
|
56
56
|
readonly codecs?: ZLinkChannelEnvelopeCodecRegistry;
|
|
57
57
|
readonly defaultRequestTimeoutMs: number;
|
|
58
|
-
/** Internal one-way deadline policy; public calls do not expose this option. */
|
|
59
|
-
readonly defaultSendTimeoutMs?: number;
|
|
60
|
-
/** Resolves the send timeout for a configured Spot Mesh. */
|
|
61
|
-
readonly sendTimeoutMsForMesh?: (meshName: string) => number;
|
|
62
|
-
/** Resolves the send timeout for a resolved Spot route channel. */
|
|
63
|
-
readonly sendTimeoutMsForRouteChannel?: (routeChannelId: string) => number;
|
|
64
58
|
readonly dispatchErrors?: ZLinkDispatchErrorReporter;
|
|
65
59
|
}
|
|
66
60
|
|
|
@@ -93,7 +87,7 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
93
87
|
sendToSpotAddress(
|
|
94
88
|
spotId: RoutingId,
|
|
95
89
|
message: unknown,
|
|
96
|
-
call: ZLinkSpotAddressCallOptions
|
|
90
|
+
call: Omit<ZLinkSpotAddressCallOptions, 'timeoutMs' | 'signal'>
|
|
97
91
|
): Promise<ZLinkSubmitResult> {
|
|
98
92
|
// Call-scoped flow (spec 27 §4): the envelope encoders and the
|
|
99
93
|
// traceInstanceAddress points share one ambient flow that does not
|
|
@@ -107,157 +101,136 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
107
101
|
private async sendToSpotAddressScoped(
|
|
108
102
|
spotId: RoutingId,
|
|
109
103
|
message: unknown,
|
|
110
|
-
call: ZLinkSpotAddressCallOptions
|
|
104
|
+
call: Omit<ZLinkSpotAddressCallOptions, 'timeoutMs' | 'signal'>
|
|
111
105
|
): Promise<ZLinkSubmitResult> {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
106
|
+
const activationDeadlineUnixMs = BigInt(
|
|
107
|
+
Math.round(Date.now() + this.options.defaultRequestTimeoutMs)
|
|
108
|
+
);
|
|
109
|
+
const existing = await this.resolveExisting(spotId);
|
|
110
|
+
if (existing !== undefined) {
|
|
111
|
+
this.validateExisting(existing, call);
|
|
112
|
+
try {
|
|
113
|
+
const result = await this.options.routed.sendToSpot(existing, message, {
|
|
114
|
+
instanceSpot: call.instanceSpot,
|
|
115
|
+
metadata: call.metadata
|
|
116
|
+
});
|
|
117
|
+
if (result.status === ZLinkSubmitStatus.Submitted) {
|
|
118
|
+
this.traceInstanceAddress(
|
|
119
|
+
ZLinkMessageFlowOutcome.Sent,
|
|
120
|
+
ZLinkDispatchMessageKind.Send,
|
|
121
|
+
spotId,
|
|
122
|
+
message,
|
|
123
|
+
existing.routerChannelId,
|
|
124
|
+
existing.stableType,
|
|
125
|
+
existing.targetNodeRid
|
|
129
126
|
);
|
|
130
|
-
|
|
131
|
-
this.traceInstanceAddress(
|
|
132
|
-
ZLinkMessageFlowOutcome.Sent,
|
|
133
|
-
ZLinkDispatchMessageKind.Send,
|
|
134
|
-
spotId,
|
|
135
|
-
message,
|
|
136
|
-
existing.routerChannelId,
|
|
137
|
-
existing.stableType,
|
|
138
|
-
existing.targetNodeRid
|
|
139
|
-
);
|
|
140
|
-
} else {
|
|
141
|
-
this.traceInstanceAddress(
|
|
142
|
-
submitResultFlowOutcome(result.status),
|
|
143
|
-
ZLinkDispatchMessageKind.Send,
|
|
144
|
-
spotId,
|
|
145
|
-
message,
|
|
146
|
-
existing.routerChannelId,
|
|
147
|
-
existing.stableType,
|
|
148
|
-
existing.targetNodeRid,
|
|
149
|
-
submitResultReason(result.status)
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
if (
|
|
153
|
-
result.status === ZLinkSubmitStatus.TargetNotFound ||
|
|
154
|
-
result.status === ZLinkSubmitStatus.RouteNotConnected
|
|
155
|
-
) {
|
|
156
|
-
this.options.resolver()?.invalidate?.(spotId);
|
|
157
|
-
}
|
|
158
|
-
return result;
|
|
159
|
-
} catch (error) {
|
|
160
|
-
if (isSpotRouteRefreshError(error)) {
|
|
161
|
-
this.options.resolver()?.invalidate?.(spotId);
|
|
162
|
-
}
|
|
163
|
-
const reason = addressedInstanceErrorReason(error);
|
|
127
|
+
} else {
|
|
164
128
|
this.traceInstanceAddress(
|
|
165
|
-
|
|
166
|
-
? ZLinkMessageFlowOutcome.Backpressured
|
|
167
|
-
: ZLinkMessageFlowOutcome.Dropped,
|
|
129
|
+
submitResultFlowOutcome(result.status),
|
|
168
130
|
ZLinkDispatchMessageKind.Send,
|
|
169
131
|
spotId,
|
|
170
132
|
message,
|
|
171
133
|
existing.routerChannelId,
|
|
172
134
|
existing.stableType,
|
|
173
135
|
existing.targetNodeRid,
|
|
174
|
-
|
|
136
|
+
submitResultReason(result.status)
|
|
175
137
|
);
|
|
176
|
-
throw error;
|
|
177
138
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
spotId
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
call.instanceSpotType,
|
|
191
|
-
undefined,
|
|
192
|
-
ZLinkDispatchErrorReason.StaleTarget
|
|
193
|
-
);
|
|
194
|
-
return { status: ZLinkSubmitStatus.TargetNotFound };
|
|
195
|
-
}
|
|
196
|
-
if (selected.kind === 'capacity') {
|
|
197
|
-
const error = missingInstancePlacementCapacity(spotId, call.instanceSpotType);
|
|
139
|
+
if (
|
|
140
|
+
result.status === ZLinkSubmitStatus.TargetNotFound ||
|
|
141
|
+
result.status === ZLinkSubmitStatus.RouteNotConnected
|
|
142
|
+
) {
|
|
143
|
+
this.options.resolver()?.invalidate?.(spotId);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (isSpotRouteRefreshError(error)) {
|
|
148
|
+
this.options.resolver()?.invalidate?.(spotId);
|
|
149
|
+
}
|
|
150
|
+
const reason = addressedInstanceErrorReason(error);
|
|
198
151
|
this.traceInstanceAddress(
|
|
199
|
-
|
|
152
|
+
reason === ZLinkDispatchErrorReason.Backpressure
|
|
153
|
+
? ZLinkMessageFlowOutcome.Backpressured
|
|
154
|
+
: ZLinkMessageFlowOutcome.Dropped,
|
|
200
155
|
ZLinkDispatchMessageKind.Send,
|
|
201
156
|
spotId,
|
|
202
157
|
message,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
158
|
+
existing.routerChannelId,
|
|
159
|
+
existing.stableType,
|
|
160
|
+
existing.targetNodeRid,
|
|
161
|
+
reason
|
|
207
162
|
);
|
|
208
163
|
throw error;
|
|
209
164
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const sourceSpotId =
|
|
226
|
-
call.sourceSpot === undefined ? undefined : String(call.sourceSpot.routingId);
|
|
227
|
-
const mapped = classifySubmitResult(
|
|
228
|
-
await awaitWithAbort(
|
|
229
|
-
selected.node.sendToMissingInstanceSpot(
|
|
230
|
-
selected.target,
|
|
231
|
-
encoded,
|
|
232
|
-
BigInt(deadline.deadlineUnixMs),
|
|
233
|
-
sourceSpotId,
|
|
234
|
-
call.metadata
|
|
235
|
-
),
|
|
236
|
-
deadline.signal
|
|
237
|
-
),
|
|
238
|
-
'Instance Spot submission'
|
|
165
|
+
}
|
|
166
|
+
if (!call.instanceSpot) {
|
|
167
|
+
return { status: ZLinkSubmitStatus.TargetNotFound };
|
|
168
|
+
}
|
|
169
|
+
const selected = this.selectMissingTarget(spotId, call);
|
|
170
|
+
if (selected.kind === 'unsupported') {
|
|
171
|
+
this.traceInstanceAddress(
|
|
172
|
+
ZLinkMessageFlowOutcome.Dropped,
|
|
173
|
+
ZLinkDispatchMessageKind.Send,
|
|
174
|
+
spotId,
|
|
175
|
+
message,
|
|
176
|
+
call.initialMeshName,
|
|
177
|
+
call.instanceSpotType,
|
|
178
|
+
undefined,
|
|
179
|
+
ZLinkDispatchErrorReason.StaleTarget
|
|
239
180
|
);
|
|
181
|
+
return { status: ZLinkSubmitStatus.TargetNotFound };
|
|
182
|
+
}
|
|
183
|
+
if (selected.kind === 'capacity') {
|
|
184
|
+
const error = missingInstancePlacementCapacity(spotId, call.instanceSpotType);
|
|
240
185
|
this.traceInstanceAddress(
|
|
241
|
-
|
|
186
|
+
ZLinkMessageFlowOutcome.Backpressured,
|
|
242
187
|
ZLinkDispatchMessageKind.Send,
|
|
243
188
|
spotId,
|
|
244
189
|
message,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
? undefined
|
|
250
|
-
: submitResultReason(mapped.status)
|
|
190
|
+
call.initialMeshName,
|
|
191
|
+
call.instanceSpotType,
|
|
192
|
+
undefined,
|
|
193
|
+
ZLinkDispatchErrorReason.Backpressure
|
|
251
194
|
);
|
|
252
|
-
return mapped;
|
|
253
|
-
} catch (error) {
|
|
254
|
-
if (deadline.expired()) {
|
|
255
|
-
return { status: ZLinkSubmitStatus.TimedOut };
|
|
256
|
-
}
|
|
257
195
|
throw error;
|
|
258
|
-
} finally {
|
|
259
|
-
deadline.close();
|
|
260
196
|
}
|
|
197
|
+
if (selected.kind === 'unavailable') {
|
|
198
|
+
this.traceInstanceAddress(
|
|
199
|
+
ZLinkMessageFlowOutcome.Dropped,
|
|
200
|
+
ZLinkDispatchMessageKind.Send,
|
|
201
|
+
spotId,
|
|
202
|
+
message,
|
|
203
|
+
call.initialMeshName,
|
|
204
|
+
call.instanceSpotType,
|
|
205
|
+
undefined,
|
|
206
|
+
ZLinkDispatchErrorReason.StaleTarget
|
|
207
|
+
);
|
|
208
|
+
return { status: ZLinkSubmitStatus.RouteNotConnected };
|
|
209
|
+
}
|
|
210
|
+
const encoded = this.encode(ZLinkChannelMessageKind.Command, selected.meshName, message);
|
|
211
|
+
const sourceSpotId =
|
|
212
|
+
call.sourceSpot === undefined ? undefined : String(call.sourceSpot.routingId);
|
|
213
|
+
const mapped = classifySubmitResult(
|
|
214
|
+
await selected.node.sendToMissingInstanceSpot(
|
|
215
|
+
selected.target,
|
|
216
|
+
encoded,
|
|
217
|
+
activationDeadlineUnixMs,
|
|
218
|
+
sourceSpotId,
|
|
219
|
+
call.metadata
|
|
220
|
+
),
|
|
221
|
+
'Instance Spot submission'
|
|
222
|
+
);
|
|
223
|
+
this.traceInstanceAddress(
|
|
224
|
+
submitResultFlowOutcome(mapped.status),
|
|
225
|
+
ZLinkDispatchMessageKind.Send,
|
|
226
|
+
spotId,
|
|
227
|
+
message,
|
|
228
|
+
selected.meshName,
|
|
229
|
+
selected.target.stableType,
|
|
230
|
+
selected.target.targetNodeRid,
|
|
231
|
+
mapped.status === ZLinkSubmitStatus.Submitted ? undefined : submitResultReason(mapped.status)
|
|
232
|
+
);
|
|
233
|
+
return mapped;
|
|
261
234
|
}
|
|
262
235
|
|
|
263
236
|
requestToSpotAddress<TReply = unknown>(
|
|
@@ -642,22 +615,6 @@ export class ZLinkHostSpotAddressTransport implements ZLinkSpotAddressTransport
|
|
|
642
615
|
return { kind: 'unavailable' };
|
|
643
616
|
}
|
|
644
617
|
|
|
645
|
-
private sendTimeoutMsForMesh(meshName: string): number {
|
|
646
|
-
return (
|
|
647
|
-
this.options.sendTimeoutMsForMesh?.(meshName) ??
|
|
648
|
-
this.options.defaultSendTimeoutMs ??
|
|
649
|
-
this.options.defaultRequestTimeoutMs
|
|
650
|
-
);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
private sendTimeoutMsForRouteChannel(routeChannelId: string): number {
|
|
654
|
-
return (
|
|
655
|
-
this.options.sendTimeoutMsForRouteChannel?.(routeChannelId) ??
|
|
656
|
-
this.options.defaultSendTimeoutMs ??
|
|
657
|
-
this.options.defaultRequestTimeoutMs
|
|
658
|
-
);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
618
|
private validateExisting(
|
|
662
619
|
target: import('../spots/spot-routing-internal').ZLinkSpotRouteTarget,
|
|
663
620
|
call: ZLinkSpotAddressCallOptions
|
|
@@ -845,21 +802,9 @@ function addressedInstanceErrorReason(error: unknown): ZLinkDispatchErrorReason
|
|
|
845
802
|
return ZLinkDispatchErrorReason.HandlerException;
|
|
846
803
|
}
|
|
847
804
|
|
|
848
|
-
function initialSendTimeoutMs(
|
|
849
|
-
options: ZLinkHostSpotAddressTransportOptions,
|
|
850
|
-
call: ZLinkSpotAddressCallOptions
|
|
851
|
-
): number {
|
|
852
|
-
return call.initialMeshName === undefined
|
|
853
|
-
? (options.defaultSendTimeoutMs ?? options.defaultRequestTimeoutMs)
|
|
854
|
-
: (options.sendTimeoutMsForMesh?.(call.initialMeshName) ??
|
|
855
|
-
options.defaultSendTimeoutMs ??
|
|
856
|
-
options.defaultRequestTimeoutMs);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
805
|
interface ZLinkSpotAddressDeadline {
|
|
860
806
|
readonly deadlineUnixMs: number;
|
|
861
807
|
readonly signal: AbortSignal;
|
|
862
|
-
setOwnerTimeout(timeoutMs: number): void;
|
|
863
808
|
requireRemaining(): number;
|
|
864
809
|
expired(): boolean;
|
|
865
810
|
close(): void;
|
|
@@ -871,7 +816,7 @@ function createSpotAddressDeadline(
|
|
|
871
816
|
): ZLinkSpotAddressDeadline {
|
|
872
817
|
const startedAtMs = performance.now();
|
|
873
818
|
const startedAtUnixMs = Date.now();
|
|
874
|
-
|
|
819
|
+
const deadlineMs = startedAtMs + Math.max(0, timeoutMs);
|
|
875
820
|
const controller = new AbortController();
|
|
876
821
|
let expired = false;
|
|
877
822
|
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -897,10 +842,6 @@ function createSpotAddressDeadline(
|
|
|
897
842
|
return Math.round(startedAtUnixMs + (deadlineMs - startedAtMs));
|
|
898
843
|
},
|
|
899
844
|
signal: controller.signal,
|
|
900
|
-
setOwnerTimeout(ownerTimeoutMs: number) {
|
|
901
|
-
deadlineMs = startedAtMs + Math.max(0, ownerTimeoutMs);
|
|
902
|
-
arm();
|
|
903
|
-
},
|
|
904
845
|
requireRemaining() {
|
|
905
846
|
const remainingMs = deadlineMs - performance.now();
|
|
906
847
|
if (remainingMs <= 0) {
|
|
@@ -1193,7 +1193,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1193
1193
|
this.provider.read(leaseKey, signal)
|
|
1194
1194
|
]);
|
|
1195
1195
|
const descriptor = liveTargetDescriptor(descriptorRead, leaseRead, request.target);
|
|
1196
|
-
if (descriptor === undefined) {
|
|
1196
|
+
if (descriptor === undefined || descriptor.state !== ZLinkFrameworkRuntimeState.Serving) {
|
|
1197
1197
|
return { kind: 'conflict', current: { kind: 'missing', storeNow: current.storeNow } };
|
|
1198
1198
|
}
|
|
1199
1199
|
const [capacityRead, objectGenerationRead, authorityOwnerGenerationRead] = await Promise.all([
|
|
@@ -1394,9 +1394,11 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1394
1394
|
) {
|
|
1395
1395
|
return { kind: 'stale' };
|
|
1396
1396
|
}
|
|
1397
|
+
const descriptorKey = meshKey(request.target.meshName, request.target.nodeRid);
|
|
1397
1398
|
const leaseKey = ownerKey(request.target.owner.ownerId);
|
|
1398
1399
|
const capacityRowKey = capacityKey(request.target.meshName, String(request.target.nodeRid));
|
|
1399
|
-
const [leaseRead, capacityRead] = await Promise.all([
|
|
1400
|
+
const [descriptorRead, leaseRead, capacityRead] = await Promise.all([
|
|
1401
|
+
this.provider.read(descriptorKey, signal),
|
|
1400
1402
|
this.provider.read(leaseKey, signal),
|
|
1401
1403
|
this.provider.read(capacityRowKey, signal)
|
|
1402
1404
|
]);
|
|
@@ -1406,7 +1408,8 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1406
1408
|
// rather than read the absence as expiry.
|
|
1407
1409
|
throw new Error('Location Store owner lease record is invalid.');
|
|
1408
1410
|
}
|
|
1409
|
-
if (
|
|
1411
|
+
if (liveTargetDescriptor(descriptorRead, leaseRead, request.target) === undefined)
|
|
1412
|
+
return { kind: 'stale' };
|
|
1410
1413
|
const capacity =
|
|
1411
1414
|
capacityRead.kind === 'missing'
|
|
1412
1415
|
? emptyCapacityRecord()
|
|
@@ -1415,6 +1418,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1415
1418
|
{
|
|
1416
1419
|
conditions: [
|
|
1417
1420
|
{ kind: 'version', key: rowKey, expected: current.value.version },
|
|
1421
|
+
versionCondition(descriptorKey, descriptorRead),
|
|
1418
1422
|
leaseValueCondition(leaseKey, {
|
|
1419
1423
|
ownerId: record.snapshot.ownerId,
|
|
1420
1424
|
leaseGeneration: record.snapshot.ownerLeaseGeneration
|
|
@@ -3904,7 +3908,6 @@ function liveTargetDescriptor(
|
|
|
3904
3908
|
descriptor.ownerId === target.owner.ownerId &&
|
|
3905
3909
|
descriptor.leaseGeneration === target.owner.leaseGeneration &&
|
|
3906
3910
|
descriptor.objectRole === ZLinkObjectRole.Server &&
|
|
3907
|
-
descriptor.state === ZLinkFrameworkRuntimeState.Serving &&
|
|
3908
3911
|
lease.ownerId === target.owner.ownerId &&
|
|
3909
3912
|
BigInt(lease.leaseGeneration) === target.owner.leaseGeneration &&
|
|
3910
3913
|
leaseRead.value.expiresAt !== undefined &&
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { awaitWithAbort } from '../abort';
|
|
2
|
+
import {
|
|
3
|
+
createInternalFrameworkException,
|
|
4
|
+
ZLinkFrameworkInternalErrorKind
|
|
5
|
+
} from '../framework-errors-internal';
|
|
6
|
+
|
|
7
|
+
export function remainingRequestTimeout(
|
|
8
|
+
operation: string,
|
|
9
|
+
deadlineMs: number | undefined
|
|
10
|
+
): number | undefined {
|
|
11
|
+
if (deadlineMs === undefined) return undefined;
|
|
12
|
+
const remaining = deadlineMs - performance.now();
|
|
13
|
+
if (remaining <= 0) {
|
|
14
|
+
throw createInternalFrameworkException(
|
|
15
|
+
ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
|
|
16
|
+
`${operation} exceeded its deadline.`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return Math.max(1, Math.ceil(remaining));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Bounds caller waiting across outbound admission and reply; late completions stay observed. */
|
|
23
|
+
export async function waitRequestReply<T>(
|
|
24
|
+
reply: Promise<T>,
|
|
25
|
+
operation: string,
|
|
26
|
+
deadlineMs: number | undefined,
|
|
27
|
+
signal?: AbortSignal,
|
|
28
|
+
endWait?: () => void,
|
|
29
|
+
discardLateReply?: (reply: T) => void
|
|
30
|
+
): Promise<T> {
|
|
31
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
32
|
+
let waiting = reply;
|
|
33
|
+
if (deadlineMs !== undefined) {
|
|
34
|
+
const timeout = new Promise<never>((_resolve, reject) => {
|
|
35
|
+
const remaining = remainingRequestTimeout(operation, deadlineMs);
|
|
36
|
+
timer = setTimeout(
|
|
37
|
+
() =>
|
|
38
|
+
reject(
|
|
39
|
+
createInternalFrameworkException(
|
|
40
|
+
ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
|
|
41
|
+
`${operation} exceeded its deadline.`
|
|
42
|
+
)
|
|
43
|
+
),
|
|
44
|
+
remaining
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
waiting = Promise.race([reply, timeout]);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return await awaitWithAbort(waiting, signal);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
endWait?.();
|
|
53
|
+
if (discardLateReply !== undefined) void reply.then(discardLateReply, () => undefined);
|
|
54
|
+
throw error;
|
|
55
|
+
} finally {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -18,7 +18,7 @@ export interface ZLinkSubmitResult {
|
|
|
18
18
|
readonly status: ZLinkSubmitStatus;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/** Projects
|
|
21
|
+
/** Projects immediate refusal and pending admission failure from their Core phase. */
|
|
22
22
|
export function submitToRequestResult(result: number, phase: 'submit' | 'completion'): number {
|
|
23
23
|
switch (result) {
|
|
24
24
|
case SubmitResult.Ok:
|
|
@@ -28,7 +28,7 @@ export function submitToRequestResult(result: number, phase: 'submit' | 'complet
|
|
|
28
28
|
case SubmitResult.NotConnected:
|
|
29
29
|
return RequestResult.NotConnected;
|
|
30
30
|
case SubmitResult.NotFound:
|
|
31
|
-
return RequestResult.NotFound;
|
|
31
|
+
return phase === 'submit' ? RequestResult.NotFound : RequestResult.NotConnected;
|
|
32
32
|
case SubmitResult.NotAdmitted:
|
|
33
33
|
return RequestResult.Rejected;
|
|
34
34
|
case SubmitResult.InvalidHandle:
|
|
@@ -49,7 +49,7 @@ export function submitToRequestResult(result: number, phase: 'submit' | 'complet
|
|
|
49
49
|
export function classifySubmitResult(
|
|
50
50
|
result: number,
|
|
51
51
|
operation: string,
|
|
52
|
-
phase: 'submit' | 'completion' = '
|
|
52
|
+
phase: 'submit' | 'completion' = 'submit'
|
|
53
53
|
): ZLinkSubmitResult {
|
|
54
54
|
const terminal = submitToRequestResult(result, phase);
|
|
55
55
|
switch (terminal) {
|
|
@@ -80,12 +80,17 @@ export function requireOneWayCompletion(
|
|
|
80
80
|
case ZLinkSubmitStatus.Submitted:
|
|
81
81
|
return;
|
|
82
82
|
case ZLinkSubmitStatus.TimedOut:
|
|
83
|
-
case ZLinkSubmitStatus.Backpressured:
|
|
84
83
|
throw createInternalFrameworkException(
|
|
85
84
|
ZLinkFrameworkInternalErrorKind.DeadlineExceeded,
|
|
86
85
|
`${operation} did not obtain admission before its deadline.`,
|
|
87
86
|
true
|
|
88
87
|
);
|
|
88
|
+
case ZLinkSubmitStatus.Backpressured:
|
|
89
|
+
throw createInternalFrameworkException(
|
|
90
|
+
ZLinkFrameworkInternalErrorKind.RouteNotConnected,
|
|
91
|
+
`${operation} has no admission wait token.`,
|
|
92
|
+
true
|
|
93
|
+
);
|
|
89
94
|
case ZLinkSubmitStatus.TargetNotFound:
|
|
90
95
|
throw createInternalFrameworkException(notFoundKind, `${operation} target was not found.`);
|
|
91
96
|
case ZLinkSubmitStatus.RouteNotConnected:
|
|
@@ -106,6 +111,15 @@ export function requirePublishCompletion(result: ZLinkSubmitResult, operation: s
|
|
|
106
111
|
requireOneWayCompletion(result, operation);
|
|
107
112
|
}
|
|
108
113
|
|
|
114
|
+
export function requireClassicFanoutCompletion(result: ZLinkSubmitResult, operation: string): void {
|
|
115
|
+
requireOneWayCompletion(
|
|
116
|
+
result.status === ZLinkSubmitStatus.Backpressured
|
|
117
|
+
? { status: ZLinkSubmitStatus.TimedOut }
|
|
118
|
+
: result,
|
|
119
|
+
operation
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
export function throwAlreadySubmitted(operation: string): never {
|
|
110
124
|
throw createInternalFrameworkException(
|
|
111
125
|
ZLinkFrameworkInternalErrorKind.AlreadySubmitted,
|
|
@@ -191,7 +191,7 @@ export interface ZLinkSpotAddressTransport {
|
|
|
191
191
|
sendToSpotAddress(
|
|
192
192
|
spotId: RoutingId,
|
|
193
193
|
message: unknown,
|
|
194
|
-
options: ZLinkSpotAddressCallOptions
|
|
194
|
+
options: Omit<ZLinkSpotAddressCallOptions, 'timeoutMs' | 'signal'>
|
|
195
195
|
): Promise<ZLinkSubmitResult>;
|
|
196
196
|
requestToSpotAddress<TReply = unknown>(
|
|
197
197
|
spotId: RoutingId,
|
|
@@ -228,14 +228,12 @@ export interface ZLinkSpotRoutedTransport {
|
|
|
228
228
|
export interface ZLinkSpotRoutedSendOptions {
|
|
229
229
|
readonly instanceSpot?: boolean;
|
|
230
230
|
readonly packetName?: string;
|
|
231
|
-
/** Internal end-to-end budget remaining for route admission. */
|
|
232
|
-
readonly timeoutMs?: number;
|
|
233
|
-
readonly signal?: AbortSignal;
|
|
234
231
|
readonly metadata?: ReadonlyMap<string, string>;
|
|
235
232
|
}
|
|
236
233
|
|
|
237
234
|
export interface ZLinkSpotRoutedRequestOptions extends ZLinkSpotRoutedSendOptions {
|
|
238
235
|
readonly timeoutMs?: number;
|
|
236
|
+
readonly signal?: AbortSignal;
|
|
239
237
|
}
|
|
240
238
|
|
|
241
239
|
interface MutableAddressCallOptions {
|
|
@@ -283,13 +281,13 @@ function createAddressedSpotSendCall(
|
|
|
283
281
|
);
|
|
284
282
|
return this;
|
|
285
283
|
},
|
|
286
|
-
async submit(
|
|
284
|
+
async submit(): Promise<void> {
|
|
287
285
|
markSubmitted(options);
|
|
288
286
|
const pending = startRequestOnSerial(serial, () => ({
|
|
289
287
|
pending: transport.sendToSpotAddress(
|
|
290
288
|
spotId,
|
|
291
289
|
message,
|
|
292
|
-
freezeAddressCallOptions(options,
|
|
290
|
+
freezeAddressCallOptions(options, sourceSpotProvider?.())
|
|
293
291
|
)
|
|
294
292
|
}));
|
|
295
293
|
const result = await (serial.isCurrentTurn ? pending : deliverOnSerial(serial, pending));
|
|
@@ -314,11 +312,11 @@ function createAddressedSpotRequestCall(
|
|
|
314
312
|
markSubmitted(options);
|
|
315
313
|
rejectSameSpotAsyncRequest(serial, spotId, waitPolicy);
|
|
316
314
|
return startRequestOnSerial<TReply>(serial, () => ({
|
|
317
|
-
pending: transport.requestToSpotAddress<TReply>(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
)
|
|
315
|
+
pending: transport.requestToSpotAddress<TReply>(spotId, request, {
|
|
316
|
+
...freezeAddressCallOptions(options, sourceSpotProvider?.()),
|
|
317
|
+
timeoutMs: options.timeoutMs,
|
|
318
|
+
signal
|
|
319
|
+
})
|
|
322
320
|
}));
|
|
323
321
|
};
|
|
324
322
|
return {
|
|
@@ -422,7 +420,6 @@ function markSubmitted(options: MutableAddressCallOptions): void {
|
|
|
422
420
|
|
|
423
421
|
function freezeAddressCallOptions(
|
|
424
422
|
options: MutableAddressCallOptions,
|
|
425
|
-
signal: AbortSignal | undefined,
|
|
426
423
|
sourceSpot: ZLinkBackendSpot | undefined
|
|
427
424
|
): ZLinkSpotAddressCallOptions {
|
|
428
425
|
return {
|
|
@@ -430,8 +427,6 @@ function freezeAddressCallOptions(
|
|
|
430
427
|
instanceSpot: options.instanceSpot,
|
|
431
428
|
instanceSpotType: options.instanceSpotType,
|
|
432
429
|
initialMeshName: options.initialMeshName,
|
|
433
|
-
timeoutMs: options.timeoutMs,
|
|
434
|
-
signal,
|
|
435
430
|
sourceSpot
|
|
436
431
|
};
|
|
437
432
|
}
|
|
@@ -453,8 +448,8 @@ function wrapSendCall(serial: ZLinkSpotSerialTurnExecutor, inner: ZLinkSendCall)
|
|
|
453
448
|
else inner.metadata(key);
|
|
454
449
|
return this;
|
|
455
450
|
},
|
|
456
|
-
async submit(
|
|
457
|
-
const result = await runInternalTransportStart(serial, () => inner.submit(
|
|
451
|
+
async submit() {
|
|
452
|
+
const result = await runInternalTransportStart(serial, () => inner.submit());
|
|
458
453
|
return result;
|
|
459
454
|
}
|
|
460
455
|
};
|
|
@@ -548,11 +543,10 @@ function wrapRoutedSpotSendCall(
|
|
|
548
543
|
}
|
|
549
544
|
return this;
|
|
550
545
|
},
|
|
551
|
-
async submit(
|
|
546
|
+
async submit(): Promise<void> {
|
|
552
547
|
const pending = startRequestOnSerial(serial, () => ({
|
|
553
548
|
pending: sendToSpotHandle(transport, spot, message, {
|
|
554
549
|
metadata,
|
|
555
|
-
signal,
|
|
556
550
|
spotRouterChannelIdForMesh,
|
|
557
551
|
sourceSpot: sourceSpotProvider?.()
|
|
558
552
|
})
|
|
@@ -645,7 +639,7 @@ export async function sendToSpotHandle(
|
|
|
645
639
|
transport: ZLinkSpotRoutedTransport,
|
|
646
640
|
spot: SpotHandle,
|
|
647
641
|
message: unknown,
|
|
648
|
-
options: ZLinkSpotHandleCallOptions = {}
|
|
642
|
+
options: Omit<ZLinkSpotHandleCallOptions, 'timeoutMs' | 'signal'> = {}
|
|
649
643
|
): Promise<ZLinkSubmitResult> {
|
|
650
644
|
const packetName = resolveFrameworkPacketName(message, undefined, 'SPOT');
|
|
651
645
|
const sendResolved = async (resolved: ResolvedSpotHandle): Promise<ZLinkSubmitResult> => {
|
|
@@ -653,20 +647,16 @@ export async function sendToSpotHandle(
|
|
|
653
647
|
if (options.sourceSpot !== undefined && transport.sendFromSpotToSpot !== undefined) {
|
|
654
648
|
return transport.sendFromSpotToSpot(options.sourceSpot, target, message, {
|
|
655
649
|
packetName,
|
|
656
|
-
timeoutMs: options.timeoutMs,
|
|
657
|
-
signal: options.signal,
|
|
658
650
|
metadata: options.metadata
|
|
659
651
|
});
|
|
660
652
|
}
|
|
661
653
|
return transport.sendToSpot(target, message, {
|
|
662
654
|
packetName,
|
|
663
|
-
timeoutMs: options.timeoutMs,
|
|
664
|
-
signal: options.signal,
|
|
665
655
|
metadata: options.metadata
|
|
666
656
|
});
|
|
667
657
|
};
|
|
668
658
|
|
|
669
|
-
return sendResolved(await requireSpotRef(spot
|
|
659
|
+
return sendResolved(await requireSpotRef(spot));
|
|
670
660
|
}
|
|
671
661
|
|
|
672
662
|
export async function requestToSpotHandle<TReply = unknown>(
|