@zlink-systems/framework 0.27.0 → 0.29.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 +2 -1
- package/dist/contracts/Configuration/Configs.d.ts +0 -1
- package/dist/contracts/Configuration/InternalDefaults.d.ts +3 -0
- package/dist/contracts/Configuration/InternalDefaults.js +4 -1
- package/dist/contracts/Configuration/RegistrationBuilders.js +9 -0
- package/dist/contracts/Configuration/RegistrationNormalizers.d.ts +1 -0
- package/dist/contracts/Configuration/RegistrationNormalizers.js +16 -0
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +3 -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-mailbox.d.ts +2 -2
- package/dist/runtime/actors/actor-mailbox.js +2 -2
- 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-raw-mesh-backend.js +1 -3
- 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/execution/serial-execution-queue.d.ts +12 -3
- package/dist/runtime/execution/serial-execution-queue.js +116 -28
- package/dist/runtime/foundation/operation-registry.d.ts +3 -2
- package/dist/runtime/foundation/operation-registry.js +5 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +17 -11
- package/dist/runtime/foundation/service-authority-payload-codec.d.ts +0 -2
- package/dist/runtime/foundation/service-authority-payload-codec.js +0 -43
- package/dist/runtime/foundation/service-stateful-registry.d.ts +4 -3
- package/dist/runtime/foundation/service-stateful-registry.js +5 -2
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -8
- package/dist/runtime/foundation/service-stateful-runtime.js +78 -126
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -11
- package/dist/runtime/foundation/service-stateful-wire-codec.js +1 -23
- package/dist/runtime/foundation/service-topology-registry.d.ts +5 -0
- package/dist/runtime/foundation/service-topology-registry.js +16 -17
- 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/instance-activation-authority.d.ts +0 -1
- package/dist/runtime/host/instance-activation-authority.js +46 -97
- 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 +47 -87
- package/dist/runtime/host/stateful-authority-route-runtime.d.ts +1 -0
- package/dist/runtime/host/stateful-authority-route-runtime.js +17 -9
- package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
- package/dist/runtime/locations/in-memory-authority-store.d.ts +2 -0
- package/dist/runtime/locations/in-memory-authority-store.js +22 -8
- package/dist/runtime/locations/in-memory-location-store.d.ts +1 -0
- package/dist/runtime/locations/in-memory-location-store.js +3 -0
- package/dist/runtime/locations/internal-store-contracts.d.ts +1 -1
- package/dist/runtime/locations/location-store-repository.d.ts +1 -0
- package/dist/runtime/locations/location-store-repository.js +98 -53
- 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/spots/spot-serial-executor.js +4 -1
- package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
- package/dist/runtime/spots/spot-serial-turn-executor.js +5 -0
- 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 -3
- package/dist/runtime/streams/index.js +6 -5
- 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/protocol.js +0 -9
- 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 -8
- package/dist/runtime/streams/session-context.js +3 -32
- package/dist/runtime/streams/session-serial-executor.d.ts +0 -1
- package/dist/runtime/streams/session-serial-executor.js +0 -3
- package/dist/runtime/streams/stream-message-utils.d.ts +0 -1
- package/dist/runtime/streams/stream-message-utils.js +0 -20
- package/dist/runtime/streams/stream-session-runtime.d.ts +6 -3
- package/dist/runtime/streams/stream-session-runtime.js +40 -85
- 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 +2 -1
- package/src/contracts/Configuration/Configs.ts +0 -1
- package/src/contracts/Configuration/InternalDefaults.ts +4 -0
- package/src/contracts/Configuration/RegistrationBuilders.ts +13 -3
- package/src/contracts/Configuration/RegistrationNormalizers.ts +25 -0
- package/src/contracts/Configuration/RegistrationTypes.ts +3 -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-mailbox.ts +7 -2
- 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-raw-mesh-backend.ts +1 -7
- 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/execution/serial-execution-queue.ts +117 -29
- package/src/runtime/foundation/operation-registry.ts +16 -9
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +17 -14
- package/src/runtime/foundation/service-authority-payload-codec.ts +0 -46
- package/src/runtime/foundation/service-stateful-registry.ts +10 -5
- package/src/runtime/foundation/service-stateful-runtime.ts +103 -181
- package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -25
- package/src/runtime/foundation/service-topology-registry.ts +30 -20
- package/src/runtime/host/actor-packet-relay.ts +8 -15
- package/src/runtime/host/index.ts +2 -26
- package/src/runtime/host/instance-activation-authority.ts +58 -125
- package/src/runtime/host/remote-bound-session-relay.ts +8 -16
- package/src/runtime/host/spot-address-transport.ts +107 -166
- package/src/runtime/host/stateful-authority-route-runtime.ts +22 -9
- package/src/runtime/locations/domain-store-contract.ts +5 -0
- package/src/runtime/locations/in-memory-authority-store.ts +42 -8
- package/src/runtime/locations/in-memory-location-store.ts +8 -0
- package/src/runtime/locations/internal-store-contracts.ts +1 -0
- package/src/runtime/locations/location-store-repository.ts +130 -68
- package/src/runtime/messaging/request-deadline.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +18 -4
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
- package/src/runtime/spots/spot-outbound.ts +14 -24
- package/src/runtime/spots/spot-serial-executor.ts +4 -1
- package/src/runtime/spots/spot-serial-turn-executor.ts +10 -0
- 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 +5 -5
- package/src/runtime/streams/managed-stream.ts +3 -13
- package/src/runtime/streams/native-fallback-bound-session.ts +13 -25
- package/src/runtime/streams/protocol.ts +0 -13
- package/src/runtime/streams/session-calls.ts +8 -34
- package/src/runtime/streams/session-context.ts +6 -47
- package/src/runtime/streams/session-serial-executor.ts +0 -8
- package/src/runtime/streams/stream-message-utils.ts +1 -27
- package/src/runtime/streams/stream-session-runtime.ts +54 -97
- package/dist/runtime/streams/session-requests.d.ts +0 -25
- package/dist/runtime/streams/session-requests.js +0 -101
- package/src/runtime/streams/session-requests.ts +0 -110
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ServiceRelocationAuthorityPayloadCodec } from '../foundation/service-relocation-runtime';
|
|
1
2
|
import { UINT64_MAX } from '@zlink-systems/stream-wire';
|
|
2
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
4
|
import { zlinkRuntimeDefaultLocationOptions } from '../../contracts/Locations/Options';
|
|
@@ -17,6 +18,8 @@ import {
|
|
|
17
18
|
type ZLinkStoreScanCursor,
|
|
18
19
|
type ZLinkStoreVersion,
|
|
19
20
|
type ZLinkStoreWriteRequest,
|
|
21
|
+
ZLinkFrameworkException,
|
|
22
|
+
ZLinkFrameworkErrorKind,
|
|
20
23
|
ZLinkFrameworkRuntimeState,
|
|
21
24
|
ZLinkObjectRole
|
|
22
25
|
} from '../../contracts';
|
|
@@ -204,7 +207,30 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
204
207
|
private readonly nowProvider: () => Date = () => new Date()
|
|
205
208
|
) {
|
|
206
209
|
super(nowProvider);
|
|
207
|
-
|
|
210
|
+
// Classify only failures of the opaque SPI, before interpreting its records.
|
|
211
|
+
this.provider = {
|
|
212
|
+
async read(key, signal) {
|
|
213
|
+
try {
|
|
214
|
+
return await provider.read(key, signal);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
throw locationStoreProviderFailure(error, signal);
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
async write(request, signal) {
|
|
220
|
+
try {
|
|
221
|
+
return await provider.write(request, signal);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
throw locationStoreProviderFailure(error, signal);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
async scan(request, signal) {
|
|
227
|
+
try {
|
|
228
|
+
return await provider.scan(request, signal);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
throw locationStoreProviderFailure(error, signal);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
208
234
|
this.aggregateInventory = new ZLinkAggregateInventoryStore(this.provider);
|
|
209
235
|
}
|
|
210
236
|
|
|
@@ -1099,6 +1125,77 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1099
1125
|
}
|
|
1100
1126
|
}
|
|
1101
1127
|
|
|
1128
|
+
override async releaseEndedReservation(
|
|
1129
|
+
key: ZLinkAuthorityKey,
|
|
1130
|
+
expectedStoreVersion: string,
|
|
1131
|
+
signal?: AbortSignal
|
|
1132
|
+
): Promise<boolean> {
|
|
1133
|
+
const rowKey = authorityKey(key.value);
|
|
1134
|
+
const current = await this.provider.read(rowKey, signal);
|
|
1135
|
+
if (current.kind === 'missing' || current.value.version.value !== expectedStoreVersion)
|
|
1136
|
+
return false;
|
|
1137
|
+
const record = decodeAuthorityRecord(current.value.bytes);
|
|
1138
|
+
const snapshot = record.snapshot;
|
|
1139
|
+
if (
|
|
1140
|
+
snapshot.allocation.state !== 'reserved' ||
|
|
1141
|
+
snapshot.pendingCreation === undefined ||
|
|
1142
|
+
record.aggregate !== undefined ||
|
|
1143
|
+
hasRelocationAuthority(snapshot.payload)
|
|
1144
|
+
)
|
|
1145
|
+
return false;
|
|
1146
|
+
const leaseKey = ownerKey(snapshot.ownerId);
|
|
1147
|
+
const descriptorKey = meshKey(
|
|
1148
|
+
snapshot.allocation.descriptor.meshName,
|
|
1149
|
+
snapshot.allocation.descriptor.rid
|
|
1150
|
+
);
|
|
1151
|
+
const capacityRowKey = capacityKey(
|
|
1152
|
+
snapshot.allocation.descriptor.meshName,
|
|
1153
|
+
String(snapshot.allocation.descriptor.rid)
|
|
1154
|
+
);
|
|
1155
|
+
const [lease, descriptor, capacity] = await Promise.all([
|
|
1156
|
+
this.provider.read(leaseKey, signal),
|
|
1157
|
+
this.provider.read(descriptorKey, signal),
|
|
1158
|
+
this.provider.read(capacityRowKey, signal)
|
|
1159
|
+
]);
|
|
1160
|
+
if (lease.kind === 'found' && lease.value.expiresAt === undefined)
|
|
1161
|
+
throw new Error('Location Store owner lease record is invalid.');
|
|
1162
|
+
if (
|
|
1163
|
+
sameLiveOwner(lease, snapshot) &&
|
|
1164
|
+
descriptor.kind === 'found' &&
|
|
1165
|
+
reviveMeshDescriptor(
|
|
1166
|
+
decodeCanonicalDescriptorRecord<ZLinkMeshNodeDescriptor>(descriptor.value.bytes).descriptor
|
|
1167
|
+
).lifecycleGeneration === snapshot.allocation.descriptorLifecycleGeneration
|
|
1168
|
+
)
|
|
1169
|
+
return false;
|
|
1170
|
+
const mutations: ZLinkStoreWriteRequest['mutations'][number][] = [
|
|
1171
|
+
{ kind: 'delete', key: rowKey }
|
|
1172
|
+
];
|
|
1173
|
+
if (capacity.kind === 'found') {
|
|
1174
|
+
const stored = decodeJson<CapacityRecord>(capacity.value.bytes);
|
|
1175
|
+
mutations.push({
|
|
1176
|
+
kind: 'put',
|
|
1177
|
+
key: capacityRowKey,
|
|
1178
|
+
bytes: encodeJson({
|
|
1179
|
+
active: stored.active,
|
|
1180
|
+
pending: subtractCapacity(stored.pending, snapshot.allocation.capacity)
|
|
1181
|
+
} satisfies CapacityRecord)
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const result = await this.provider.write(
|
|
1185
|
+
{
|
|
1186
|
+
conditions: [
|
|
1187
|
+
{ kind: 'version', key: rowKey, expected: current.value.version },
|
|
1188
|
+
conditionFor(leaseKey, lease),
|
|
1189
|
+
conditionFor(descriptorKey, descriptor),
|
|
1190
|
+
conditionFor(capacityRowKey, capacity)
|
|
1191
|
+
],
|
|
1192
|
+
mutations
|
|
1193
|
+
},
|
|
1194
|
+
signal
|
|
1195
|
+
);
|
|
1196
|
+
return result.kind === 'applied';
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1102
1199
|
override async reserve(
|
|
1103
1200
|
request: ZLinkObjectReserveRequest,
|
|
1104
1201
|
signal?: AbortSignal,
|
|
@@ -1130,62 +1227,13 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1130
1227
|
return { kind: 'alreadyExists', current: snapshot };
|
|
1131
1228
|
}
|
|
1132
1229
|
if (
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
// The row is Reserved by another owner. An unfinished creation
|
|
1141
|
-
// whose owner lease ended is cancellable, so reclaim it and retry
|
|
1142
|
-
// instead of blocking the key forever.
|
|
1143
|
-
const staleOwnerKey = ownerKey(snapshot.ownerId);
|
|
1144
|
-
const staleCapacityKey = capacityKey(
|
|
1145
|
-
snapshot.allocation.descriptor.meshName,
|
|
1146
|
-
String(snapshot.allocation.descriptor.rid)
|
|
1147
|
-
);
|
|
1148
|
-
const [staleOwnerRead, staleCapacityRead] = await Promise.all([
|
|
1149
|
-
this.provider.read(staleOwnerKey, signal),
|
|
1150
|
-
this.provider.read(staleCapacityKey, signal)
|
|
1151
|
-
]);
|
|
1152
|
-
if (staleOwnerRead.kind === 'found' && staleOwnerRead.value.expiresAt === undefined) {
|
|
1153
|
-
// A lease is always written with a positive TTL, so a missing
|
|
1154
|
-
// expiry is a corrupt record. Reclaiming deletes authority state,
|
|
1155
|
-
// so refuse rather than read the absence as expiry.
|
|
1156
|
-
throw new Error('Location Store owner lease record is invalid.');
|
|
1157
|
-
}
|
|
1158
|
-
if (sameLiveOwner(staleOwnerRead, record.snapshot)) {
|
|
1230
|
+
!(await this.releaseEndedReservation(
|
|
1231
|
+
encodedAuthorityKey,
|
|
1232
|
+
current.value.version.value,
|
|
1233
|
+
signal
|
|
1234
|
+
))
|
|
1235
|
+
)
|
|
1159
1236
|
return { kind: 'conflict', current: snapshot };
|
|
1160
|
-
}
|
|
1161
|
-
const staleCapacity =
|
|
1162
|
-
staleCapacityRead.kind === 'missing'
|
|
1163
|
-
? emptyCapacityRecord()
|
|
1164
|
-
: decodeJson<CapacityRecord>(staleCapacityRead.value.bytes);
|
|
1165
|
-
await this.provider.write(
|
|
1166
|
-
{
|
|
1167
|
-
conditions: [
|
|
1168
|
-
{ kind: 'version', key: rowKey, expected: current.value.version },
|
|
1169
|
-
versionCondition(staleOwnerKey, staleOwnerRead),
|
|
1170
|
-
conditionFor(staleCapacityKey, staleCapacityRead)
|
|
1171
|
-
],
|
|
1172
|
-
mutations: [
|
|
1173
|
-
{ kind: 'delete', key: rowKey },
|
|
1174
|
-
{
|
|
1175
|
-
kind: 'put',
|
|
1176
|
-
key: staleCapacityKey,
|
|
1177
|
-
bytes: encodeJson({
|
|
1178
|
-
active: staleCapacity.active,
|
|
1179
|
-
pending: subtractCapacity(
|
|
1180
|
-
staleCapacity.pending,
|
|
1181
|
-
record.snapshot.allocation.capacity
|
|
1182
|
-
)
|
|
1183
|
-
} satisfies CapacityRecord)
|
|
1184
|
-
}
|
|
1185
|
-
]
|
|
1186
|
-
},
|
|
1187
|
-
signal
|
|
1188
|
-
);
|
|
1189
1237
|
continue;
|
|
1190
1238
|
}
|
|
1191
1239
|
const [descriptorRead, leaseRead] = await Promise.all([
|
|
@@ -1193,7 +1241,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1193
1241
|
this.provider.read(leaseKey, signal)
|
|
1194
1242
|
]);
|
|
1195
1243
|
const descriptor = liveTargetDescriptor(descriptorRead, leaseRead, request.target);
|
|
1196
|
-
if (descriptor === undefined) {
|
|
1244
|
+
if (descriptor === undefined || descriptor.state !== ZLinkFrameworkRuntimeState.Serving) {
|
|
1197
1245
|
return { kind: 'conflict', current: { kind: 'missing', storeNow: current.storeNow } };
|
|
1198
1246
|
}
|
|
1199
1247
|
const [capacityRead, objectGenerationRead, authorityOwnerGenerationRead] = await Promise.all([
|
|
@@ -1394,9 +1442,11 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1394
1442
|
) {
|
|
1395
1443
|
return { kind: 'stale' };
|
|
1396
1444
|
}
|
|
1445
|
+
const descriptorKey = meshKey(request.target.meshName, request.target.nodeRid);
|
|
1397
1446
|
const leaseKey = ownerKey(request.target.owner.ownerId);
|
|
1398
1447
|
const capacityRowKey = capacityKey(request.target.meshName, String(request.target.nodeRid));
|
|
1399
|
-
const [leaseRead, capacityRead] = await Promise.all([
|
|
1448
|
+
const [descriptorRead, leaseRead, capacityRead] = await Promise.all([
|
|
1449
|
+
this.provider.read(descriptorKey, signal),
|
|
1400
1450
|
this.provider.read(leaseKey, signal),
|
|
1401
1451
|
this.provider.read(capacityRowKey, signal)
|
|
1402
1452
|
]);
|
|
@@ -1406,7 +1456,8 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1406
1456
|
// rather than read the absence as expiry.
|
|
1407
1457
|
throw new Error('Location Store owner lease record is invalid.');
|
|
1408
1458
|
}
|
|
1409
|
-
if (
|
|
1459
|
+
if (liveTargetDescriptor(descriptorRead, leaseRead, request.target) === undefined)
|
|
1460
|
+
return { kind: 'stale' };
|
|
1410
1461
|
const capacity =
|
|
1411
1462
|
capacityRead.kind === 'missing'
|
|
1412
1463
|
? emptyCapacityRecord()
|
|
@@ -1415,6 +1466,7 @@ export class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationStore {
|
|
|
1415
1466
|
{
|
|
1416
1467
|
conditions: [
|
|
1417
1468
|
{ kind: 'version', key: rowKey, expected: current.value.version },
|
|
1469
|
+
versionCondition(descriptorKey, descriptorRead),
|
|
1418
1470
|
leaseValueCondition(leaseKey, {
|
|
1419
1471
|
ownerId: record.snapshot.ownerId,
|
|
1420
1472
|
leaseGeneration: record.snapshot.ownerLeaseGeneration
|
|
@@ -3904,7 +3956,6 @@ function liveTargetDescriptor(
|
|
|
3904
3956
|
descriptor.ownerId === target.owner.ownerId &&
|
|
3905
3957
|
descriptor.leaseGeneration === target.owner.leaseGeneration &&
|
|
3906
3958
|
descriptor.objectRole === ZLinkObjectRole.Server &&
|
|
3907
|
-
descriptor.state === ZLinkFrameworkRuntimeState.Serving &&
|
|
3908
3959
|
lease.ownerId === target.owner.ownerId &&
|
|
3909
3960
|
BigInt(lease.leaseGeneration) === target.owner.leaseGeneration &&
|
|
3910
3961
|
leaseRead.value.expiresAt !== undefined &&
|
|
@@ -4034,15 +4085,10 @@ function sameCreationTarget(
|
|
|
4034
4085
|
);
|
|
4035
4086
|
}
|
|
4036
4087
|
|
|
4037
|
-
const
|
|
4088
|
+
const relocationAuthorityCodec = new ServiceRelocationAuthorityPayloadCodec();
|
|
4038
4089
|
|
|
4039
|
-
function
|
|
4040
|
-
return (
|
|
4041
|
-
payload.byteLength >= CANONICAL_AUTHORITY_MAGIC.byteLength &&
|
|
4042
|
-
Buffer.from(payload.buffer, payload.byteOffset, CANONICAL_AUTHORITY_MAGIC.byteLength).equals(
|
|
4043
|
-
CANONICAL_AUTHORITY_MAGIC
|
|
4044
|
-
)
|
|
4045
|
-
);
|
|
4090
|
+
function hasRelocationAuthority(payload: Uint8Array): boolean {
|
|
4091
|
+
return relocationAuthorityCodec.read(payload) !== undefined;
|
|
4046
4092
|
}
|
|
4047
4093
|
|
|
4048
4094
|
function sameLiveOwner(lease: ZLinkStoreReadResult, snapshot: StoredAuthoritySnapshot): boolean {
|
|
@@ -4438,3 +4484,19 @@ function throwIfOperationExpired(signal?: AbortSignal, deadlineUnixMs?: bigint):
|
|
|
4438
4484
|
throw new DOMException('Operation deadline exceeded.', 'TimeoutError');
|
|
4439
4485
|
}
|
|
4440
4486
|
}
|
|
4487
|
+
|
|
4488
|
+
// Store SPI §6: preserve caller failures and classify provider failures once.
|
|
4489
|
+
function locationStoreProviderFailure(error: unknown, signal?: AbortSignal): unknown {
|
|
4490
|
+
if (
|
|
4491
|
+
error instanceof ZLinkFrameworkException ||
|
|
4492
|
+
error instanceof TypeError ||
|
|
4493
|
+
error instanceof RangeError ||
|
|
4494
|
+
signal?.aborted === true
|
|
4495
|
+
)
|
|
4496
|
+
return error;
|
|
4497
|
+
return new ZLinkFrameworkException(
|
|
4498
|
+
ZLinkFrameworkErrorKind.Unavailable,
|
|
4499
|
+
'Location Store provider is unavailable.',
|
|
4500
|
+
error
|
|
4501
|
+
);
|
|
4502
|
+
}
|
|
@@ -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,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// <auto-generated> DO NOT EDIT. schema-sha256:
|
|
1
|
+
// <auto-generated> DO NOT EDIT. schema-sha256: 818fcd2f767793be8b5f626e5ac688807e671e546af2b11786e6fbaa02010ba5
|
|
2
2
|
export interface ServiceWireRouteFence { readonly id: string; readonly generation: bigint; readonly targetNodeRid: Uint8Array; readonly targetNodeGeneration: bigint; readonly expectedAuthorityOwnerGeneration: bigint; readonly expectedOwnerLeaseGeneration: bigint; }
|
|
3
3
|
export interface ApplicationPayloadEnvelopeV1 { readonly packetName: string; readonly contentType: string; readonly payload: Uint8Array; }
|
|
4
4
|
export interface ActorJoin28 { readonly correlation: bigint; readonly actor: ServiceWireRouteFence; readonly entry: boolean; readonly targetSpot: ServiceWireRouteFence; readonly payload?: ApplicationPayloadEnvelopeV1; }
|
|
@@ -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>(
|
|
@@ -134,7 +134,10 @@ export class ZLinkSpotSerialExecutor {
|
|
|
134
134
|
this.throwIfClosing();
|
|
135
135
|
let executor = this.actorExecutors.get(actorId);
|
|
136
136
|
if (executor === undefined) {
|
|
137
|
-
executor =
|
|
137
|
+
executor =
|
|
138
|
+
this.executionMode === ZLinkUserSpotExecutionMode.SpotWide
|
|
139
|
+
? this.spotSerial.createActorExecutor(actorId, this.sourceSpotId, this.actorOptions)
|
|
140
|
+
: new ZLinkActorSerialExecutor(actorId, this.sourceSpotId, this.actorOptions);
|
|
138
141
|
this.actorExecutors.set(actorId, executor);
|
|
139
142
|
}
|
|
140
143
|
return executor;
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type ZLinkSerialWorkRecord
|
|
20
20
|
} from '../execution/serial-execution-queue';
|
|
21
21
|
import type { ZLinkSerialLifecycleContext } from '../execution/serial-execution-queue';
|
|
22
|
+
import { ZLinkActorSerialExecutor } from '../actors/actor-mailbox';
|
|
22
23
|
|
|
23
24
|
export type ZLinkSpotApplicationTurnContext = ZLinkExecutionBarrierClaim & {
|
|
24
25
|
readonly replay?: (failure?: unknown) => Promise<unknown> | unknown;
|
|
@@ -53,6 +54,15 @@ export class ZLinkSpotSerialTurnExecutor {
|
|
|
53
54
|
return this.depth > 0;
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
/** Creates a passive Actor mailbox consumed by this Spot's scheduler. */
|
|
58
|
+
createActorExecutor(
|
|
59
|
+
actorId: string,
|
|
60
|
+
sourceSpotId: unknown,
|
|
61
|
+
options?: ZLinkSerialSchedulerOptions
|
|
62
|
+
): ZLinkActorSerialExecutor {
|
|
63
|
+
return new ZLinkActorSerialExecutor(actorId, sourceSpotId, options, this.scheduler);
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
get isCurrentTurn(): boolean {
|
|
57
67
|
return this.depth > 0 && isCurrentZLinkSpotSerialTurn(this);
|
|
58
68
|
}
|