@zlink-systems/framework 0.18.1 → 0.20.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/Configuration/Builders.d.ts +0 -2
- package/dist/contracts/Configuration/Configs.d.ts +1 -0
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -2
- package/dist/contracts/Locations/Authority.d.ts +1 -7
- package/dist/runtime/actors/actor-authority-publication.js +25 -22
- package/dist/runtime/actors/actor-creation.js +30 -9
- package/dist/runtime/actors/actor-runtime-state.d.ts +3 -0
- package/dist/runtime/actors/index.d.ts +3 -0
- package/dist/runtime/actors/index.js +14 -3
- package/dist/runtime/admission.d.ts +2 -0
- package/dist/runtime/admission.js +11 -5
- package/dist/runtime/backend/contracts/index.d.ts +4 -1
- package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -0
- package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
- package/dist/runtime/backend/node/node-raw-binding-port.d.ts +2 -1
- package/dist/runtime/backend/node/node-raw-binding-port.js +12 -5
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +1 -1
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -0
- package/dist/runtime/channels/channel-socket-options.js +7 -0
- package/dist/runtime/channels/channel-socket-registry.js +3 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +1 -1
- package/dist/runtime/foundation/service-stateful-runtime.js +1 -5
- package/dist/runtime/host/actor-placement-coordinator.d.ts +14 -5
- package/dist/runtime/host/actor-placement-coordinator.js +159 -47
- package/dist/runtime/host/index.d.ts +2 -1
- package/dist/runtime/host/index.js +77 -120
- package/dist/runtime/host/location-runtime-owner.js +4 -2
- package/dist/runtime/host/remote-actor-join-receiver.js +12 -3
- package/dist/runtime/locations/creation-operation-id.d.ts +4 -0
- package/dist/runtime/locations/creation-operation-id.js +12 -0
- package/dist/runtime/locations/in-memory-authority-store.js +8 -22
- package/dist/runtime/locations/location-store-repository.js +36 -59
- package/dist/runtime/locations/opaque-record-key.d.ts +5 -0
- package/dist/runtime/locations/opaque-record-key.js +16 -0
- package/dist/runtime/locations/runtime.d.ts +7 -0
- package/dist/runtime/locations/runtime.js +130 -42
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1672 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +9169 -0
- package/dist/runtime/spots/spot-node-runtime-manager.js +2 -2
- package/package.json +2 -2
- package/src/contracts/Configuration/Builders.ts +0 -2
- package/src/contracts/Configuration/Configs.ts +1 -0
- package/src/contracts/Configuration/RegistrationTypes.ts +1 -2
- package/src/contracts/Locations/Authority.ts +1 -8
- package/src/runtime/actors/actor-authority-publication.ts +25 -22
- package/src/runtime/actors/actor-creation.ts +45 -11
- package/src/runtime/actors/actor-runtime-state.ts +4 -0
- package/src/runtime/actors/index.ts +32 -4
- package/src/runtime/admission.ts +8 -5
- package/src/runtime/backend/contracts/index.ts +4 -1
- package/src/runtime/backend/node/node-mesh-backend-adapter.ts +2 -1
- package/src/runtime/backend/node/node-raw-binding-port.ts +16 -5
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +1 -1
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +7 -0
- package/src/runtime/channels/channel-socket-options.ts +9 -0
- package/src/runtime/channels/channel-socket-registry.ts +4 -0
- package/src/runtime/foundation/service-stateful-runtime.ts +2 -6
- package/src/runtime/host/actor-placement-coordinator.ts +216 -77
- package/src/runtime/host/index.ts +95 -135
- package/src/runtime/host/location-runtime-owner.ts +4 -2
- package/src/runtime/host/remote-actor-join-receiver.ts +15 -3
- package/src/runtime/locations/creation-operation-id.ts +11 -0
- package/src/runtime/locations/in-memory-authority-store.ts +7 -29
- package/src/runtime/locations/location-store-repository.ts +71 -69
- package/src/runtime/locations/opaque-record-key.ts +26 -0
- package/src/runtime/locations/runtime.ts +154 -60
- package/src/runtime/protocol/service_wire_codec.generated.ts +8302 -0
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
- package/src/runtime/spots/spot-node-runtime-manager.ts +2 -2
|
@@ -137,6 +137,7 @@ class ZLinkSpotNodeRuntimeManager {
|
|
|
137
137
|
const node = meshAdapter.createMeshNode(this.options.context, {
|
|
138
138
|
meshName: spotNodeName,
|
|
139
139
|
routingId,
|
|
140
|
+
receiveTimeoutMs: spotNode.router?.receiveTimeoutMs,
|
|
140
141
|
applicationJobQueue: this.applicationJobQueue,
|
|
141
142
|
applicationJobReceiveFlowFailureSink: this.options.applicationJobReceiveFlowFailureSink,
|
|
142
143
|
peerAdmissionSealed: () => this.options.peerAdmissionSealed?.(spotNodeName) ?? false
|
|
@@ -399,8 +400,7 @@ class ZLinkSpotNodeRuntimeManager {
|
|
|
399
400
|
await this.publishMeshNodeState(state, signal, meshName);
|
|
400
401
|
}
|
|
401
402
|
entrySpotId(meshName, registration) {
|
|
402
|
-
if (effectiveObjectRole(registration) !== contracts_1.ZLinkObjectRole.Server
|
|
403
|
-
|| registration.entrySpotType === undefined) {
|
|
403
|
+
if (effectiveObjectRole(registration) !== contracts_1.ZLinkObjectRole.Server) {
|
|
404
404
|
return undefined;
|
|
405
405
|
}
|
|
406
406
|
let entrySpotId = this.entrySpotIds.get(meshName);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zlink-systems/framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@opentelemetry/api": "^1.9.1",
|
|
21
21
|
"@opentelemetry/api-logs": "^0.221.0",
|
|
22
|
-
"@zlink-systems/stream-wire": "0.
|
|
22
|
+
"@zlink-systems/stream-wire": "0.20.0",
|
|
23
23
|
"@zlink-systems/zlink": "1.2.1"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -103,8 +103,6 @@ export interface ZLinkMeshChannelServerBuilder {
|
|
|
103
103
|
export interface ZLinkMeshNodeSocketConfig {
|
|
104
104
|
sendHighWaterMark: number;
|
|
105
105
|
receiveHighWaterMark: number;
|
|
106
|
-
mailboxMessageBudget: number;
|
|
107
|
-
mailboxByteBudget: number;
|
|
108
106
|
receiveTimeoutMs?: number;
|
|
109
107
|
sendTimeoutMs?: number;
|
|
110
108
|
}
|
|
@@ -198,8 +198,6 @@ export interface ZLinkClientCapabilityOptions {
|
|
|
198
198
|
readonly manualConnections?: readonly string[];
|
|
199
199
|
readonly sendHighWaterMark?: number;
|
|
200
200
|
readonly receiveHighWaterMark?: number;
|
|
201
|
-
readonly mailboxMessageBudget?: number;
|
|
202
|
-
readonly mailboxByteBudget?: number;
|
|
203
201
|
readonly sendTimeoutMs?: number;
|
|
204
202
|
readonly maxMessageSize?: number;
|
|
205
203
|
}
|
|
@@ -434,6 +432,7 @@ export interface ZLinkSpotRouterCapabilityOptions {
|
|
|
434
432
|
readonly routingId?: string;
|
|
435
433
|
readonly sendHighWaterMark?: number;
|
|
436
434
|
readonly receiveHighWaterMark?: number;
|
|
435
|
+
readonly receiveTimeoutMs?: number;
|
|
437
436
|
readonly sendTimeoutMs?: number;
|
|
438
437
|
}
|
|
439
438
|
|
|
@@ -154,12 +154,9 @@ export interface ZLinkCreationOperationIdentity {
|
|
|
154
154
|
readonly operationId: ZLinkCreationOperationId;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
export type ZLinkCreationTerminalState = 'created' | 'rejected' | 'failed';
|
|
158
|
-
|
|
159
157
|
export interface ZLinkCreationTerminalPublication {
|
|
160
158
|
readonly operation: ZLinkCreationOperationIdentity;
|
|
161
159
|
readonly terminalEnvelope: Uint8Array;
|
|
162
|
-
readonly terminalEnvelopeSha256: Uint8Array;
|
|
163
160
|
/**
|
|
164
161
|
* The original operation deadline. Providers retain the terminal for five
|
|
165
162
|
* minutes after this absolute instant.
|
|
@@ -168,19 +165,15 @@ export interface ZLinkCreationTerminalPublication {
|
|
|
168
165
|
}
|
|
169
166
|
|
|
170
167
|
export interface ZLinkCreationTerminalRecord {
|
|
171
|
-
readonly state: ZLinkCreationTerminalState;
|
|
172
168
|
readonly operation: ZLinkCreationOperationIdentity;
|
|
173
|
-
readonly reservationId: string;
|
|
174
|
-
readonly objectKind: ZLinkPlacementObjectKind;
|
|
175
169
|
readonly terminalEnvelope: Uint8Array;
|
|
176
|
-
readonly terminalEnvelopeSha256: Uint8Array;
|
|
177
170
|
readonly expiresAt: Date;
|
|
178
171
|
readonly storeNow: Date;
|
|
179
172
|
}
|
|
180
173
|
|
|
181
174
|
export type ZLinkCreationTerminalReadResult =
|
|
182
175
|
| { readonly kind: 'missing'; readonly storeNow: Date }
|
|
183
|
-
| { readonly kind: 'found'; readonly
|
|
176
|
+
| { readonly kind: 'found'; readonly terminalEnvelope: Uint8Array };
|
|
184
177
|
|
|
185
178
|
export interface ZLinkObjectReserveRequest {
|
|
186
179
|
readonly key: ZLinkObjectCreationKey;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createHash
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
2
|
import type {
|
|
3
3
|
ActorRef
|
|
4
4
|
} from '../../contracts';
|
|
@@ -6,6 +6,7 @@ import { ZLinkSpotKind } from '../../contracts';
|
|
|
6
6
|
import type { ZLinkLocationOwnerToken } from '../../contracts/Locations';
|
|
7
7
|
import type { ZLinkAuthoritySnapshot } from '../locations/internal-location-contracts';
|
|
8
8
|
import type { ZLinkObjectCreationStore } from '../locations/internal-store-contracts';
|
|
9
|
+
import { randomOperationId } from '../locations/creation-operation-id';
|
|
9
10
|
import {
|
|
10
11
|
actorRelocationAuthorityApplicationPayload,
|
|
11
12
|
decodeActorAuthorityPayload,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
replaceServiceRelocationAuthorityApplicationPayload,
|
|
19
20
|
serviceRelocationAuthorityApplicationPayload
|
|
20
21
|
} from '../foundation/service-relocation-runtime';
|
|
22
|
+
import { encodeCreationOperationTerminalV1 } from '../protocol/service_wire_codec.generated';
|
|
21
23
|
|
|
22
24
|
const CREATION_OPERATION_TIMEOUT_MS = 30_000;
|
|
23
25
|
|
|
@@ -74,12 +76,20 @@ export async function publishInitialActorAuthority(
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
try {
|
|
77
|
-
const terminalEnvelope = Buffer.from(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
const terminalEnvelope = Buffer.from(encodeCreationOperationTerminalV1({
|
|
80
|
+
terminalResult: 'ok',
|
|
81
|
+
failureCode: 'none',
|
|
82
|
+
hasCreation: 'true',
|
|
83
|
+
creation: {
|
|
84
|
+
createResult: 'created',
|
|
85
|
+
actor: {
|
|
86
|
+
actorId: identity.actor.actorId,
|
|
87
|
+
objectGeneration: identity.actor.objectGeneration
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
hasApplicationPayload: 'false'
|
|
91
|
+
}, { runtimePredicates: {} }));
|
|
92
|
+
const operationId = randomOperationId();
|
|
83
93
|
const completed = await store.completeCreation({
|
|
84
94
|
key: { kind: 'actor', globalId: identity.actor.actorId },
|
|
85
95
|
reservationId: reserved.reservationId,
|
|
@@ -92,13 +102,9 @@ export async function publishInitialActorAuthority(
|
|
|
92
102
|
operation: {
|
|
93
103
|
sourceNodeRid: identity.actor.nodeRid,
|
|
94
104
|
sourceNodeGeneration: identity.ownerNodeGeneration,
|
|
95
|
-
operationId
|
|
96
|
-
high: operationBytes.readBigUInt64BE(0),
|
|
97
|
-
low: operationBytes.readBigUInt64BE(8)
|
|
98
|
-
}
|
|
105
|
+
operationId
|
|
99
106
|
},
|
|
100
107
|
terminalEnvelope,
|
|
101
|
-
terminalEnvelopeSha256: createHash('sha256').update(terminalEnvelope).digest(),
|
|
102
108
|
operationDeadline: new Date(Date.now() + CREATION_OPERATION_TIMEOUT_MS)
|
|
103
109
|
}
|
|
104
110
|
}
|
|
@@ -111,16 +117,13 @@ export async function publishInitialActorAuthority(
|
|
|
111
117
|
requireActorAuthority(completed.ready, identity);
|
|
112
118
|
return completed.ready;
|
|
113
119
|
} catch (error) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
} catch {
|
|
122
|
-
// A completed creation cannot be aborted; the validated authority remains.
|
|
123
|
-
}
|
|
120
|
+
const aborted = await store.abort({
|
|
121
|
+
key: { kind: 'actor', globalId: identity.actor.actorId },
|
|
122
|
+
reservationId: reserved.reservationId,
|
|
123
|
+
expectedStoreVersion: reserved.creating.storeVersion.value,
|
|
124
|
+
target
|
|
125
|
+
}, signal);
|
|
126
|
+
if (aborted.kind === 'stale') throw error;
|
|
124
127
|
throw error;
|
|
125
128
|
}
|
|
126
129
|
}
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
RoutingId,
|
|
4
4
|
Type,
|
|
5
5
|
ZLinkActor,
|
|
6
|
+
ZLinkActorCreateResponse,
|
|
6
7
|
ZLinkActorFactory,
|
|
7
8
|
} from '../../contracts';
|
|
8
9
|
import type { ZLinkProviderResolver } from '../../contracts/Common/ZLinkProviderResolver';
|
|
@@ -53,10 +54,17 @@ export class ZLinkActorCreationCoordinator {
|
|
|
53
54
|
this.options.actorDestroyedCleanup?.(actorId);
|
|
54
55
|
state.clearAfterDestroy();
|
|
55
56
|
},
|
|
56
|
-
() => this.createActorAfterClaim(
|
|
57
|
+
() => this.createActorAfterClaim(
|
|
58
|
+
actorId,
|
|
59
|
+
actorType,
|
|
60
|
+
state,
|
|
61
|
+
createRequest,
|
|
62
|
+
true,
|
|
63
|
+
signal
|
|
64
|
+
)
|
|
57
65
|
);
|
|
58
66
|
if (activation.activated !== undefined) {
|
|
59
|
-
if (activation.activated.status
|
|
67
|
+
if (activation.activated.status !== 'created') {
|
|
60
68
|
await lifecycle.releaseActor(actorType, actorId);
|
|
61
69
|
return activation.activated;
|
|
62
70
|
}
|
|
@@ -77,7 +85,14 @@ export class ZLinkActorCreationCoordinator {
|
|
|
77
85
|
);
|
|
78
86
|
}
|
|
79
87
|
|
|
80
|
-
return await this.createActorAfterClaim(
|
|
88
|
+
return await this.createActorAfterClaim(
|
|
89
|
+
actorId,
|
|
90
|
+
actorType,
|
|
91
|
+
state,
|
|
92
|
+
createRequest,
|
|
93
|
+
claimLocation,
|
|
94
|
+
signal
|
|
95
|
+
);
|
|
81
96
|
}
|
|
82
97
|
|
|
83
98
|
async materializeTransferredActor(
|
|
@@ -122,27 +137,41 @@ export class ZLinkActorCreationCoordinator {
|
|
|
122
137
|
this.options.actorMeshNameProvider
|
|
123
138
|
));
|
|
124
139
|
const nativeActorNode = this.options.nativeActorNode ?? this.options.nativeActorNodeProvider?.();
|
|
140
|
+
let actor: ZLinkActor;
|
|
141
|
+
try {
|
|
142
|
+
actor = await factory.create(context, signal);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
await this.discardStagingActor(state, nativeActorNode);
|
|
145
|
+
return { status: 'failed', error };
|
|
146
|
+
}
|
|
147
|
+
let meshName: string;
|
|
148
|
+
let nodeRid: RoutingId | undefined;
|
|
125
149
|
try {
|
|
126
|
-
const actor = await factory.create(context, signal);
|
|
127
150
|
if (actor.context !== context || actor.context.actorId !== context.actorId) {
|
|
128
151
|
throw new ZLinkConfigurationException(
|
|
129
152
|
`Actor factory '${actorType}' must return an Actor bound to the exact supplied context.`
|
|
130
153
|
);
|
|
131
154
|
}
|
|
132
|
-
|
|
155
|
+
meshName = state.meshName ?? '';
|
|
133
156
|
if (meshName.length === 0 && state.nativeActorRef === undefined) {
|
|
134
157
|
throw new ZLinkConfigurationException(
|
|
135
158
|
`Actor '${actorId}' has no RouteMesh identity.`
|
|
136
159
|
);
|
|
137
160
|
}
|
|
138
|
-
let nodeRid: RoutingId | undefined;
|
|
139
161
|
if (nativeActorNode !== undefined) {
|
|
140
162
|
const actorRef = state.ensureNativeActorRef(nativeActorNode, createRequest.nativeRequest);
|
|
141
163
|
nodeRid = toFrameworkRoutingId(actorRef.nodeRid);
|
|
142
164
|
} else {
|
|
143
165
|
nodeRid = this.options.actorCreatedNodeRidProvider?.();
|
|
144
166
|
}
|
|
145
|
-
|
|
167
|
+
} catch (error) {
|
|
168
|
+
await this.discardStagingActor(state, nativeActorNode);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let response: ZLinkActorCreateResponse;
|
|
173
|
+
try {
|
|
174
|
+
response = nodeRid === undefined
|
|
146
175
|
? { accepted: true }
|
|
147
176
|
: await this.options.actorCreatedNotifier?.(
|
|
148
177
|
nodeRid,
|
|
@@ -150,11 +179,16 @@ export class ZLinkActorCreationCoordinator {
|
|
|
150
179
|
createRequest.callbackRequest,
|
|
151
180
|
signal
|
|
152
181
|
) ?? { accepted: true };
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
182
|
+
} catch (error) {
|
|
183
|
+
await this.discardStagingActor(state, nativeActorNode);
|
|
184
|
+
return { status: 'failed', error };
|
|
185
|
+
}
|
|
186
|
+
if (!response.accepted) {
|
|
187
|
+
await this.discardStagingActor(state, nativeActorNode);
|
|
188
|
+
return { status: 'rejected', reply: response.reply };
|
|
189
|
+
}
|
|
157
190
|
|
|
191
|
+
try {
|
|
158
192
|
state.bindActor(actor, context);
|
|
159
193
|
if (nativeActorNode !== undefined) {
|
|
160
194
|
const actorRef = state.nativeActorRef!;
|
|
@@ -379,6 +379,9 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
|
|
|
379
379
|
? { status: 'rejected' }
|
|
380
380
|
: { status: 'rejected', reply: result.reply };
|
|
381
381
|
}
|
|
382
|
+
if (result.status === 'failed') {
|
|
383
|
+
throw actorApplicationFailure(actorId, result.error);
|
|
384
|
+
}
|
|
382
385
|
return result.reply === undefined
|
|
383
386
|
? { status: result.status, actor: result.actorRef }
|
|
384
387
|
: { status: result.status, actor: result.actorRef, reply: result.reply };
|
|
@@ -720,12 +723,19 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
|
|
|
720
723
|
const operation = state.getOrStartCreation(
|
|
721
724
|
actorType,
|
|
722
725
|
failIfExists,
|
|
723
|
-
() => this.creation.createActor(
|
|
726
|
+
() => this.creation.createActor(
|
|
727
|
+
actorId,
|
|
728
|
+
actorType,
|
|
729
|
+
state,
|
|
730
|
+
createRequest,
|
|
731
|
+
claimLocation,
|
|
732
|
+
signal
|
|
733
|
+
)
|
|
724
734
|
);
|
|
725
735
|
if (operation.created) {
|
|
726
736
|
void operation.task.then(
|
|
727
737
|
(result) => {
|
|
728
|
-
if (result.status
|
|
738
|
+
if (result.status !== 'created') {
|
|
729
739
|
this.discardFailedState(actorId, state, operation.task);
|
|
730
740
|
}
|
|
731
741
|
},
|
|
@@ -745,7 +755,9 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
|
|
|
745
755
|
};
|
|
746
756
|
}
|
|
747
757
|
if (operation.created) {
|
|
748
|
-
return
|
|
758
|
+
return result.status === 'failed'
|
|
759
|
+
? { status: 'failed', error: result.error }
|
|
760
|
+
: { status: 'rejected', reply: result.reply };
|
|
749
761
|
}
|
|
750
762
|
} catch (error) {
|
|
751
763
|
if (operation.created) {
|
|
@@ -936,16 +948,32 @@ export type ZLinkActorLocalCreateResult =
|
|
|
936
948
|
| {
|
|
937
949
|
readonly status: 'rejected';
|
|
938
950
|
readonly reply?: unknown;
|
|
951
|
+
}
|
|
952
|
+
| {
|
|
953
|
+
readonly status: 'failed';
|
|
954
|
+
readonly error: unknown;
|
|
939
955
|
};
|
|
940
956
|
|
|
941
957
|
function requireCreatedActor(result: ZLinkActorLocalCreateResult, actorId: string): ZLinkActor {
|
|
942
|
-
if (result.status
|
|
958
|
+
if (result.status === 'existing' || result.status === 'created') return result.actor;
|
|
959
|
+
if (result.status === 'failed') {
|
|
960
|
+
throw actorApplicationFailure(actorId, result.error);
|
|
961
|
+
}
|
|
943
962
|
throw createInternalFrameworkException(
|
|
944
963
|
ZLinkFrameworkInternalErrorKind.ActorCreateRejected,
|
|
945
964
|
`Actor '${actorId}' create request was rejected.`
|
|
946
965
|
);
|
|
947
966
|
}
|
|
948
967
|
|
|
968
|
+
function actorApplicationFailure(actorId: string, error: unknown): ZLinkFrameworkException {
|
|
969
|
+
return createInternalFrameworkException(
|
|
970
|
+
ZLinkFrameworkInternalErrorKind.ActorCreateFailed,
|
|
971
|
+
`Actor '${actorId}' creation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
972
|
+
false,
|
|
973
|
+
error
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
|
|
949
977
|
async function waitForCreationRetry(signal?: AbortSignal): Promise<void> {
|
|
950
978
|
throwIfAborted(signal);
|
|
951
979
|
await new Promise<void>((resolve, reject) => {
|
package/src/runtime/admission.ts
CHANGED
|
@@ -2,7 +2,10 @@ import { ZLinkFrameworkInternalErrorKind, createInternalFrameworkException } fr
|
|
|
2
2
|
export class ZLinkRuntimeAdmissionGate {
|
|
3
3
|
private readonly meshes = new Map<string, ZLinkMeshAdmissionState>();
|
|
4
4
|
|
|
5
|
+
constructor(private readonly ownerAdmissionOpen: () => boolean = () => true) {}
|
|
6
|
+
|
|
5
7
|
get acceptsNewWork(): boolean {
|
|
8
|
+
if (!this.ownerAdmissionOpen()) return false;
|
|
6
9
|
for (const state of this.meshes.values()) {
|
|
7
10
|
if (state.sealed) return false;
|
|
8
11
|
}
|
|
@@ -23,7 +26,7 @@ export class ZLinkRuntimeAdmissionGate {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
accepts(meshName: string): boolean {
|
|
26
|
-
return !this.requireState(meshName).sealed;
|
|
29
|
+
return this.ownerAdmissionOpen() && !this.requireState(meshName).sealed;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
pending(meshName: string): number {
|
|
@@ -48,7 +51,7 @@ export class ZLinkRuntimeAdmissionGate {
|
|
|
48
51
|
|
|
49
52
|
claim(meshName: string, operation: string): ZLinkApplicationWorkClaim {
|
|
50
53
|
const state = this.requireState(meshName);
|
|
51
|
-
if (!state.sealed) {
|
|
54
|
+
if (this.ownerAdmissionOpen() && !state.sealed) {
|
|
52
55
|
state.active += 1;
|
|
53
56
|
let closed = false;
|
|
54
57
|
return {
|
|
@@ -65,7 +68,7 @@ export class ZLinkRuntimeAdmissionGate {
|
|
|
65
68
|
}
|
|
66
69
|
throw createInternalFrameworkException(
|
|
67
70
|
state.sealedReason,
|
|
68
|
-
`${operation} was rejected because
|
|
71
|
+
`${operation} was rejected because framework admission is closed.`
|
|
69
72
|
);
|
|
70
73
|
}
|
|
71
74
|
|
|
@@ -113,7 +116,7 @@ export class ZLinkRuntimeAdmissionGate {
|
|
|
113
116
|
meshName === undefined
|
|
114
117
|
? this.firstSealedReason()
|
|
115
118
|
: this.requireState(meshName).sealedReason,
|
|
116
|
-
`${operation} was rejected because
|
|
119
|
+
`${operation} was rejected because framework admission is closed.`
|
|
117
120
|
);
|
|
118
121
|
}
|
|
119
122
|
|
|
@@ -130,7 +133,7 @@ export class ZLinkRuntimeAdmissionGate {
|
|
|
130
133
|
reason === ZLinkFrameworkInternalErrorKind.RuntimeShutdown
|
|
131
134
|
? ZLinkFrameworkInternalErrorKind.RuntimeShutdown
|
|
132
135
|
: ZLinkFrameworkInternalErrorKind.ActorCreateRejected,
|
|
133
|
-
`Actor '${actorId}' create request was rejected because
|
|
136
|
+
`Actor '${actorId}' create request was rejected because framework admission is closed.`
|
|
134
137
|
);
|
|
135
138
|
}
|
|
136
139
|
|
|
@@ -157,7 +157,7 @@ export interface ZLinkBackendMeshNode {
|
|
|
157
157
|
): Promise<ServiceUserSpotOperationResult>;
|
|
158
158
|
requestActorCreate(
|
|
159
159
|
targetNodeRid: string,
|
|
160
|
-
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'
|
|
160
|
+
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'>,
|
|
161
161
|
timeoutMs: number
|
|
162
162
|
): Promise<ServiceUserSpotOperationResult>;
|
|
163
163
|
connectPeer(options: {
|
|
@@ -503,6 +503,7 @@ export interface ZLinkBackendDealerSocket extends ZLinkBackendConnectableSocket
|
|
|
503
503
|
peerWeight: number;
|
|
504
504
|
sendHighWaterMark: number;
|
|
505
505
|
receiveHighWaterMark: number;
|
|
506
|
+
receiveTimeoutMs: number;
|
|
506
507
|
sendTimeoutMs: number;
|
|
507
508
|
maxMessageSize: number;
|
|
508
509
|
send(message: Message | readonly Message[]): Promise<void>;
|
|
@@ -536,6 +537,7 @@ export interface ZLinkBackendRouterSocket extends ZLinkBackendConnectableSocket
|
|
|
536
537
|
peerWeight: number;
|
|
537
538
|
sendHighWaterMark: number;
|
|
538
539
|
receiveHighWaterMark: number;
|
|
540
|
+
receiveTimeoutMs: number;
|
|
539
541
|
sendTimeoutMs: number;
|
|
540
542
|
maxMessageSize: number;
|
|
541
543
|
setRoutingId(routingId: RoutingId): void;
|
|
@@ -740,6 +742,7 @@ export interface ZLinkMeshBackendAdapter {
|
|
|
740
742
|
options: {
|
|
741
743
|
readonly meshName: string;
|
|
742
744
|
readonly routingId?: RoutingId;
|
|
745
|
+
readonly receiveTimeoutMs?: number;
|
|
743
746
|
readonly trustProfile?: string;
|
|
744
747
|
readonly applicationJobQueue: import('../../application-jobs/contracts').ApplicationJobQueuePort;
|
|
745
748
|
readonly applicationJobReceiveFlowFailureSink?: (error: unknown) => void;
|
|
@@ -13,6 +13,7 @@ export class ZLinkNodeMeshBackendAdapter implements ZLinkMeshBackendAdapter {
|
|
|
13
13
|
options: {
|
|
14
14
|
readonly meshName: string;
|
|
15
15
|
readonly routingId?: string;
|
|
16
|
+
readonly receiveTimeoutMs?: number;
|
|
16
17
|
readonly trustProfile?: string;
|
|
17
18
|
readonly applicationJobQueue: import('../../application-jobs/contracts').ApplicationJobQueuePort;
|
|
18
19
|
readonly applicationJobReceiveFlowFailureSink?: (error: unknown) => void;
|
|
@@ -29,7 +30,7 @@ export class ZLinkNodeMeshBackendAdapter implements ZLinkMeshBackendAdapter {
|
|
|
29
30
|
return new ZLinkNodeRawMeshBackend(
|
|
30
31
|
options.meshName,
|
|
31
32
|
options.routingId,
|
|
32
|
-
new ZLinkNodeRawBindingPort(bindingContext),
|
|
33
|
+
new ZLinkNodeRawBindingPort(bindingContext, options.receiveTimeoutMs),
|
|
33
34
|
options.applicationJobQueue,
|
|
34
35
|
options.applicationJobReceiveFlowFailureSink,
|
|
35
36
|
options.peerAdmissionSealed
|
|
@@ -47,12 +47,16 @@ export type {
|
|
|
47
47
|
} from '../raw-binding-port';
|
|
48
48
|
|
|
49
49
|
export class ZLinkNodeRawBindingPort implements ZLinkRawBindingPort {
|
|
50
|
-
constructor(
|
|
50
|
+
constructor(
|
|
51
|
+
private readonly sharedContext?: Context,
|
|
52
|
+
private readonly routerReceiveTimeoutMs?: number
|
|
53
|
+
) {}
|
|
51
54
|
|
|
52
55
|
createHost(): ZLinkRawHostPort {
|
|
53
56
|
return new NodeRawHostPort(
|
|
54
57
|
this.sharedContext ?? createContext(),
|
|
55
|
-
this.sharedContext === undefined
|
|
58
|
+
this.sharedContext === undefined,
|
|
59
|
+
this.routerReceiveTimeoutMs
|
|
56
60
|
);
|
|
57
61
|
}
|
|
58
62
|
}
|
|
@@ -63,12 +67,16 @@ class NodeRawHostPort implements ZLinkRawHostPort {
|
|
|
63
67
|
|
|
64
68
|
constructor(
|
|
65
69
|
private readonly context: Context,
|
|
66
|
-
private readonly ownsContext: boolean
|
|
70
|
+
private readonly ownsContext: boolean,
|
|
71
|
+
private readonly routerReceiveTimeoutMs?: number
|
|
67
72
|
) {}
|
|
68
73
|
|
|
69
74
|
createRouter(): ZLinkRawRouterPort {
|
|
70
75
|
this.requireOpen();
|
|
71
|
-
return this.own(new NodeRawRouterPort(
|
|
76
|
+
return this.own(new NodeRawRouterPort(
|
|
77
|
+
createRouterSocket(this.context),
|
|
78
|
+
this.routerReceiveTimeoutMs
|
|
79
|
+
));
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
createDealer(): ZLinkRawDealerPort {
|
|
@@ -230,11 +238,14 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
230
238
|
}).disconnectRid(bindingRoutingId(routingId));
|
|
231
239
|
}
|
|
232
240
|
|
|
233
|
-
constructor(socket: RouterSocket) {
|
|
241
|
+
constructor(socket: RouterSocket, receiveTimeoutMs?: number) {
|
|
234
242
|
super(socket);
|
|
235
243
|
socket.options.handover = true;
|
|
236
244
|
socket.options.mandatory = true;
|
|
237
245
|
socket.options.probe = true;
|
|
246
|
+
if (receiveTimeoutMs !== undefined) {
|
|
247
|
+
socket.options.recvTimeout = receiveTimeoutMs;
|
|
248
|
+
}
|
|
238
249
|
}
|
|
239
250
|
|
|
240
251
|
localEndpoint(): string {
|
|
@@ -1008,7 +1008,7 @@ export class ZLinkNodeRawMeshBackend implements ZLinkBackendMeshNode {
|
|
|
1008
1008
|
|
|
1009
1009
|
requestActorCreate(
|
|
1010
1010
|
targetNodeRid: string,
|
|
1011
|
-
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'
|
|
1011
|
+
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'>,
|
|
1012
1012
|
timeoutMs: number
|
|
1013
1013
|
): Promise<ServiceUserSpotOperationResult> {
|
|
1014
1014
|
return this.requireStateful().requestActorCreate(targetNodeRid, request, timeoutMs);
|
|
@@ -32,6 +32,7 @@ export function wrapSocket<T extends { close(): void }>(
|
|
|
32
32
|
peerWeight?: number;
|
|
33
33
|
sendHwm?: number;
|
|
34
34
|
recvHwm?: number;
|
|
35
|
+
recvTimeout?: number;
|
|
35
36
|
sendTimeout?: number;
|
|
36
37
|
noDrop?: boolean;
|
|
37
38
|
maxMsgSize?: bigint;
|
|
@@ -129,6 +130,12 @@ export function wrapSocket<T extends { close(): void }>(
|
|
|
129
130
|
set receiveHighWaterMark(value: number) {
|
|
130
131
|
requireSocketOptions(socket).recvHwm = value;
|
|
131
132
|
},
|
|
133
|
+
get receiveTimeoutMs(): number {
|
|
134
|
+
return socket.options?.recvTimeout ?? 0;
|
|
135
|
+
},
|
|
136
|
+
set receiveTimeoutMs(value: number) {
|
|
137
|
+
requireSocketOptions(socket).recvTimeout = value;
|
|
138
|
+
},
|
|
132
139
|
get sendTimeoutMs(): number {
|
|
133
140
|
return socket.options?.sendTimeout ?? 0;
|
|
134
141
|
},
|
|
@@ -53,6 +53,15 @@ class ZLinkLiveSocketConfig implements ZLinkSocketConfig {
|
|
|
53
53
|
this.socket.receiveHighWaterMark = value;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
get receiveTimeoutMs(): number {
|
|
57
|
+
return this.socket.receiveTimeoutMs;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
set receiveTimeoutMs(value: number) {
|
|
61
|
+
requireValidSendTimeoutMs('receiveTimeoutMs', value);
|
|
62
|
+
this.socket.receiveTimeoutMs = value;
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
get sendTimeoutMs(): number {
|
|
57
66
|
return this.socket.sendTimeoutMs;
|
|
58
67
|
}
|
|
@@ -1854,6 +1854,7 @@ function applySocketConfig(
|
|
|
1854
1854
|
config: {
|
|
1855
1855
|
readonly sendHighWaterMark?: number;
|
|
1856
1856
|
readonly receiveHighWaterMark?: number;
|
|
1857
|
+
readonly receiveTimeoutMs?: number;
|
|
1857
1858
|
readonly sendTimeoutMs?: number;
|
|
1858
1859
|
readonly maxMessageSize?: number;
|
|
1859
1860
|
}
|
|
@@ -1864,6 +1865,9 @@ function applySocketConfig(
|
|
|
1864
1865
|
if (config.receiveHighWaterMark !== undefined) {
|
|
1865
1866
|
socket.receiveHighWaterMark = config.receiveHighWaterMark;
|
|
1866
1867
|
}
|
|
1868
|
+
if (config.receiveTimeoutMs !== undefined) {
|
|
1869
|
+
socket.receiveTimeoutMs = config.receiveTimeoutMs;
|
|
1870
|
+
}
|
|
1867
1871
|
if (config.sendTimeoutMs !== undefined) {
|
|
1868
1872
|
socket.sendTimeoutMs = config.sendTimeoutMs;
|
|
1869
1873
|
}
|
|
@@ -750,14 +750,10 @@ export class ServiceStatefulRuntime {
|
|
|
750
750
|
|
|
751
751
|
requestActorCreate(
|
|
752
752
|
targetNodeRid: string,
|
|
753
|
-
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'
|
|
753
|
+
request: Omit<ServiceActorCreateRecord, 'kind' | 'correlation'>,
|
|
754
754
|
timeoutMs: number
|
|
755
755
|
): Promise<ServiceUserSpotOperationResult> {
|
|
756
756
|
const correlation = this.nextUserSpotOperation++;
|
|
757
|
-
const operation = {
|
|
758
|
-
high: this.nodeGeneration,
|
|
759
|
-
low: correlation
|
|
760
|
-
};
|
|
761
757
|
return this.requestUserSpotOperation(
|
|
762
758
|
targetNodeRid,
|
|
763
759
|
encodeActorCreateHeader({
|
|
@@ -765,7 +761,7 @@ export class ServiceStatefulRuntime {
|
|
|
765
761
|
sourceNodeRid: this.nodeRid,
|
|
766
762
|
sourceNodeGeneration: this.nodeGeneration,
|
|
767
763
|
correlation,
|
|
768
|
-
operation
|
|
764
|
+
operation: request.operation
|
|
769
765
|
}),
|
|
770
766
|
correlation,
|
|
771
767
|
'actorCreate',
|