@cadenza.io/service 2.8.0 → 2.9.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/index.d.mts +61 -29
- package/dist/index.d.ts +61 -29
- package/dist/index.js +1218 -617
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1221 -618
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
Actor: () => import_core4.Actor,
|
|
33
34
|
DatabaseTask: () => DatabaseTask,
|
|
34
35
|
DebounceTask: () => import_core4.DebounceTask,
|
|
35
36
|
DeputyTask: () => DeputyTask,
|
|
@@ -2474,6 +2475,8 @@ var RestController = class _RestController {
|
|
|
2474
2475
|
constructor() {
|
|
2475
2476
|
this.fetchClientDiagnostics = /* @__PURE__ */ new Map();
|
|
2476
2477
|
this.diagnosticsErrorHistoryLimit = 100;
|
|
2478
|
+
this.diagnosticsMaxClientEntries = 500;
|
|
2479
|
+
this.destroyedDiagnosticsTtlMs = 15 * 6e4;
|
|
2477
2480
|
/**
|
|
2478
2481
|
* Fetches data from the given URL with a specified timeout. This function performs
|
|
2479
2482
|
* a fetch request with the ability to cancel the request if it exceeds the provided timeout duration.
|
|
@@ -3127,6 +3130,28 @@ var RestController = class _RestController {
|
|
|
3127
3130
|
if (!this._instance) this._instance = new _RestController();
|
|
3128
3131
|
return this._instance;
|
|
3129
3132
|
}
|
|
3133
|
+
pruneFetchClientDiagnostics(now = Date.now()) {
|
|
3134
|
+
for (const [fetchId, state] of this.fetchClientDiagnostics.entries()) {
|
|
3135
|
+
if (state.destroyed && now - state.updatedAt > this.destroyedDiagnosticsTtlMs) {
|
|
3136
|
+
this.fetchClientDiagnostics.delete(fetchId);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
if (this.fetchClientDiagnostics.size <= this.diagnosticsMaxClientEntries) {
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
const entriesByEvictionPriority = Array.from(
|
|
3143
|
+
this.fetchClientDiagnostics.entries()
|
|
3144
|
+
).sort((left, right) => {
|
|
3145
|
+
if (left[1].destroyed !== right[1].destroyed) {
|
|
3146
|
+
return left[1].destroyed ? -1 : 1;
|
|
3147
|
+
}
|
|
3148
|
+
return left[1].updatedAt - right[1].updatedAt;
|
|
3149
|
+
});
|
|
3150
|
+
while (this.fetchClientDiagnostics.size > this.diagnosticsMaxClientEntries && entriesByEvictionPriority.length > 0) {
|
|
3151
|
+
const [fetchId] = entriesByEvictionPriority.shift();
|
|
3152
|
+
this.fetchClientDiagnostics.delete(fetchId);
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3130
3155
|
resolveTransportDiagnosticsOptions(ctx) {
|
|
3131
3156
|
const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
|
|
3132
3157
|
const includeErrorHistory = Boolean(ctx.includeErrorHistory);
|
|
@@ -3139,6 +3164,8 @@ var RestController = class _RestController {
|
|
|
3139
3164
|
};
|
|
3140
3165
|
}
|
|
3141
3166
|
ensureFetchClientDiagnostics(fetchId, serviceName, url) {
|
|
3167
|
+
const now = Date.now();
|
|
3168
|
+
this.pruneFetchClientDiagnostics(now);
|
|
3142
3169
|
let state = this.fetchClientDiagnostics.get(fetchId);
|
|
3143
3170
|
if (!state) {
|
|
3144
3171
|
state = {
|
|
@@ -3158,13 +3185,14 @@ var RestController = class _RestController {
|
|
|
3158
3185
|
signalFailures: 0,
|
|
3159
3186
|
statusChecks: 0,
|
|
3160
3187
|
statusFailures: 0,
|
|
3161
|
-
updatedAt:
|
|
3188
|
+
updatedAt: now
|
|
3162
3189
|
};
|
|
3163
3190
|
this.fetchClientDiagnostics.set(fetchId, state);
|
|
3164
3191
|
} else {
|
|
3165
3192
|
state.serviceName = serviceName;
|
|
3166
3193
|
state.url = url;
|
|
3167
3194
|
}
|
|
3195
|
+
this.pruneFetchClientDiagnostics(now);
|
|
3168
3196
|
return state;
|
|
3169
3197
|
}
|
|
3170
3198
|
getErrorMessage(error) {
|
|
@@ -3196,6 +3224,7 @@ var RestController = class _RestController {
|
|
|
3196
3224
|
}
|
|
3197
3225
|
}
|
|
3198
3226
|
collectFetchTransportDiagnostics(ctx) {
|
|
3227
|
+
this.pruneFetchClientDiagnostics();
|
|
3199
3228
|
const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
|
|
3200
3229
|
const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
|
|
3201
3230
|
const states = Array.from(this.fetchClientDiagnostics.values()).sort(
|
|
@@ -3312,55 +3341,225 @@ var waitForSocketConnection = async (socket, timeoutMs, createError) => {
|
|
|
3312
3341
|
|
|
3313
3342
|
// src/network/SocketController.ts
|
|
3314
3343
|
var SocketController = class _SocketController {
|
|
3315
|
-
/**
|
|
3316
|
-
* Constructs the `SocketServer`, setting up a WebSocket server with specific configurations,
|
|
3317
|
-
* including connection state recovery, rate limiting, CORS handling, and custom event handling.
|
|
3318
|
-
* This class sets up the communication infrastructure for scalable, resilient, and secure WebSocket-based interactions
|
|
3319
|
-
* using metadata-driven task execution with `Cadenza`.
|
|
3320
|
-
*
|
|
3321
|
-
* It provides support for:
|
|
3322
|
-
* - Origin-based access control for connections.
|
|
3323
|
-
* - Optional payload sanitization.
|
|
3324
|
-
* - Configurable rate limiting and behavior on limit breaches (soft/hard disconnects).
|
|
3325
|
-
* - Event handlers for connection, handshake, delegation, signaling, status checks, and disconnection.
|
|
3326
|
-
*
|
|
3327
|
-
* The server can handle both internal and external interactions depending on the provided configurations,
|
|
3328
|
-
* and integrates directly with Cadenza's task workflow engine.
|
|
3329
|
-
*
|
|
3330
|
-
* Initializes the `SocketServer` to be ready for WebSocket communication.
|
|
3331
|
-
*/
|
|
3332
3344
|
constructor() {
|
|
3333
|
-
this.socketClientDiagnostics = /* @__PURE__ */ new Map();
|
|
3334
3345
|
this.diagnosticsErrorHistoryLimit = 100;
|
|
3346
|
+
this.diagnosticsMaxClientEntries = 500;
|
|
3347
|
+
this.destroyedDiagnosticsTtlMs = 15 * 6e4;
|
|
3348
|
+
this.socketServerDefaultKey = "socket-server-default";
|
|
3349
|
+
this.socketServerActor = CadenzaService.createActor(
|
|
3350
|
+
{
|
|
3351
|
+
name: "SocketServerActor",
|
|
3352
|
+
description: "Holds durable socket server session state and runtime socket server handle",
|
|
3353
|
+
defaultKey: this.socketServerDefaultKey,
|
|
3354
|
+
keyResolver: (input) => this.resolveSocketServerKey(input),
|
|
3355
|
+
loadPolicy: "lazy",
|
|
3356
|
+
writeContract: "overwrite",
|
|
3357
|
+
initState: this.createInitialSocketServerSessionState(
|
|
3358
|
+
this.socketServerDefaultKey
|
|
3359
|
+
)
|
|
3360
|
+
},
|
|
3361
|
+
{ isMeta: true }
|
|
3362
|
+
);
|
|
3363
|
+
this.socketClientActor = CadenzaService.createActor(
|
|
3364
|
+
{
|
|
3365
|
+
name: "SocketClientActor",
|
|
3366
|
+
description: "Holds durable socket client session state and runtime socket connection handles",
|
|
3367
|
+
defaultKey: "socket-client-default",
|
|
3368
|
+
keyResolver: (input) => this.resolveSocketClientFetchId(input),
|
|
3369
|
+
loadPolicy: "lazy",
|
|
3370
|
+
writeContract: "overwrite",
|
|
3371
|
+
initState: this.createInitialSocketClientSessionState()
|
|
3372
|
+
},
|
|
3373
|
+
{ isMeta: true }
|
|
3374
|
+
);
|
|
3375
|
+
this.socketClientDiagnosticsActor = CadenzaService.createActor(
|
|
3376
|
+
{
|
|
3377
|
+
name: "SocketClientDiagnosticsActor",
|
|
3378
|
+
description: "Tracks socket client diagnostics snapshots per fetchId for transport observability",
|
|
3379
|
+
defaultKey: "socket-client-diagnostics",
|
|
3380
|
+
loadPolicy: "eager",
|
|
3381
|
+
writeContract: "overwrite",
|
|
3382
|
+
initState: {
|
|
3383
|
+
entries: {}
|
|
3384
|
+
}
|
|
3385
|
+
},
|
|
3386
|
+
{ isMeta: true }
|
|
3387
|
+
);
|
|
3388
|
+
this.registerDiagnosticsTasks();
|
|
3389
|
+
this.registerSocketServerTasks();
|
|
3390
|
+
this.registerSocketClientTasks();
|
|
3335
3391
|
CadenzaService.createMetaTask(
|
|
3336
3392
|
"Collect socket transport diagnostics",
|
|
3337
|
-
|
|
3393
|
+
this.socketClientDiagnosticsActor.task(
|
|
3394
|
+
({ state, input }) => this.collectSocketTransportDiagnostics(input, state.entries),
|
|
3395
|
+
{ mode: "read" }
|
|
3396
|
+
),
|
|
3338
3397
|
"Responds to distributed transport diagnostics inquiries with socket client data."
|
|
3339
3398
|
).respondsTo(META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT);
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3399
|
+
}
|
|
3400
|
+
static get instance() {
|
|
3401
|
+
if (!this._instance) this._instance = new _SocketController();
|
|
3402
|
+
return this._instance;
|
|
3403
|
+
}
|
|
3404
|
+
registerDiagnosticsTasks() {
|
|
3405
|
+
CadenzaService.createThrottledMetaTask(
|
|
3406
|
+
"SocketClientDiagnosticsActor.Upsert",
|
|
3407
|
+
this.socketClientDiagnosticsActor.task(
|
|
3408
|
+
({ state, input, setState }) => {
|
|
3409
|
+
const fetchId = String(input.fetchId ?? "").trim();
|
|
3410
|
+
if (!fetchId) {
|
|
3345
3411
|
return;
|
|
3346
3412
|
}
|
|
3347
|
-
const
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3413
|
+
const now = Date.now();
|
|
3414
|
+
const entries = { ...state.entries };
|
|
3415
|
+
const existing = entries[fetchId];
|
|
3416
|
+
const base = existing ? {
|
|
3417
|
+
...existing,
|
|
3418
|
+
errorHistory: [...existing.errorHistory]
|
|
3419
|
+
} : {
|
|
3420
|
+
fetchId,
|
|
3421
|
+
serviceName: String(input.serviceName ?? ""),
|
|
3422
|
+
url: String(input.url ?? ""),
|
|
3423
|
+
socketId: null,
|
|
3424
|
+
connected: false,
|
|
3425
|
+
handshake: false,
|
|
3426
|
+
reconnectAttempts: 0,
|
|
3427
|
+
connectErrors: 0,
|
|
3428
|
+
reconnectErrors: 0,
|
|
3429
|
+
socketErrors: 0,
|
|
3430
|
+
pendingDelegations: 0,
|
|
3431
|
+
pendingTimers: 0,
|
|
3432
|
+
destroyed: false,
|
|
3433
|
+
lastHandshakeAt: null,
|
|
3434
|
+
lastHandshakeError: null,
|
|
3435
|
+
lastDisconnectAt: null,
|
|
3436
|
+
lastError: null,
|
|
3437
|
+
lastErrorAt: 0,
|
|
3438
|
+
errorHistory: [],
|
|
3439
|
+
updatedAt: now
|
|
3440
|
+
};
|
|
3441
|
+
if (input.serviceName !== void 0) {
|
|
3442
|
+
base.serviceName = String(input.serviceName);
|
|
3443
|
+
}
|
|
3444
|
+
if (input.url !== void 0) {
|
|
3445
|
+
base.url = String(input.url);
|
|
3446
|
+
}
|
|
3447
|
+
const patch = input.patch && typeof input.patch === "object" ? input.patch : {};
|
|
3448
|
+
Object.assign(base, patch);
|
|
3449
|
+
base.fetchId = fetchId;
|
|
3450
|
+
base.updatedAt = now;
|
|
3451
|
+
const errorMessage = input.error !== void 0 ? this.getErrorMessage(input.error) : void 0;
|
|
3452
|
+
if (errorMessage) {
|
|
3453
|
+
base.lastError = errorMessage;
|
|
3454
|
+
base.lastErrorAt = now;
|
|
3455
|
+
base.errorHistory.push({
|
|
3456
|
+
at: new Date(now).toISOString(),
|
|
3457
|
+
message: errorMessage
|
|
3458
|
+
});
|
|
3459
|
+
if (base.errorHistory.length > this.diagnosticsErrorHistoryLimit) {
|
|
3460
|
+
base.errorHistory.splice(
|
|
3461
|
+
0,
|
|
3462
|
+
base.errorHistory.length - this.diagnosticsErrorHistoryLimit
|
|
3463
|
+
);
|
|
3357
3464
|
}
|
|
3465
|
+
}
|
|
3466
|
+
entries[fetchId] = base;
|
|
3467
|
+
this.pruneDiagnosticsEntries(entries, now);
|
|
3468
|
+
setState({ entries });
|
|
3469
|
+
},
|
|
3470
|
+
{ mode: "write" }
|
|
3471
|
+
),
|
|
3472
|
+
(context) => String(context?.fetchId ?? "default"),
|
|
3473
|
+
"Upserts socket client diagnostics in actor state."
|
|
3474
|
+
).doOn("meta.socket_client.diagnostics_upsert_requested");
|
|
3475
|
+
}
|
|
3476
|
+
registerSocketServerTasks() {
|
|
3477
|
+
CadenzaService.createThrottledMetaTask(
|
|
3478
|
+
"SocketServerActor.PatchSession",
|
|
3479
|
+
this.socketServerActor.task(
|
|
3480
|
+
({ state, input, setState }) => {
|
|
3481
|
+
const patch = input.patch && typeof input.patch === "object" ? input.patch : {};
|
|
3482
|
+
setState({
|
|
3483
|
+
...state,
|
|
3484
|
+
...patch,
|
|
3485
|
+
updatedAt: Date.now()
|
|
3486
|
+
});
|
|
3487
|
+
},
|
|
3488
|
+
{ mode: "write" }
|
|
3489
|
+
),
|
|
3490
|
+
(context) => String(context?.serverKey ?? this.socketServerDefaultKey),
|
|
3491
|
+
"Applies partial durable session updates for socket server actor."
|
|
3492
|
+
).doOn("meta.socket_server.session_patch_requested");
|
|
3493
|
+
CadenzaService.createMetaTask(
|
|
3494
|
+
"SocketServerActor.ClearRuntime",
|
|
3495
|
+
this.socketServerActor.task(
|
|
3496
|
+
({ setRuntimeState }) => {
|
|
3497
|
+
setRuntimeState(null);
|
|
3498
|
+
},
|
|
3499
|
+
{ mode: "write" }
|
|
3500
|
+
),
|
|
3501
|
+
"Clears socket server runtime handle after shutdown."
|
|
3502
|
+
).doOn("meta.socket_server.runtime_clear_requested");
|
|
3503
|
+
const setupSocketServerTask = CadenzaService.createMetaTask(
|
|
3504
|
+
"Setup SocketServer",
|
|
3505
|
+
this.socketServerActor.task(
|
|
3506
|
+
({ state, runtimeState, input, actor, setState, setRuntimeState, emit }) => {
|
|
3507
|
+
const serverKey = this.resolveSocketServerKey(input) ?? actor.key ?? this.socketServerDefaultKey;
|
|
3508
|
+
const shouldUseSocket = Boolean(input.__useSocket);
|
|
3509
|
+
if (!shouldUseSocket) {
|
|
3510
|
+
this.destroySocketServerRuntimeHandle(runtimeState);
|
|
3511
|
+
setRuntimeState(null);
|
|
3512
|
+
setState({
|
|
3513
|
+
...state,
|
|
3514
|
+
serverKey,
|
|
3515
|
+
useSocket: false,
|
|
3516
|
+
status: "inactive",
|
|
3517
|
+
connectionCount: 0,
|
|
3518
|
+
lastShutdownAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3519
|
+
updatedAt: Date.now()
|
|
3520
|
+
});
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
3523
|
+
let runtimeHandle = runtimeState;
|
|
3524
|
+
if (!runtimeHandle) {
|
|
3525
|
+
runtimeHandle = this.createSocketServerRuntimeHandleFromContext(input);
|
|
3526
|
+
setRuntimeState(runtimeHandle);
|
|
3527
|
+
}
|
|
3528
|
+
const profile = String(input.__securityProfile ?? state.securityProfile ?? "medium");
|
|
3529
|
+
const networkType = String(input.__networkType ?? state.networkType ?? "internal");
|
|
3530
|
+
const schedulePatch = (patch) => {
|
|
3531
|
+
CadenzaService.emit("meta.socket_server.session_patch_requested", {
|
|
3532
|
+
serverKey,
|
|
3533
|
+
patch
|
|
3534
|
+
});
|
|
3535
|
+
};
|
|
3536
|
+
if (runtimeHandle.initialized) {
|
|
3537
|
+
schedulePatch({
|
|
3538
|
+
status: "active",
|
|
3539
|
+
useSocket: true,
|
|
3540
|
+
securityProfile: profile,
|
|
3541
|
+
networkType,
|
|
3542
|
+
connectionCount: runtimeHandle.connectedSocketIds.size,
|
|
3543
|
+
lastStartedAt: state.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
3544
|
+
});
|
|
3545
|
+
return;
|
|
3546
|
+
}
|
|
3547
|
+
const server = runtimeHandle.server;
|
|
3548
|
+
runtimeHandle.initialized = true;
|
|
3549
|
+
setState({
|
|
3550
|
+
...state,
|
|
3551
|
+
serverKey,
|
|
3552
|
+
useSocket: true,
|
|
3553
|
+
status: "active",
|
|
3554
|
+
securityProfile: profile,
|
|
3555
|
+
networkType,
|
|
3556
|
+
connectionCount: runtimeHandle.connectedSocketIds.size,
|
|
3557
|
+
lastStartedAt: state.lastStartedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3558
|
+
updatedAt: Date.now()
|
|
3358
3559
|
});
|
|
3359
|
-
const profile = ctx.__securityProfile ?? "medium";
|
|
3360
3560
|
server.use((socket, next) => {
|
|
3361
3561
|
const origin = socket?.handshake?.headers?.origin;
|
|
3362
3562
|
const allowedOrigins = ["*"];
|
|
3363
|
-
const networkType = ctx.__networkType ?? "internal";
|
|
3364
3563
|
let effectiveOrigin = origin || "unknown";
|
|
3365
3564
|
if (networkType === "internal") effectiveOrigin = "internal";
|
|
3366
3565
|
if (profile !== "low" && !allowedOrigins.includes(effectiveOrigin) && !allowedOrigins.includes("*")) {
|
|
@@ -3371,7 +3570,9 @@ var SocketController = class _SocketController {
|
|
|
3371
3570
|
medium: { points: 1e4, duration: 10 },
|
|
3372
3571
|
high: { points: 1e3, duration: 60, blockDuration: 300 }
|
|
3373
3572
|
};
|
|
3374
|
-
const limiter = new import_rate_limiter_flexible2.RateLimiterMemory(
|
|
3573
|
+
const limiter = new import_rate_limiter_flexible2.RateLimiterMemory(
|
|
3574
|
+
limiterOptions[profile] ?? limiterOptions.medium
|
|
3575
|
+
);
|
|
3375
3576
|
const clientKey = socket?.handshake?.address || "unknown";
|
|
3376
3577
|
socket.use((packet, packetNext) => {
|
|
3377
3578
|
limiter.consume(clientKey).then(() => packetNext()).catch((rej) => {
|
|
@@ -3406,116 +3607,111 @@ var SocketController = class _SocketController {
|
|
|
3406
3607
|
});
|
|
3407
3608
|
next();
|
|
3408
3609
|
});
|
|
3409
|
-
if (!server) {
|
|
3410
|
-
CadenzaService.log("Socket setup error: No server", {}, "error");
|
|
3411
|
-
return { ...ctx, __error: "No server", errored: true };
|
|
3412
|
-
}
|
|
3413
3610
|
server.on("connection", (ws) => {
|
|
3611
|
+
runtimeHandle.connectedSocketIds.add(ws.id);
|
|
3612
|
+
schedulePatch({
|
|
3613
|
+
connectionCount: runtimeHandle.connectedSocketIds.size,
|
|
3614
|
+
lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3615
|
+
status: "active"
|
|
3616
|
+
});
|
|
3414
3617
|
try {
|
|
3415
|
-
ws.on(
|
|
3416
|
-
"
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
}
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
if (ctx3.__routineExecId) {
|
|
3436
|
-
emit(
|
|
3437
|
-
`meta.socket_client.transmitted:${ctx3.__routineExecId}`,
|
|
3438
|
-
{}
|
|
3439
|
-
);
|
|
3440
|
-
}
|
|
3618
|
+
ws.on("handshake", (ctx, callback) => {
|
|
3619
|
+
CadenzaService.log("SocketServer: New connection", {
|
|
3620
|
+
...ctx,
|
|
3621
|
+
socketId: ws.id
|
|
3622
|
+
});
|
|
3623
|
+
callback({
|
|
3624
|
+
status: "success",
|
|
3625
|
+
serviceName: CadenzaService.serviceRegistry.serviceName
|
|
3626
|
+
});
|
|
3627
|
+
if (ctx.isFrontend) {
|
|
3628
|
+
const fetchId = `browser:${ctx.serviceInstanceId}`;
|
|
3629
|
+
CadenzaService.createMetaTask(
|
|
3630
|
+
`Transmit signal to ${fetchId}`,
|
|
3631
|
+
(c, emitter) => {
|
|
3632
|
+
if (c.__signalName === void 0) {
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3635
|
+
ws.emit("signal", c);
|
|
3636
|
+
if (c.__routineExecId) {
|
|
3637
|
+
emitter(`meta.socket_client.transmitted:${c.__routineExecId}`, {});
|
|
3441
3638
|
}
|
|
3442
|
-
).doOn(
|
|
3443
|
-
`meta.service_registry.selected_instance_for_socket:${fetchId}`
|
|
3444
|
-
).attachSignal("meta.socket_client.transmitted");
|
|
3445
|
-
}
|
|
3446
|
-
CadenzaService.emit("meta.socket.handshake", ctx2);
|
|
3447
|
-
}
|
|
3448
|
-
);
|
|
3449
|
-
ws.on(
|
|
3450
|
-
"delegation",
|
|
3451
|
-
(ctx2, callback) => {
|
|
3452
|
-
const deputyExecId = ctx2.__metadata.__deputyExecId;
|
|
3453
|
-
CadenzaService.createEphemeralMetaTask(
|
|
3454
|
-
"Resolve delegation",
|
|
3455
|
-
(ctx3) => {
|
|
3456
|
-
callback(ctx3);
|
|
3457
|
-
},
|
|
3458
|
-
"Resolves a delegation request using the provided callback from the client (.emitWithAck())",
|
|
3459
|
-
{ register: false }
|
|
3460
|
-
).doOn(`meta.node.graph_completed:${deputyExecId}`).emits(`meta.socket.delegation_resolved:${deputyExecId}`);
|
|
3461
|
-
CadenzaService.createEphemeralMetaTask(
|
|
3462
|
-
"Delegation progress update",
|
|
3463
|
-
(ctx3) => {
|
|
3464
|
-
if (ctx3.__progress !== void 0)
|
|
3465
|
-
ws.emit("delegation_progress", ctx3);
|
|
3466
3639
|
},
|
|
3467
|
-
"
|
|
3468
|
-
|
|
3469
|
-
once: false,
|
|
3470
|
-
destroyCondition: (ctx3) => ctx3.data.progress === 1 || ctx3.data?.progress === void 0,
|
|
3471
|
-
register: false
|
|
3472
|
-
}
|
|
3473
|
-
).doOn(
|
|
3474
|
-
`meta.node.routine_execution_progress:${deputyExecId}`,
|
|
3475
|
-
`meta.node.graph_completed:${deputyExecId}`
|
|
3476
|
-
).emitsOnFail(`meta.socket.progress_failed:${deputyExecId}`);
|
|
3477
|
-
CadenzaService.emit("meta.socket.delegation_requested", {
|
|
3478
|
-
...ctx2,
|
|
3479
|
-
__name: ctx2.__remoteRoutineName
|
|
3480
|
-
});
|
|
3640
|
+
"Transmit frontend bound signal through active websocket."
|
|
3641
|
+
).doOn(`meta.service_registry.selected_instance_for_socket:${fetchId}`).attachSignal("meta.socket_client.transmitted");
|
|
3481
3642
|
}
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3643
|
+
CadenzaService.emit("meta.socket.handshake", ctx);
|
|
3644
|
+
});
|
|
3645
|
+
ws.on("delegation", (ctx, callback) => {
|
|
3646
|
+
const deputyExecId = ctx.__metadata.__deputyExecId;
|
|
3647
|
+
CadenzaService.createEphemeralMetaTask(
|
|
3648
|
+
"Resolve delegation",
|
|
3649
|
+
(delegationCtx) => {
|
|
3650
|
+
callback(delegationCtx);
|
|
3651
|
+
},
|
|
3652
|
+
"Resolves a delegation request using client callback.",
|
|
3653
|
+
{ register: false }
|
|
3654
|
+
).doOn(`meta.node.graph_completed:${deputyExecId}`).emits(`meta.socket.delegation_resolved:${deputyExecId}`);
|
|
3655
|
+
CadenzaService.createEphemeralMetaTask(
|
|
3656
|
+
"Delegation progress update",
|
|
3657
|
+
(progressCtx) => {
|
|
3658
|
+
if (progressCtx.__progress !== void 0) {
|
|
3659
|
+
ws.emit("delegation_progress", progressCtx);
|
|
3660
|
+
}
|
|
3661
|
+
},
|
|
3662
|
+
"Updates delegation progress to client.",
|
|
3663
|
+
{
|
|
3664
|
+
once: false,
|
|
3665
|
+
destroyCondition: (progressCtx) => progressCtx.data.progress === 1 || progressCtx.data?.progress === void 0,
|
|
3666
|
+
register: false
|
|
3503
3667
|
}
|
|
3668
|
+
).doOn(
|
|
3669
|
+
`meta.node.routine_execution_progress:${deputyExecId}`,
|
|
3670
|
+
`meta.node.graph_completed:${deputyExecId}`
|
|
3671
|
+
).emitsOnFail(`meta.socket.progress_failed:${deputyExecId}`);
|
|
3672
|
+
CadenzaService.emit("meta.socket.delegation_requested", {
|
|
3673
|
+
...ctx,
|
|
3674
|
+
__name: ctx.__remoteRoutineName
|
|
3675
|
+
});
|
|
3676
|
+
});
|
|
3677
|
+
ws.on("signal", (ctx, callback) => {
|
|
3678
|
+
if (CadenzaService.signalBroker.listObservedSignals().includes(ctx.__signalName)) {
|
|
3679
|
+
callback({
|
|
3680
|
+
__status: "success",
|
|
3681
|
+
__signalName: ctx.__signalName
|
|
3682
|
+
});
|
|
3683
|
+
CadenzaService.emit(ctx.__signalName, ctx);
|
|
3684
|
+
} else {
|
|
3685
|
+
CadenzaService.log(
|
|
3686
|
+
`No such signal ${ctx.__signalName} on ${ctx.__serviceName}`,
|
|
3687
|
+
"warning"
|
|
3688
|
+
);
|
|
3689
|
+
callback({
|
|
3690
|
+
...ctx,
|
|
3691
|
+
__status: "error",
|
|
3692
|
+
__error: `No such signal: ${ctx.__signalName}`,
|
|
3693
|
+
errored: true
|
|
3694
|
+
});
|
|
3504
3695
|
}
|
|
3505
|
-
);
|
|
3696
|
+
});
|
|
3506
3697
|
ws.on(
|
|
3507
3698
|
"status_check",
|
|
3508
|
-
(
|
|
3699
|
+
(ctx, callback) => {
|
|
3509
3700
|
CadenzaService.createEphemeralMetaTask(
|
|
3510
3701
|
"Resolve status check",
|
|
3511
3702
|
callback,
|
|
3512
3703
|
"Resolves a status check request",
|
|
3513
3704
|
{ register: false }
|
|
3514
3705
|
).doAfter(CadenzaService.serviceRegistry.getStatusTask);
|
|
3515
|
-
CadenzaService.emit("meta.socket.status_check_requested",
|
|
3706
|
+
CadenzaService.emit("meta.socket.status_check_requested", ctx);
|
|
3516
3707
|
}
|
|
3517
3708
|
);
|
|
3518
3709
|
ws.on("disconnect", () => {
|
|
3710
|
+
runtimeHandle.connectedSocketIds.delete(ws.id);
|
|
3711
|
+
schedulePatch({
|
|
3712
|
+
connectionCount: runtimeHandle.connectedSocketIds.size,
|
|
3713
|
+
lastDisconnectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3714
|
+
});
|
|
3519
3715
|
CadenzaService.log(
|
|
3520
3716
|
"Socket client disconnected",
|
|
3521
3717
|
{ socketId: ws.id },
|
|
@@ -3525,514 +3721,888 @@ var SocketController = class _SocketController {
|
|
|
3525
3721
|
__wsId: ws.id
|
|
3526
3722
|
});
|
|
3527
3723
|
});
|
|
3528
|
-
} catch (
|
|
3724
|
+
} catch (error) {
|
|
3529
3725
|
CadenzaService.log(
|
|
3530
3726
|
"SocketServer: Error in socket event",
|
|
3531
|
-
{ error
|
|
3727
|
+
{ error },
|
|
3532
3728
|
"error"
|
|
3533
3729
|
);
|
|
3534
3730
|
}
|
|
3535
3731
|
CadenzaService.emit("meta.socket.connected", { __wsId: ws.id });
|
|
3536
3732
|
});
|
|
3537
|
-
CadenzaService.createMetaTask(
|
|
3538
|
-
|
|
3539
|
-
(
|
|
3733
|
+
runtimeHandle.broadcastStatusTask = CadenzaService.createMetaTask(
|
|
3734
|
+
`Broadcast status ${serverKey}`,
|
|
3735
|
+
(ctx) => server.emit("status_update", ctx),
|
|
3540
3736
|
"Broadcasts the status of the server to all clients"
|
|
3541
3737
|
).doOn("meta.service.updated");
|
|
3542
|
-
CadenzaService.createMetaTask(
|
|
3543
|
-
|
|
3544
|
-
() =>
|
|
3738
|
+
runtimeHandle.shutdownTask = CadenzaService.createMetaTask(
|
|
3739
|
+
`Shutdown SocketServer ${serverKey}`,
|
|
3740
|
+
async () => {
|
|
3741
|
+
this.destroySocketServerRuntimeHandle(runtimeHandle);
|
|
3742
|
+
CadenzaService.emit("meta.socket_server.runtime_clear_requested", {
|
|
3743
|
+
serverKey
|
|
3744
|
+
});
|
|
3745
|
+
CadenzaService.emit("meta.socket_server.session_patch_requested", {
|
|
3746
|
+
serverKey,
|
|
3747
|
+
patch: {
|
|
3748
|
+
useSocket: false,
|
|
3749
|
+
status: "shutdown",
|
|
3750
|
+
connectionCount: 0,
|
|
3751
|
+
lastShutdownAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3752
|
+
}
|
|
3753
|
+
});
|
|
3754
|
+
},
|
|
3545
3755
|
"Shuts down the socket server"
|
|
3546
3756
|
).doOn("meta.socket_server_shutdown_requested").emits("meta.socket.shutdown");
|
|
3547
|
-
return
|
|
3548
|
-
}
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3757
|
+
return true;
|
|
3758
|
+
},
|
|
3759
|
+
{ mode: "write" }
|
|
3760
|
+
),
|
|
3761
|
+
"Initializes socket server runtime through actor state."
|
|
3762
|
+
);
|
|
3763
|
+
setupSocketServerTask.doOn("global.meta.rest.network_configured");
|
|
3764
|
+
}
|
|
3765
|
+
registerSocketClientTasks() {
|
|
3766
|
+
CadenzaService.createThrottledMetaTask(
|
|
3767
|
+
"SocketClientActor.ApplySessionOperation",
|
|
3768
|
+
this.socketClientActor.task(
|
|
3769
|
+
({ state, input, setState }) => {
|
|
3770
|
+
const operation = String(
|
|
3771
|
+
input.operation ?? "transmit"
|
|
3772
|
+
);
|
|
3773
|
+
const patch = input.patch && typeof input.patch === "object" ? input.patch : {};
|
|
3774
|
+
let next = {
|
|
3775
|
+
...state,
|
|
3776
|
+
...patch,
|
|
3777
|
+
communicationTypes: patch.communicationTypes !== void 0 ? this.normalizeCommunicationTypes(patch.communicationTypes) : state.communicationTypes,
|
|
3778
|
+
updatedAt: Date.now()
|
|
3779
|
+
};
|
|
3780
|
+
if (input.serviceName !== void 0) {
|
|
3781
|
+
next.serviceName = String(input.serviceName);
|
|
3782
|
+
}
|
|
3783
|
+
if (input.serviceAddress !== void 0) {
|
|
3784
|
+
next.serviceAddress = String(input.serviceAddress);
|
|
3785
|
+
}
|
|
3786
|
+
if (input.serviceInstanceId !== void 0) {
|
|
3787
|
+
next.serviceInstanceId = String(input.serviceInstanceId);
|
|
3788
|
+
}
|
|
3789
|
+
if (input.protocol !== void 0) {
|
|
3790
|
+
next.protocol = String(input.protocol);
|
|
3791
|
+
}
|
|
3792
|
+
if (input.url !== void 0) {
|
|
3793
|
+
next.url = String(input.url);
|
|
3794
|
+
}
|
|
3795
|
+
if (input.servicePort !== void 0) {
|
|
3796
|
+
next.servicePort = Number(input.servicePort);
|
|
3797
|
+
}
|
|
3798
|
+
if (input.fetchId !== void 0) {
|
|
3799
|
+
next.fetchId = String(input.fetchId);
|
|
3800
|
+
}
|
|
3801
|
+
if (operation === "connect") {
|
|
3802
|
+
next.destroyed = false;
|
|
3803
|
+
} else if (operation === "handshake") {
|
|
3804
|
+
next.destroyed = false;
|
|
3805
|
+
next.connected = patch.connected ?? true;
|
|
3806
|
+
next.handshake = patch.handshake ?? true;
|
|
3807
|
+
} else if (operation === "shutdown") {
|
|
3808
|
+
next.connected = false;
|
|
3809
|
+
next.handshake = false;
|
|
3810
|
+
next.destroyed = true;
|
|
3811
|
+
next.pendingDelegations = 0;
|
|
3812
|
+
next.pendingTimers = 0;
|
|
3813
|
+
}
|
|
3814
|
+
setState(next);
|
|
3815
|
+
return next;
|
|
3816
|
+
},
|
|
3817
|
+
{ mode: "write" }
|
|
3818
|
+
),
|
|
3819
|
+
(context) => String(this.resolveSocketClientFetchId(context ?? {}) ?? "default"),
|
|
3820
|
+
"Applies socket client session operation patch in actor durable state."
|
|
3821
|
+
).doOn("meta.socket_client.session_operation_requested");
|
|
3822
|
+
CadenzaService.createMetaTask(
|
|
3823
|
+
"SocketClientActor.ClearRuntime",
|
|
3824
|
+
this.socketClientActor.task(
|
|
3825
|
+
({ setRuntimeState }) => {
|
|
3826
|
+
setRuntimeState(null);
|
|
3827
|
+
},
|
|
3828
|
+
{ mode: "write" }
|
|
3829
|
+
),
|
|
3830
|
+
"Clears socket client runtime handle."
|
|
3831
|
+
).doOn("meta.socket_client.runtime_clear_requested");
|
|
3552
3832
|
CadenzaService.createMetaTask(
|
|
3553
3833
|
"Connect to socket server",
|
|
3554
|
-
(
|
|
3555
|
-
|
|
3556
|
-
serviceInstanceId
|
|
3557
|
-
communicationTypes
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
fetchId,
|
|
3569
|
-
serviceName,
|
|
3570
|
-
URL
|
|
3571
|
-
);
|
|
3572
|
-
socketDiagnostics.destroyed = false;
|
|
3573
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3574
|
-
let handshake = false;
|
|
3575
|
-
let errorCount = 0;
|
|
3576
|
-
const ERROR_LIMIT = 5;
|
|
3577
|
-
if (CadenzaService.get(`Socket handshake with ${URL}`)) {
|
|
3578
|
-
console.error("Socket client already exists", URL);
|
|
3579
|
-
return;
|
|
3580
|
-
}
|
|
3581
|
-
const pendingDelegationIds = /* @__PURE__ */ new Set();
|
|
3582
|
-
const pendingTimers = /* @__PURE__ */ new Set();
|
|
3583
|
-
const syncPendingCounts = () => {
|
|
3584
|
-
socketDiagnostics.pendingDelegations = pendingDelegationIds.size;
|
|
3585
|
-
socketDiagnostics.pendingTimers = pendingTimers.size;
|
|
3586
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3587
|
-
};
|
|
3588
|
-
let handshakeTask = null;
|
|
3589
|
-
let emitWhenReady = null;
|
|
3590
|
-
let transmitTask = null;
|
|
3591
|
-
let delegateTask = null;
|
|
3592
|
-
let socket = null;
|
|
3593
|
-
socket = (0, import_socket2.io)(URL, {
|
|
3594
|
-
reconnection: true,
|
|
3595
|
-
reconnectionAttempts: 5,
|
|
3596
|
-
reconnectionDelay: 2e3,
|
|
3597
|
-
reconnectionDelayMax: 1e4,
|
|
3598
|
-
randomizationFactor: 0.5,
|
|
3599
|
-
transports: ["websocket"],
|
|
3600
|
-
autoConnect: false
|
|
3601
|
-
});
|
|
3602
|
-
emitWhenReady = (event, data, timeoutMs = 6e4, ack) => {
|
|
3603
|
-
return new Promise((resolve) => {
|
|
3604
|
-
const resolveWithError = (errorMessage, fallbackError) => {
|
|
3605
|
-
resolve({
|
|
3606
|
-
...data,
|
|
3607
|
-
errored: true,
|
|
3608
|
-
__error: errorMessage,
|
|
3609
|
-
error: fallbackError instanceof Error ? fallbackError.message : errorMessage,
|
|
3610
|
-
socketId: socket?.id,
|
|
3834
|
+
this.socketClientActor.task(
|
|
3835
|
+
({ state, runtimeState, input, setState, setRuntimeState, emit }) => {
|
|
3836
|
+
const serviceInstanceId = String(input.serviceInstanceId ?? "");
|
|
3837
|
+
const communicationTypes = this.normalizeCommunicationTypes(
|
|
3838
|
+
input.communicationTypes
|
|
3839
|
+
);
|
|
3840
|
+
const serviceName = String(input.serviceName ?? "");
|
|
3841
|
+
const serviceAddress = String(input.serviceAddress ?? "");
|
|
3842
|
+
const protocol = String(input.protocol ?? "http");
|
|
3843
|
+
const normalizedPort = this.resolveServicePort(protocol, input.servicePort);
|
|
3844
|
+
if (!serviceAddress || !normalizedPort) {
|
|
3845
|
+
CadenzaService.log(
|
|
3846
|
+
"Socket client setup skipped due to missing address/port",
|
|
3847
|
+
{
|
|
3611
3848
|
serviceName,
|
|
3612
|
-
|
|
3849
|
+
serviceAddress,
|
|
3850
|
+
servicePort: input.servicePort,
|
|
3851
|
+
protocol
|
|
3852
|
+
},
|
|
3853
|
+
"warning"
|
|
3854
|
+
);
|
|
3855
|
+
return false;
|
|
3856
|
+
}
|
|
3857
|
+
const socketProtocol = protocol === "https" ? "wss" : "ws";
|
|
3858
|
+
const url = `${socketProtocol}://${serviceAddress}:${normalizedPort}`;
|
|
3859
|
+
const fetchId = `${serviceAddress}_${normalizedPort}`;
|
|
3860
|
+
const applySessionOperation = (operation, patch = {}) => {
|
|
3861
|
+
CadenzaService.emit("meta.socket_client.session_operation_requested", {
|
|
3862
|
+
fetchId,
|
|
3863
|
+
operation,
|
|
3864
|
+
patch,
|
|
3865
|
+
serviceInstanceId,
|
|
3866
|
+
communicationTypes,
|
|
3867
|
+
serviceName,
|
|
3868
|
+
serviceAddress,
|
|
3869
|
+
servicePort: normalizedPort,
|
|
3870
|
+
protocol,
|
|
3871
|
+
url
|
|
3872
|
+
});
|
|
3873
|
+
};
|
|
3874
|
+
const upsertDiagnostics = (patch, error) => {
|
|
3875
|
+
CadenzaService.emit("meta.socket_client.diagnostics_upsert_requested", {
|
|
3876
|
+
fetchId,
|
|
3877
|
+
serviceName,
|
|
3878
|
+
url,
|
|
3879
|
+
patch,
|
|
3880
|
+
error
|
|
3881
|
+
});
|
|
3882
|
+
};
|
|
3883
|
+
setState({
|
|
3884
|
+
...state,
|
|
3885
|
+
fetchId,
|
|
3886
|
+
serviceInstanceId,
|
|
3887
|
+
communicationTypes,
|
|
3888
|
+
serviceName,
|
|
3889
|
+
serviceAddress,
|
|
3890
|
+
servicePort: normalizedPort,
|
|
3891
|
+
protocol,
|
|
3892
|
+
url,
|
|
3893
|
+
destroyed: false,
|
|
3894
|
+
updatedAt: Date.now()
|
|
3895
|
+
});
|
|
3896
|
+
let runtimeHandle = runtimeState;
|
|
3897
|
+
if (!runtimeHandle || runtimeHandle.url !== url) {
|
|
3898
|
+
this.destroySocketClientRuntimeHandle(runtimeHandle);
|
|
3899
|
+
runtimeHandle = this.createSocketClientRuntimeHandle(url);
|
|
3900
|
+
setRuntimeState(runtimeHandle);
|
|
3901
|
+
}
|
|
3902
|
+
upsertDiagnostics({
|
|
3903
|
+
destroyed: false,
|
|
3904
|
+
connected: false,
|
|
3905
|
+
handshake: false,
|
|
3906
|
+
socketId: runtimeHandle.socket.id ?? null
|
|
3907
|
+
});
|
|
3908
|
+
applySessionOperation("connect", {
|
|
3909
|
+
destroyed: false,
|
|
3910
|
+
connected: false,
|
|
3911
|
+
handshake: false,
|
|
3912
|
+
socketId: runtimeHandle.socket.id ?? null,
|
|
3913
|
+
pendingDelegations: runtimeHandle.pendingDelegationIds.size,
|
|
3914
|
+
pendingTimers: runtimeHandle.pendingTimers.size,
|
|
3915
|
+
errorCount: runtimeHandle.errorCount
|
|
3916
|
+
});
|
|
3917
|
+
if (runtimeHandle.initialized) {
|
|
3918
|
+
return true;
|
|
3919
|
+
}
|
|
3920
|
+
runtimeHandle.initialized = true;
|
|
3921
|
+
runtimeHandle.handshake = false;
|
|
3922
|
+
runtimeHandle.errorCount = 0;
|
|
3923
|
+
const syncPendingCounts = () => {
|
|
3924
|
+
const pendingDelegations = runtimeHandle.pendingDelegationIds.size;
|
|
3925
|
+
const pendingTimers = runtimeHandle.pendingTimers.size;
|
|
3926
|
+
upsertDiagnostics({
|
|
3927
|
+
pendingDelegations,
|
|
3928
|
+
pendingTimers
|
|
3929
|
+
});
|
|
3930
|
+
applySessionOperation("delegate", {
|
|
3931
|
+
pendingDelegations,
|
|
3932
|
+
pendingTimers
|
|
3933
|
+
});
|
|
3934
|
+
};
|
|
3935
|
+
runtimeHandle.emitWhenReady = (event, data, timeoutMs = 6e4, ack) => {
|
|
3936
|
+
return new Promise((resolve) => {
|
|
3937
|
+
const parsedTimeout = Number(timeoutMs);
|
|
3938
|
+
const normalizedTimeoutMs = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? Math.trunc(parsedTimeout) : 6e4;
|
|
3939
|
+
let timer = null;
|
|
3940
|
+
let settled = false;
|
|
3941
|
+
const clearPendingTimer = () => {
|
|
3942
|
+
if (!timer) {
|
|
3943
|
+
return;
|
|
3944
|
+
}
|
|
3945
|
+
clearTimeout(timer);
|
|
3946
|
+
runtimeHandle.pendingTimers.delete(timer);
|
|
3947
|
+
syncPendingCounts();
|
|
3948
|
+
timer = null;
|
|
3949
|
+
};
|
|
3950
|
+
const settle = (response) => {
|
|
3951
|
+
if (settled) {
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
settled = true;
|
|
3955
|
+
clearPendingTimer();
|
|
3956
|
+
if (ack) ack(response);
|
|
3957
|
+
resolve(response);
|
|
3958
|
+
};
|
|
3959
|
+
const resolveWithError = (errorMessage, fallbackError) => {
|
|
3960
|
+
settle({
|
|
3961
|
+
...data,
|
|
3962
|
+
errored: true,
|
|
3963
|
+
__error: errorMessage,
|
|
3964
|
+
error: fallbackError instanceof Error ? fallbackError.message : errorMessage,
|
|
3965
|
+
socketId: runtimeHandle.socket.id,
|
|
3966
|
+
serviceName,
|
|
3967
|
+
url
|
|
3968
|
+
});
|
|
3969
|
+
};
|
|
3970
|
+
const tryEmit = async () => {
|
|
3971
|
+
const waitResult = await waitForSocketConnection(
|
|
3972
|
+
runtimeHandle.socket,
|
|
3973
|
+
normalizedTimeoutMs + 10,
|
|
3974
|
+
(reason, error) => {
|
|
3975
|
+
if (reason === "connect_timeout") {
|
|
3976
|
+
return `Socket connect timed out before '${event}'`;
|
|
3977
|
+
}
|
|
3978
|
+
if (reason === "connect_error") {
|
|
3979
|
+
const errMessage = error instanceof Error ? error.message : String(error);
|
|
3980
|
+
return `Socket connect error before '${event}': ${errMessage}`;
|
|
3981
|
+
}
|
|
3982
|
+
return `Socket disconnected before '${event}'`;
|
|
3983
|
+
}
|
|
3984
|
+
);
|
|
3985
|
+
if (!waitResult.ok) {
|
|
3986
|
+
CadenzaService.log(
|
|
3987
|
+
waitResult.error,
|
|
3988
|
+
{
|
|
3989
|
+
socketId: runtimeHandle.socket.id,
|
|
3990
|
+
serviceName,
|
|
3991
|
+
url,
|
|
3992
|
+
event
|
|
3993
|
+
},
|
|
3994
|
+
"error"
|
|
3995
|
+
);
|
|
3996
|
+
upsertDiagnostics({}, waitResult.error);
|
|
3997
|
+
resolveWithError(waitResult.error);
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
4000
|
+
timer = setTimeout(() => {
|
|
4001
|
+
if (settled) {
|
|
4002
|
+
return;
|
|
4003
|
+
}
|
|
4004
|
+
clearPendingTimer();
|
|
4005
|
+
const message = `Socket event '${event}' timed out`;
|
|
4006
|
+
CadenzaService.log(
|
|
4007
|
+
message,
|
|
4008
|
+
{ socketId: runtimeHandle.socket.id, serviceName, url },
|
|
4009
|
+
"error"
|
|
4010
|
+
);
|
|
4011
|
+
upsertDiagnostics(
|
|
4012
|
+
{
|
|
4013
|
+
lastHandshakeError: message
|
|
4014
|
+
},
|
|
4015
|
+
message
|
|
4016
|
+
);
|
|
4017
|
+
applySessionOperation("transmit", {
|
|
4018
|
+
lastHandshakeError: message
|
|
4019
|
+
});
|
|
4020
|
+
resolveWithError(message);
|
|
4021
|
+
}, normalizedTimeoutMs + 10);
|
|
4022
|
+
runtimeHandle.pendingTimers.add(timer);
|
|
4023
|
+
syncPendingCounts();
|
|
4024
|
+
runtimeHandle.socket.timeout(normalizedTimeoutMs).emit(event, data, (err, response) => {
|
|
4025
|
+
if (err) {
|
|
4026
|
+
CadenzaService.log(
|
|
4027
|
+
"Socket timeout.",
|
|
4028
|
+
{
|
|
4029
|
+
event,
|
|
4030
|
+
error: err.message,
|
|
4031
|
+
socketId: runtimeHandle.socket.id,
|
|
4032
|
+
serviceName
|
|
4033
|
+
},
|
|
4034
|
+
"warning"
|
|
4035
|
+
);
|
|
4036
|
+
upsertDiagnostics(
|
|
4037
|
+
{
|
|
4038
|
+
lastHandshakeError: err.message
|
|
4039
|
+
},
|
|
4040
|
+
err
|
|
4041
|
+
);
|
|
4042
|
+
applySessionOperation("transmit", {
|
|
4043
|
+
lastHandshakeError: err.message
|
|
4044
|
+
});
|
|
4045
|
+
response = {
|
|
4046
|
+
__error: `Timeout error: ${err}`,
|
|
4047
|
+
errored: true,
|
|
4048
|
+
...data
|
|
4049
|
+
};
|
|
4050
|
+
}
|
|
4051
|
+
settle(response);
|
|
4052
|
+
});
|
|
4053
|
+
};
|
|
4054
|
+
void tryEmit().catch((error) => {
|
|
4055
|
+
CadenzaService.log(
|
|
4056
|
+
"Socket emit failed unexpectedly",
|
|
4057
|
+
{
|
|
4058
|
+
event,
|
|
4059
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4060
|
+
socketId: runtimeHandle.socket.id,
|
|
4061
|
+
serviceName,
|
|
4062
|
+
url
|
|
4063
|
+
},
|
|
4064
|
+
"error"
|
|
4065
|
+
);
|
|
4066
|
+
const message = `Socket event '${event}' failed`;
|
|
4067
|
+
upsertDiagnostics(
|
|
4068
|
+
{
|
|
4069
|
+
lastHandshakeError: error instanceof Error ? error.message : String(error)
|
|
4070
|
+
},
|
|
4071
|
+
error
|
|
4072
|
+
);
|
|
4073
|
+
applySessionOperation("transmit", {
|
|
4074
|
+
lastHandshakeError: error instanceof Error ? error.message : String(error)
|
|
4075
|
+
});
|
|
4076
|
+
resolveWithError(message, error);
|
|
4077
|
+
});
|
|
4078
|
+
});
|
|
4079
|
+
};
|
|
4080
|
+
const socket = runtimeHandle.socket;
|
|
4081
|
+
socket.on("connect", () => {
|
|
4082
|
+
if (runtimeHandle.handshake) return;
|
|
4083
|
+
upsertDiagnostics({
|
|
4084
|
+
connected: true,
|
|
4085
|
+
destroyed: false,
|
|
4086
|
+
socketId: socket.id ?? null
|
|
4087
|
+
});
|
|
4088
|
+
applySessionOperation("connect", {
|
|
4089
|
+
connected: true,
|
|
4090
|
+
destroyed: false,
|
|
4091
|
+
socketId: socket.id ?? null
|
|
4092
|
+
});
|
|
4093
|
+
CadenzaService.emit(`meta.socket_client.connected:${fetchId}`, input);
|
|
4094
|
+
});
|
|
4095
|
+
socket.on("delegation_progress", (delegationCtx) => {
|
|
4096
|
+
CadenzaService.emit(
|
|
4097
|
+
`meta.socket_client.delegation_progress:${delegationCtx.__metadata.__deputyExecId}`,
|
|
4098
|
+
delegationCtx
|
|
4099
|
+
);
|
|
4100
|
+
});
|
|
4101
|
+
socket.on("signal", (signalCtx) => {
|
|
4102
|
+
if (CadenzaService.signalBroker.listObservedSignals().includes(signalCtx.__signalName)) {
|
|
4103
|
+
CadenzaService.emit(signalCtx.__signalName, signalCtx);
|
|
4104
|
+
}
|
|
4105
|
+
});
|
|
4106
|
+
socket.on("status_update", (status) => {
|
|
4107
|
+
CadenzaService.emit("meta.socket_client.status_received", status);
|
|
4108
|
+
});
|
|
4109
|
+
socket.on("connect_error", (err) => {
|
|
4110
|
+
runtimeHandle.handshake = false;
|
|
4111
|
+
upsertDiagnostics(
|
|
4112
|
+
{
|
|
4113
|
+
connected: false,
|
|
4114
|
+
handshake: false,
|
|
4115
|
+
connectErrors: state.connectErrors + 1,
|
|
4116
|
+
lastHandshakeError: err.message
|
|
4117
|
+
},
|
|
4118
|
+
err
|
|
4119
|
+
);
|
|
4120
|
+
applySessionOperation("connect", {
|
|
4121
|
+
connected: false,
|
|
4122
|
+
handshake: false,
|
|
4123
|
+
connectErrors: state.connectErrors + 1,
|
|
4124
|
+
lastHandshakeError: err.message
|
|
4125
|
+
});
|
|
4126
|
+
CadenzaService.log(
|
|
4127
|
+
"Socket connect error",
|
|
4128
|
+
{
|
|
4129
|
+
error: err.message,
|
|
4130
|
+
serviceName,
|
|
4131
|
+
socketId: socket.id,
|
|
4132
|
+
url
|
|
4133
|
+
},
|
|
4134
|
+
"error"
|
|
4135
|
+
);
|
|
4136
|
+
CadenzaService.emit(`meta.socket_client.connect_error:${fetchId}`, err);
|
|
4137
|
+
});
|
|
4138
|
+
socket.on("reconnect_attempt", (attempt) => {
|
|
4139
|
+
upsertDiagnostics({ reconnectAttempts: attempt });
|
|
4140
|
+
applySessionOperation("connect", {
|
|
4141
|
+
reconnectAttempts: attempt
|
|
4142
|
+
});
|
|
4143
|
+
CadenzaService.log(`Reconnect attempt: ${attempt}`);
|
|
4144
|
+
});
|
|
4145
|
+
socket.on("reconnect", (attempt) => {
|
|
4146
|
+
upsertDiagnostics({ connected: true });
|
|
4147
|
+
applySessionOperation("connect", {
|
|
4148
|
+
connected: true
|
|
4149
|
+
});
|
|
4150
|
+
CadenzaService.log(`Socket reconnected after ${attempt} tries`, {
|
|
4151
|
+
socketId: socket.id,
|
|
4152
|
+
url,
|
|
4153
|
+
serviceName
|
|
4154
|
+
});
|
|
4155
|
+
});
|
|
4156
|
+
socket.on("reconnect_error", (err) => {
|
|
4157
|
+
runtimeHandle.handshake = false;
|
|
4158
|
+
upsertDiagnostics(
|
|
4159
|
+
{
|
|
4160
|
+
connected: false,
|
|
4161
|
+
handshake: false,
|
|
4162
|
+
reconnectErrors: state.reconnectErrors + 1,
|
|
4163
|
+
lastHandshakeError: err.message
|
|
4164
|
+
},
|
|
4165
|
+
err
|
|
4166
|
+
);
|
|
4167
|
+
applySessionOperation("connect", {
|
|
4168
|
+
connected: false,
|
|
4169
|
+
handshake: false,
|
|
4170
|
+
reconnectErrors: state.reconnectErrors + 1,
|
|
4171
|
+
lastHandshakeError: err.message
|
|
4172
|
+
});
|
|
4173
|
+
CadenzaService.log(
|
|
4174
|
+
"Socket reconnect failed.",
|
|
4175
|
+
{ error: err.message, serviceName, url, socketId: socket.id },
|
|
4176
|
+
"warning"
|
|
4177
|
+
);
|
|
4178
|
+
});
|
|
4179
|
+
socket.on("error", (err) => {
|
|
4180
|
+
runtimeHandle.errorCount += 1;
|
|
4181
|
+
upsertDiagnostics(
|
|
4182
|
+
{
|
|
4183
|
+
socketErrors: state.socketErrors + 1,
|
|
4184
|
+
lastHandshakeError: this.getErrorMessage(err)
|
|
4185
|
+
},
|
|
4186
|
+
err
|
|
4187
|
+
);
|
|
4188
|
+
applySessionOperation("transmit", {
|
|
4189
|
+
socketErrors: state.socketErrors + 1,
|
|
4190
|
+
errorCount: runtimeHandle.errorCount,
|
|
4191
|
+
lastHandshakeError: this.getErrorMessage(err)
|
|
4192
|
+
});
|
|
4193
|
+
CadenzaService.log(
|
|
4194
|
+
"Socket error",
|
|
4195
|
+
{ error: err, socketId: socket.id, url, serviceName },
|
|
4196
|
+
"error"
|
|
4197
|
+
);
|
|
4198
|
+
CadenzaService.emit("meta.socket_client.error", err);
|
|
4199
|
+
});
|
|
4200
|
+
socket.on("disconnect", () => {
|
|
4201
|
+
const disconnectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4202
|
+
upsertDiagnostics({
|
|
4203
|
+
connected: false,
|
|
4204
|
+
handshake: false,
|
|
4205
|
+
lastDisconnectAt: disconnectedAt
|
|
4206
|
+
});
|
|
4207
|
+
applySessionOperation("connect", {
|
|
4208
|
+
connected: false,
|
|
4209
|
+
handshake: false,
|
|
4210
|
+
lastDisconnectAt: disconnectedAt
|
|
4211
|
+
});
|
|
4212
|
+
CadenzaService.log(
|
|
4213
|
+
"Socket disconnected.",
|
|
4214
|
+
{ url, serviceName, socketId: socket.id },
|
|
4215
|
+
"warning"
|
|
4216
|
+
);
|
|
4217
|
+
CadenzaService.emit(`meta.socket_client.disconnected:${fetchId}`, {
|
|
4218
|
+
serviceName,
|
|
4219
|
+
serviceAddress,
|
|
4220
|
+
servicePort: normalizedPort
|
|
4221
|
+
});
|
|
4222
|
+
runtimeHandle.handshake = false;
|
|
4223
|
+
});
|
|
4224
|
+
socket.connect();
|
|
4225
|
+
runtimeHandle.handshakeTask = CadenzaService.createMetaTask(
|
|
4226
|
+
`Socket handshake with ${url}`,
|
|
4227
|
+
async (_ctx, emitter) => {
|
|
4228
|
+
if (runtimeHandle.handshake) return;
|
|
4229
|
+
runtimeHandle.handshake = true;
|
|
4230
|
+
upsertDiagnostics({
|
|
4231
|
+
handshake: true
|
|
3613
4232
|
});
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
4233
|
+
applySessionOperation("handshake", {
|
|
4234
|
+
handshake: true
|
|
4235
|
+
});
|
|
4236
|
+
await runtimeHandle.emitWhenReady?.(
|
|
4237
|
+
"handshake",
|
|
4238
|
+
{
|
|
4239
|
+
serviceInstanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
4240
|
+
serviceName: CadenzaService.serviceRegistry.serviceName,
|
|
4241
|
+
isFrontend: isBrowser,
|
|
4242
|
+
__status: "success"
|
|
4243
|
+
},
|
|
4244
|
+
1e4,
|
|
4245
|
+
(result) => {
|
|
4246
|
+
if (result.status === "success") {
|
|
4247
|
+
const handshakeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4248
|
+
upsertDiagnostics({
|
|
4249
|
+
connected: true,
|
|
4250
|
+
handshake: true,
|
|
4251
|
+
lastHandshakeAt: handshakeAt,
|
|
4252
|
+
lastHandshakeError: null,
|
|
4253
|
+
socketId: socket.id ?? null
|
|
4254
|
+
});
|
|
4255
|
+
applySessionOperation("handshake", {
|
|
4256
|
+
connected: true,
|
|
4257
|
+
handshake: true,
|
|
4258
|
+
lastHandshakeAt: handshakeAt,
|
|
4259
|
+
lastHandshakeError: null,
|
|
4260
|
+
socketId: socket.id ?? null
|
|
4261
|
+
});
|
|
4262
|
+
CadenzaService.log("Socket client connected", {
|
|
4263
|
+
result,
|
|
4264
|
+
serviceName,
|
|
4265
|
+
socketId: socket.id,
|
|
4266
|
+
url
|
|
4267
|
+
});
|
|
4268
|
+
} else {
|
|
4269
|
+
const errorMessage = result?.__error ?? result?.error ?? "Socket handshake failed";
|
|
4270
|
+
upsertDiagnostics(
|
|
4271
|
+
{
|
|
4272
|
+
connected: false,
|
|
4273
|
+
handshake: false,
|
|
4274
|
+
lastHandshakeError: errorMessage
|
|
4275
|
+
},
|
|
4276
|
+
errorMessage
|
|
4277
|
+
);
|
|
4278
|
+
applySessionOperation("handshake", {
|
|
4279
|
+
connected: false,
|
|
4280
|
+
handshake: false,
|
|
4281
|
+
lastHandshakeError: errorMessage
|
|
4282
|
+
});
|
|
4283
|
+
CadenzaService.log(
|
|
4284
|
+
"Socket handshake failed",
|
|
4285
|
+
{ result, serviceName, socketId: socket.id, url },
|
|
4286
|
+
"warning"
|
|
4287
|
+
);
|
|
3627
4288
|
}
|
|
3628
|
-
|
|
4289
|
+
void emitter;
|
|
3629
4290
|
}
|
|
3630
4291
|
);
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
fetchId,
|
|
3639
|
-
serviceName,
|
|
3640
|
-
URL,
|
|
3641
|
-
waitResult.error
|
|
3642
|
-
);
|
|
3643
|
-
resolveWithError(waitResult.error);
|
|
4292
|
+
},
|
|
4293
|
+
"Handshakes with socket server"
|
|
4294
|
+
).doOn(`meta.socket_client.connected:${fetchId}`);
|
|
4295
|
+
runtimeHandle.delegateTask = CadenzaService.createMetaTask(
|
|
4296
|
+
`Delegate flow to Socket service ${url}`,
|
|
4297
|
+
async (delegateCtx, emitter) => {
|
|
4298
|
+
if (delegateCtx.__remoteRoutineName === void 0) {
|
|
3644
4299
|
return;
|
|
3645
4300
|
}
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
timer = null;
|
|
3653
|
-
}
|
|
3654
|
-
CadenzaService.log(
|
|
3655
|
-
`Socket event '${event}' timed out`,
|
|
3656
|
-
{ socketId: socket?.id, serviceName, URL },
|
|
3657
|
-
"error"
|
|
3658
|
-
);
|
|
3659
|
-
this.recordSocketClientError(
|
|
3660
|
-
fetchId,
|
|
3661
|
-
serviceName,
|
|
3662
|
-
URL,
|
|
3663
|
-
`Socket event '${event}' timed out`
|
|
3664
|
-
);
|
|
3665
|
-
resolveWithError(`Socket event '${event}' timed out`);
|
|
3666
|
-
}, timeoutMs + 10);
|
|
3667
|
-
pendingTimers.add(timer);
|
|
4301
|
+
delete delegateCtx.__isSubMeta;
|
|
4302
|
+
delete delegateCtx.__broadcast;
|
|
4303
|
+
const deputyExecId = delegateCtx.__metadata?.__deputyExecId;
|
|
4304
|
+
const requestSentAt = Date.now();
|
|
4305
|
+
if (deputyExecId) {
|
|
4306
|
+
runtimeHandle.pendingDelegationIds.add(deputyExecId);
|
|
3668
4307
|
syncPendingCounts();
|
|
3669
4308
|
}
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
4309
|
+
try {
|
|
4310
|
+
const resultContext = await runtimeHandle.emitWhenReady?.(
|
|
4311
|
+
"delegation",
|
|
4312
|
+
delegateCtx,
|
|
4313
|
+
delegateCtx.__timeout ?? 6e4
|
|
4314
|
+
) ?? {
|
|
4315
|
+
errored: true,
|
|
4316
|
+
__error: "Socket delegation returned no response"
|
|
4317
|
+
};
|
|
4318
|
+
const requestDuration = Date.now() - requestSentAt;
|
|
4319
|
+
const metadata = resultContext.__metadata;
|
|
4320
|
+
delete resultContext.__metadata;
|
|
4321
|
+
if (deputyExecId) {
|
|
4322
|
+
emitter(`meta.socket_client.delegated:${deputyExecId}`, {
|
|
4323
|
+
...resultContext,
|
|
4324
|
+
...metadata,
|
|
4325
|
+
__requestDuration: requestDuration
|
|
4326
|
+
});
|
|
3683
4327
|
}
|
|
3684
|
-
if (
|
|
3685
|
-
|
|
3686
|
-
|
|
4328
|
+
if (resultContext?.errored || resultContext?.failed) {
|
|
4329
|
+
const errorMessage = resultContext?.__error ?? resultContext?.error ?? "Socket delegation failed";
|
|
4330
|
+
upsertDiagnostics(
|
|
3687
4331
|
{
|
|
3688
|
-
|
|
3689
|
-
error: err.message,
|
|
3690
|
-
socketId: socket?.id,
|
|
3691
|
-
serviceName
|
|
4332
|
+
lastHandshakeError: String(errorMessage)
|
|
3692
4333
|
},
|
|
3693
|
-
|
|
3694
|
-
);
|
|
3695
|
-
this.recordSocketClientError(
|
|
3696
|
-
fetchId,
|
|
3697
|
-
serviceName,
|
|
3698
|
-
URL,
|
|
3699
|
-
err
|
|
4334
|
+
errorMessage
|
|
3700
4335
|
);
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
...ctx,
|
|
3705
|
-
...ctx.__metadata
|
|
3706
|
-
};
|
|
4336
|
+
applySessionOperation("delegate", {
|
|
4337
|
+
lastHandshakeError: String(errorMessage)
|
|
4338
|
+
});
|
|
3707
4339
|
}
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
socketDiagnostics.socketId = socket?.id ?? null;
|
|
3720
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3721
|
-
CadenzaService.emit(`meta.socket_client.connected:${fetchId}`, ctx);
|
|
3722
|
-
});
|
|
3723
|
-
socket.on("delegation_progress", (ctx2) => {
|
|
3724
|
-
CadenzaService.emit(
|
|
3725
|
-
`meta.socket_client.delegation_progress:${ctx2.__metadata.__deputyExecId}`,
|
|
3726
|
-
ctx2
|
|
3727
|
-
);
|
|
3728
|
-
});
|
|
3729
|
-
socket.on("signal", (ctx2) => {
|
|
3730
|
-
if (CadenzaService.signalBroker.listObservedSignals().includes(ctx2.__signalName)) {
|
|
3731
|
-
CadenzaService.emit(ctx2.__signalName, ctx2);
|
|
3732
|
-
}
|
|
3733
|
-
});
|
|
3734
|
-
socket.on("status_update", (status) => {
|
|
3735
|
-
CadenzaService.emit("meta.socket_client.status_received", status);
|
|
3736
|
-
});
|
|
3737
|
-
socket.on("connect_error", (err) => {
|
|
3738
|
-
handshake = false;
|
|
3739
|
-
socketDiagnostics.connected = false;
|
|
3740
|
-
socketDiagnostics.handshake = false;
|
|
3741
|
-
socketDiagnostics.connectErrors++;
|
|
3742
|
-
socketDiagnostics.lastHandshakeError = err.message;
|
|
3743
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3744
|
-
this.recordSocketClientError(fetchId, serviceName, URL, err);
|
|
3745
|
-
CadenzaService.log(
|
|
3746
|
-
"Socket connect error",
|
|
3747
|
-
{ error: err.message, serviceName, socketId: socket?.id, URL },
|
|
3748
|
-
"error"
|
|
3749
|
-
);
|
|
3750
|
-
CadenzaService.emit(`meta.socket_client.connect_error:${fetchId}`, err);
|
|
3751
|
-
});
|
|
3752
|
-
socket.on("reconnect_attempt", (attempt) => {
|
|
3753
|
-
socketDiagnostics.reconnectAttempts = Math.max(
|
|
3754
|
-
socketDiagnostics.reconnectAttempts,
|
|
3755
|
-
attempt
|
|
3756
|
-
);
|
|
3757
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3758
|
-
CadenzaService.log(`Reconnect attempt: ${attempt}`);
|
|
3759
|
-
});
|
|
3760
|
-
socket.on("reconnect", (attempt) => {
|
|
3761
|
-
socketDiagnostics.connected = true;
|
|
3762
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3763
|
-
CadenzaService.log(`Socket reconnected after ${attempt} tries`, {
|
|
3764
|
-
socketId: socket?.id,
|
|
3765
|
-
URL,
|
|
3766
|
-
serviceName
|
|
3767
|
-
});
|
|
3768
|
-
});
|
|
3769
|
-
socket.on("reconnect_error", (err) => {
|
|
3770
|
-
handshake = false;
|
|
3771
|
-
socketDiagnostics.connected = false;
|
|
3772
|
-
socketDiagnostics.handshake = false;
|
|
3773
|
-
socketDiagnostics.reconnectErrors++;
|
|
3774
|
-
socketDiagnostics.lastHandshakeError = err.message;
|
|
3775
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3776
|
-
this.recordSocketClientError(fetchId, serviceName, URL, err);
|
|
3777
|
-
CadenzaService.log(
|
|
3778
|
-
"Socket reconnect failed.",
|
|
3779
|
-
{ error: err.message, serviceName, URL, socketId: socket?.id },
|
|
3780
|
-
"warning"
|
|
3781
|
-
);
|
|
3782
|
-
});
|
|
3783
|
-
socket.on("error", (err) => {
|
|
3784
|
-
errorCount++;
|
|
3785
|
-
socketDiagnostics.socketErrors++;
|
|
3786
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3787
|
-
this.recordSocketClientError(fetchId, serviceName, URL, err);
|
|
3788
|
-
CadenzaService.log(
|
|
3789
|
-
"Socket error",
|
|
3790
|
-
{ error: err, socketId: socket?.id, URL, serviceName },
|
|
3791
|
-
"error"
|
|
3792
|
-
);
|
|
3793
|
-
CadenzaService.emit("meta.socket_client.error", err);
|
|
3794
|
-
});
|
|
3795
|
-
socket.on("disconnect", () => {
|
|
3796
|
-
const disconnectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3797
|
-
socketDiagnostics.connected = false;
|
|
3798
|
-
socketDiagnostics.handshake = false;
|
|
3799
|
-
socketDiagnostics.lastDisconnectAt = disconnectedAt;
|
|
3800
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3801
|
-
CadenzaService.log(
|
|
3802
|
-
"Socket disconnected.",
|
|
3803
|
-
{ URL, serviceName, socketId: socket?.id },
|
|
3804
|
-
"warning"
|
|
3805
|
-
);
|
|
3806
|
-
CadenzaService.emit(`meta.socket_client.disconnected:${fetchId}`, {
|
|
3807
|
-
serviceName,
|
|
3808
|
-
serviceAddress,
|
|
3809
|
-
servicePort
|
|
3810
|
-
});
|
|
3811
|
-
handshake = false;
|
|
3812
|
-
});
|
|
3813
|
-
socket.connect();
|
|
3814
|
-
handshakeTask = CadenzaService.createMetaTask(
|
|
3815
|
-
`Socket handshake with ${URL}`,
|
|
3816
|
-
async (ctx2, emit) => {
|
|
3817
|
-
if (handshake) return;
|
|
3818
|
-
handshake = true;
|
|
3819
|
-
socketDiagnostics.handshake = true;
|
|
3820
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3821
|
-
await emitWhenReady?.(
|
|
3822
|
-
"handshake",
|
|
3823
|
-
{
|
|
3824
|
-
serviceInstanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
3825
|
-
serviceName: CadenzaService.serviceRegistry.serviceName,
|
|
3826
|
-
isFrontend: isBrowser,
|
|
3827
|
-
__status: "success"
|
|
3828
|
-
},
|
|
3829
|
-
1e4,
|
|
3830
|
-
(result) => {
|
|
3831
|
-
if (result.status === "success") {
|
|
3832
|
-
socketDiagnostics.connected = true;
|
|
3833
|
-
socketDiagnostics.handshake = true;
|
|
3834
|
-
socketDiagnostics.lastHandshakeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3835
|
-
socketDiagnostics.lastHandshakeError = null;
|
|
3836
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3837
|
-
CadenzaService.log("Socket client connected", {
|
|
3838
|
-
result,
|
|
3839
|
-
serviceName,
|
|
3840
|
-
socketId: socket?.id,
|
|
3841
|
-
URL
|
|
4340
|
+
return resultContext;
|
|
4341
|
+
} catch (error) {
|
|
4342
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4343
|
+
const failedContext = {
|
|
4344
|
+
errored: true,
|
|
4345
|
+
__error: message
|
|
4346
|
+
};
|
|
4347
|
+
if (deputyExecId) {
|
|
4348
|
+
emitter(`meta.socket_client.delegated:${deputyExecId}`, {
|
|
4349
|
+
...failedContext,
|
|
4350
|
+
__requestDuration: Date.now() - requestSentAt
|
|
3842
4351
|
});
|
|
3843
|
-
} else {
|
|
3844
|
-
socketDiagnostics.connected = false;
|
|
3845
|
-
socketDiagnostics.handshake = false;
|
|
3846
|
-
socketDiagnostics.lastHandshakeError = result?.__error ?? result?.error ?? "Socket handshake failed";
|
|
3847
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3848
|
-
this.recordSocketClientError(
|
|
3849
|
-
fetchId,
|
|
3850
|
-
serviceName,
|
|
3851
|
-
URL,
|
|
3852
|
-
socketDiagnostics.lastHandshakeError
|
|
3853
|
-
);
|
|
3854
|
-
CadenzaService.log(
|
|
3855
|
-
"Socket handshake failed",
|
|
3856
|
-
{ result, serviceName, socketId: socket?.id, URL },
|
|
3857
|
-
"warning"
|
|
3858
|
-
);
|
|
3859
4352
|
}
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
delete ctx2.__broadcast;
|
|
3874
|
-
const requestSentAt = Date.now();
|
|
3875
|
-
pendingDelegationIds.add(ctx2.__metadata.__deputyExecId);
|
|
3876
|
-
syncPendingCounts();
|
|
3877
|
-
emitWhenReady?.(
|
|
3878
|
-
"delegation",
|
|
3879
|
-
ctx2,
|
|
3880
|
-
ctx2.__timeout ?? 6e4,
|
|
3881
|
-
(resultContext) => {
|
|
3882
|
-
const requestDuration = Date.now() - requestSentAt;
|
|
3883
|
-
const metadata = resultContext.__metadata;
|
|
3884
|
-
delete resultContext.__metadata;
|
|
3885
|
-
emit(
|
|
3886
|
-
`meta.socket_client.delegated:${ctx2.__metadata.__deputyExecId}`,
|
|
3887
|
-
{
|
|
3888
|
-
...resultContext,
|
|
3889
|
-
...metadata,
|
|
3890
|
-
__requestDuration: requestDuration
|
|
3891
|
-
}
|
|
3892
|
-
);
|
|
3893
|
-
pendingDelegationIds.delete(ctx2.__metadata.__deputyExecId);
|
|
4353
|
+
upsertDiagnostics(
|
|
4354
|
+
{
|
|
4355
|
+
lastHandshakeError: message
|
|
4356
|
+
},
|
|
4357
|
+
error
|
|
4358
|
+
);
|
|
4359
|
+
applySessionOperation("delegate", {
|
|
4360
|
+
lastHandshakeError: message
|
|
4361
|
+
});
|
|
4362
|
+
return failedContext;
|
|
4363
|
+
} finally {
|
|
4364
|
+
if (deputyExecId) {
|
|
4365
|
+
runtimeHandle.pendingDelegationIds.delete(deputyExecId);
|
|
3894
4366
|
syncPendingCounts();
|
|
3895
|
-
if (resultContext?.errored || resultContext?.failed) {
|
|
3896
|
-
this.recordSocketClientError(
|
|
3897
|
-
fetchId,
|
|
3898
|
-
serviceName,
|
|
3899
|
-
URL,
|
|
3900
|
-
resultContext?.__error ?? resultContext?.error ?? "Socket delegation failed"
|
|
3901
|
-
);
|
|
3902
|
-
}
|
|
3903
|
-
resolve(resultContext);
|
|
3904
4367
|
}
|
|
3905
|
-
|
|
3906
|
-
}
|
|
3907
|
-
|
|
3908
|
-
`
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
4368
|
+
}
|
|
4369
|
+
},
|
|
4370
|
+
`Delegate flow to service ${serviceName} with address ${url}`
|
|
4371
|
+
).doOn(`meta.service_registry.selected_instance_for_socket:${fetchId}`).attachSignal(
|
|
4372
|
+
"meta.socket_client.delegated",
|
|
4373
|
+
"meta.socket_shutdown_requested"
|
|
4374
|
+
);
|
|
4375
|
+
runtimeHandle.transmitTask = CadenzaService.createMetaTask(
|
|
4376
|
+
`Transmit signal to socket server ${url}`,
|
|
4377
|
+
async (signalCtx, emitter) => {
|
|
4378
|
+
if (signalCtx.__signalName === void 0) {
|
|
4379
|
+
return;
|
|
4380
|
+
}
|
|
4381
|
+
delete signalCtx.__broadcast;
|
|
4382
|
+
const response = await runtimeHandle.emitWhenReady?.("signal", signalCtx, 5e3) ?? {
|
|
4383
|
+
errored: true,
|
|
4384
|
+
__error: "Socket signal transmission returned no response"
|
|
4385
|
+
};
|
|
4386
|
+
applySessionOperation("transmit", {});
|
|
4387
|
+
if (signalCtx.__routineExecId) {
|
|
4388
|
+
emitter(`meta.socket_client.transmitted:${signalCtx.__routineExecId}`, {
|
|
4389
|
+
...response
|
|
4390
|
+
});
|
|
4391
|
+
}
|
|
4392
|
+
return response;
|
|
4393
|
+
},
|
|
4394
|
+
`Transmits signal to service ${serviceName} with address ${url}`
|
|
4395
|
+
).doOn(`meta.service_registry.selected_instance_for_socket:${fetchId}`).attachSignal("meta.socket_client.transmitted");
|
|
4396
|
+
CadenzaService.createEphemeralMetaTask(
|
|
4397
|
+
`Shutdown SocketClient ${url}`,
|
|
4398
|
+
(_ctx, emitter) => {
|
|
4399
|
+
runtimeHandle.handshake = false;
|
|
4400
|
+
upsertDiagnostics({
|
|
4401
|
+
connected: false,
|
|
4402
|
+
handshake: false,
|
|
4403
|
+
destroyed: true,
|
|
4404
|
+
pendingDelegations: 0,
|
|
4405
|
+
pendingTimers: 0
|
|
4406
|
+
});
|
|
4407
|
+
applySessionOperation("shutdown", {
|
|
4408
|
+
connected: false,
|
|
4409
|
+
handshake: false,
|
|
4410
|
+
destroyed: true,
|
|
4411
|
+
pendingDelegations: 0,
|
|
4412
|
+
pendingTimers: 0
|
|
4413
|
+
});
|
|
4414
|
+
CadenzaService.log("Shutting down socket client", { url, serviceName });
|
|
4415
|
+
emitter(`meta.fetch.handshake_requested:${fetchId}`, {
|
|
4416
|
+
serviceInstanceId,
|
|
4417
|
+
serviceName,
|
|
4418
|
+
communicationTypes,
|
|
4419
|
+
serviceAddress,
|
|
4420
|
+
servicePort: normalizedPort,
|
|
4421
|
+
protocol,
|
|
4422
|
+
handshakeData: {
|
|
4423
|
+
instanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
4424
|
+
serviceName: CadenzaService.serviceRegistry.serviceName
|
|
3927
4425
|
}
|
|
3928
|
-
resolve(response);
|
|
3929
4426
|
});
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
`Shutdown SocketClient ${URL}`,
|
|
3936
|
-
(ctx2, emit) => {
|
|
3937
|
-
handshake = false;
|
|
3938
|
-
socketDiagnostics.connected = false;
|
|
3939
|
-
socketDiagnostics.handshake = false;
|
|
3940
|
-
socketDiagnostics.destroyed = true;
|
|
3941
|
-
socketDiagnostics.updatedAt = Date.now();
|
|
3942
|
-
CadenzaService.log("Shutting down socket client", { URL, serviceName });
|
|
3943
|
-
socket?.close();
|
|
3944
|
-
handshakeTask?.destroy();
|
|
3945
|
-
delegateTask?.destroy();
|
|
3946
|
-
transmitTask?.destroy();
|
|
3947
|
-
handshakeTask = null;
|
|
3948
|
-
delegateTask = null;
|
|
3949
|
-
transmitTask = null;
|
|
3950
|
-
emitWhenReady = null;
|
|
3951
|
-
socket = null;
|
|
3952
|
-
emit(`meta.fetch.handshake_requested:${fetchId}`, {
|
|
3953
|
-
serviceInstanceId,
|
|
3954
|
-
serviceName,
|
|
3955
|
-
communicationTypes,
|
|
3956
|
-
serviceAddress,
|
|
3957
|
-
servicePort,
|
|
3958
|
-
protocol,
|
|
3959
|
-
handshakeData: {
|
|
3960
|
-
instanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
3961
|
-
serviceName: CadenzaService.serviceRegistry.serviceName
|
|
4427
|
+
for (const id of runtimeHandle.pendingDelegationIds) {
|
|
4428
|
+
emitter(`meta.socket_client.delegated:${id}`, {
|
|
4429
|
+
errored: true,
|
|
4430
|
+
__error: "Shutting down socket client"
|
|
4431
|
+
});
|
|
3962
4432
|
}
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
errored: true,
|
|
3967
|
-
__error: "Shutting down socket client"
|
|
4433
|
+
this.destroySocketClientRuntimeHandle(runtimeHandle);
|
|
4434
|
+
emitter("meta.socket_client.runtime_clear_requested", {
|
|
4435
|
+
fetchId
|
|
3968
4436
|
});
|
|
3969
|
-
}
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
}
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
`meta.fetch.handshake_failed:${fetchId}`,
|
|
3983
|
-
`meta.socket_client.connect_error:${fetchId}`
|
|
3984
|
-
).attachSignal("meta.fetch.handshake_requested").emits("meta.socket_client_shutdown_complete");
|
|
3985
|
-
return true;
|
|
3986
|
-
},
|
|
3987
|
-
"Connects to a specified socket server"
|
|
4437
|
+
},
|
|
4438
|
+
"Shuts down the socket client"
|
|
4439
|
+
).doOn(
|
|
4440
|
+
`meta.socket_shutdown_requested:${fetchId}`,
|
|
4441
|
+
`meta.socket_client.disconnected:${fetchId}`,
|
|
4442
|
+
`meta.fetch.handshake_failed:${fetchId}`,
|
|
4443
|
+
`meta.socket_client.connect_error:${fetchId}`
|
|
4444
|
+
).attachSignal("meta.fetch.handshake_requested").emits("meta.socket_client_shutdown_complete");
|
|
4445
|
+
return true;
|
|
4446
|
+
},
|
|
4447
|
+
{ mode: "write" }
|
|
4448
|
+
),
|
|
4449
|
+
"Connects to a specified socket server and wires runtime tasks."
|
|
3988
4450
|
).doOn("meta.fetch.handshake_complete").emitsOnFail("meta.socket_client.connect_failed");
|
|
3989
4451
|
}
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
4452
|
+
createInitialSocketServerSessionState(serverKey) {
|
|
4453
|
+
return {
|
|
4454
|
+
serverKey,
|
|
4455
|
+
useSocket: false,
|
|
4456
|
+
status: "inactive",
|
|
4457
|
+
securityProfile: "medium",
|
|
4458
|
+
networkType: "internal",
|
|
4459
|
+
connectionCount: 0,
|
|
4460
|
+
lastStartedAt: null,
|
|
4461
|
+
lastConnectedAt: null,
|
|
4462
|
+
lastDisconnectedAt: null,
|
|
4463
|
+
lastShutdownAt: null,
|
|
4464
|
+
updatedAt: 0
|
|
4465
|
+
};
|
|
3993
4466
|
}
|
|
3994
|
-
|
|
3995
|
-
const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
|
|
3996
|
-
const includeErrorHistory = Boolean(ctx.includeErrorHistory);
|
|
3997
|
-
const requestedLimit = Number(ctx.errorHistoryLimit);
|
|
3998
|
-
const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
|
|
4467
|
+
createInitialSocketClientSessionState() {
|
|
3999
4468
|
return {
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4469
|
+
fetchId: "",
|
|
4470
|
+
serviceInstanceId: "",
|
|
4471
|
+
communicationTypes: [],
|
|
4472
|
+
serviceName: "",
|
|
4473
|
+
serviceAddress: "",
|
|
4474
|
+
servicePort: 0,
|
|
4475
|
+
protocol: "http",
|
|
4476
|
+
url: "",
|
|
4477
|
+
socketId: null,
|
|
4478
|
+
connected: false,
|
|
4479
|
+
handshake: false,
|
|
4480
|
+
pendingDelegations: 0,
|
|
4481
|
+
pendingTimers: 0,
|
|
4482
|
+
reconnectAttempts: 0,
|
|
4483
|
+
connectErrors: 0,
|
|
4484
|
+
reconnectErrors: 0,
|
|
4485
|
+
socketErrors: 0,
|
|
4486
|
+
errorCount: 0,
|
|
4487
|
+
destroyed: false,
|
|
4488
|
+
lastHandshakeAt: null,
|
|
4489
|
+
lastHandshakeError: null,
|
|
4490
|
+
lastDisconnectAt: null,
|
|
4491
|
+
updatedAt: 0
|
|
4003
4492
|
};
|
|
4004
4493
|
}
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
socketId: null,
|
|
4013
|
-
connected: false,
|
|
4014
|
-
handshake: false,
|
|
4015
|
-
reconnectAttempts: 0,
|
|
4016
|
-
connectErrors: 0,
|
|
4017
|
-
reconnectErrors: 0,
|
|
4018
|
-
socketErrors: 0,
|
|
4019
|
-
pendingDelegations: 0,
|
|
4020
|
-
pendingTimers: 0,
|
|
4021
|
-
destroyed: false,
|
|
4022
|
-
lastHandshakeAt: null,
|
|
4023
|
-
lastHandshakeError: null,
|
|
4024
|
-
lastDisconnectAt: null,
|
|
4025
|
-
lastError: null,
|
|
4026
|
-
lastErrorAt: 0,
|
|
4027
|
-
errorHistory: [],
|
|
4028
|
-
updatedAt: Date.now()
|
|
4029
|
-
};
|
|
4030
|
-
this.socketClientDiagnostics.set(fetchId, state);
|
|
4031
|
-
} else {
|
|
4032
|
-
state.serviceName = serviceName;
|
|
4033
|
-
state.url = url;
|
|
4494
|
+
resolveSocketServerKey(input) {
|
|
4495
|
+
return String(input.serverKey ?? input.__socketServerKey ?? this.socketServerDefaultKey).trim() || this.socketServerDefaultKey;
|
|
4496
|
+
}
|
|
4497
|
+
resolveSocketClientFetchId(input) {
|
|
4498
|
+
const explicitFetchId = String(input.fetchId ?? "").trim();
|
|
4499
|
+
if (explicitFetchId) {
|
|
4500
|
+
return explicitFetchId;
|
|
4034
4501
|
}
|
|
4035
|
-
|
|
4502
|
+
const serviceAddress = String(input.serviceAddress ?? "").trim();
|
|
4503
|
+
const protocol = String(input.protocol ?? "http").trim();
|
|
4504
|
+
const port = this.resolveServicePort(protocol, input.servicePort);
|
|
4505
|
+
if (!serviceAddress || !port) {
|
|
4506
|
+
return void 0;
|
|
4507
|
+
}
|
|
4508
|
+
return `${serviceAddress}_${port}`;
|
|
4509
|
+
}
|
|
4510
|
+
resolveServicePort(protocol, rawPort) {
|
|
4511
|
+
if (protocol === "https") {
|
|
4512
|
+
return 443;
|
|
4513
|
+
}
|
|
4514
|
+
const parsed = Number(rawPort);
|
|
4515
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
4516
|
+
return void 0;
|
|
4517
|
+
}
|
|
4518
|
+
return Math.trunc(parsed);
|
|
4519
|
+
}
|
|
4520
|
+
createSocketServerRuntimeHandleFromContext(context) {
|
|
4521
|
+
const baseServer = context.httpsServer ?? context.httpServer;
|
|
4522
|
+
if (!baseServer) {
|
|
4523
|
+
throw new Error(
|
|
4524
|
+
"Socket server runtime setup requires either httpsServer or httpServer"
|
|
4525
|
+
);
|
|
4526
|
+
}
|
|
4527
|
+
const server = new import_socket.Server(baseServer, {
|
|
4528
|
+
pingInterval: 3e4,
|
|
4529
|
+
pingTimeout: 2e4,
|
|
4530
|
+
maxHttpBufferSize: 1e7,
|
|
4531
|
+
connectionStateRecovery: {
|
|
4532
|
+
maxDisconnectionDuration: 2 * 60 * 1e3,
|
|
4533
|
+
skipMiddlewares: true
|
|
4534
|
+
}
|
|
4535
|
+
});
|
|
4536
|
+
return {
|
|
4537
|
+
server,
|
|
4538
|
+
initialized: false,
|
|
4539
|
+
connectedSocketIds: /* @__PURE__ */ new Set(),
|
|
4540
|
+
broadcastStatusTask: null,
|
|
4541
|
+
shutdownTask: null
|
|
4542
|
+
};
|
|
4543
|
+
}
|
|
4544
|
+
destroySocketServerRuntimeHandle(runtimeHandle) {
|
|
4545
|
+
if (!runtimeHandle) {
|
|
4546
|
+
return;
|
|
4547
|
+
}
|
|
4548
|
+
runtimeHandle.broadcastStatusTask?.destroy();
|
|
4549
|
+
runtimeHandle.shutdownTask?.destroy();
|
|
4550
|
+
runtimeHandle.broadcastStatusTask = null;
|
|
4551
|
+
runtimeHandle.shutdownTask = null;
|
|
4552
|
+
runtimeHandle.connectedSocketIds.clear();
|
|
4553
|
+
runtimeHandle.initialized = false;
|
|
4554
|
+
runtimeHandle.server.close();
|
|
4555
|
+
runtimeHandle.server.removeAllListeners();
|
|
4556
|
+
}
|
|
4557
|
+
createSocketClientRuntimeHandle(url) {
|
|
4558
|
+
return {
|
|
4559
|
+
url,
|
|
4560
|
+
socket: (0, import_socket2.io)(url, {
|
|
4561
|
+
reconnection: true,
|
|
4562
|
+
reconnectionAttempts: 5,
|
|
4563
|
+
reconnectionDelay: 2e3,
|
|
4564
|
+
reconnectionDelayMax: 1e4,
|
|
4565
|
+
randomizationFactor: 0.5,
|
|
4566
|
+
transports: ["websocket"],
|
|
4567
|
+
autoConnect: false
|
|
4568
|
+
}),
|
|
4569
|
+
initialized: false,
|
|
4570
|
+
handshake: false,
|
|
4571
|
+
errorCount: 0,
|
|
4572
|
+
pendingDelegationIds: /* @__PURE__ */ new Set(),
|
|
4573
|
+
pendingTimers: /* @__PURE__ */ new Set(),
|
|
4574
|
+
emitWhenReady: null,
|
|
4575
|
+
handshakeTask: null,
|
|
4576
|
+
delegateTask: null,
|
|
4577
|
+
transmitTask: null
|
|
4578
|
+
};
|
|
4579
|
+
}
|
|
4580
|
+
destroySocketClientRuntimeHandle(runtimeHandle) {
|
|
4581
|
+
if (!runtimeHandle) {
|
|
4582
|
+
return;
|
|
4583
|
+
}
|
|
4584
|
+
runtimeHandle.initialized = false;
|
|
4585
|
+
runtimeHandle.handshake = false;
|
|
4586
|
+
runtimeHandle.emitWhenReady = null;
|
|
4587
|
+
runtimeHandle.handshakeTask?.destroy();
|
|
4588
|
+
runtimeHandle.delegateTask?.destroy();
|
|
4589
|
+
runtimeHandle.transmitTask?.destroy();
|
|
4590
|
+
runtimeHandle.handshakeTask = null;
|
|
4591
|
+
runtimeHandle.delegateTask = null;
|
|
4592
|
+
runtimeHandle.transmitTask = null;
|
|
4593
|
+
for (const timer of runtimeHandle.pendingTimers) {
|
|
4594
|
+
clearTimeout(timer);
|
|
4595
|
+
}
|
|
4596
|
+
runtimeHandle.pendingTimers.clear();
|
|
4597
|
+
runtimeHandle.pendingDelegationIds.clear();
|
|
4598
|
+
runtimeHandle.socket.close();
|
|
4599
|
+
runtimeHandle.socket.removeAllListeners();
|
|
4600
|
+
}
|
|
4601
|
+
normalizeCommunicationTypes(value) {
|
|
4602
|
+
if (!Array.isArray(value)) {
|
|
4603
|
+
return [];
|
|
4604
|
+
}
|
|
4605
|
+
return value.map((item) => String(item)).filter((item) => item.trim().length > 0);
|
|
4036
4606
|
}
|
|
4037
4607
|
getErrorMessage(error) {
|
|
4038
4608
|
if (error instanceof Error) {
|
|
@@ -4047,28 +4617,53 @@ var SocketController = class _SocketController {
|
|
|
4047
4617
|
return String(error);
|
|
4048
4618
|
}
|
|
4049
4619
|
}
|
|
4050
|
-
|
|
4051
|
-
const state
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4620
|
+
pruneDiagnosticsEntries(entries, now = Date.now()) {
|
|
4621
|
+
for (const [fetchId, state] of Object.entries(entries)) {
|
|
4622
|
+
if (state.destroyed && now - state.updatedAt > this.destroyedDiagnosticsTtlMs) {
|
|
4623
|
+
delete entries[fetchId];
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
if (Object.keys(entries).length <= this.diagnosticsMaxClientEntries) {
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
const entriesByEvictionPriority = Object.entries(entries).sort((left, right) => {
|
|
4630
|
+
if (left[1].destroyed !== right[1].destroyed) {
|
|
4631
|
+
return left[1].destroyed ? -1 : 1;
|
|
4632
|
+
}
|
|
4633
|
+
return left[1].updatedAt - right[1].updatedAt;
|
|
4060
4634
|
});
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
state.errorHistory.length - this.diagnosticsErrorHistoryLimit
|
|
4065
|
-
);
|
|
4635
|
+
while (Object.keys(entries).length > this.diagnosticsMaxClientEntries && entriesByEvictionPriority.length > 0) {
|
|
4636
|
+
const [fetchId] = entriesByEvictionPriority.shift();
|
|
4637
|
+
delete entries[fetchId];
|
|
4066
4638
|
}
|
|
4067
4639
|
}
|
|
4068
|
-
|
|
4640
|
+
async getSocketClientDiagnosticsEntry(fetchId) {
|
|
4641
|
+
const normalized = String(fetchId ?? "").trim();
|
|
4642
|
+
if (!normalized) {
|
|
4643
|
+
return void 0;
|
|
4644
|
+
}
|
|
4645
|
+
const snapshot = this.socketClientDiagnosticsActor.getState();
|
|
4646
|
+
const entries = { ...snapshot.entries };
|
|
4647
|
+
this.pruneDiagnosticsEntries(entries);
|
|
4648
|
+
return entries[normalized];
|
|
4649
|
+
}
|
|
4650
|
+
resolveTransportDiagnosticsOptions(ctx) {
|
|
4651
|
+
const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
|
|
4652
|
+
const includeErrorHistory = Boolean(ctx.includeErrorHistory);
|
|
4653
|
+
const requestedLimit = Number(ctx.errorHistoryLimit);
|
|
4654
|
+
const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
|
|
4655
|
+
return {
|
|
4656
|
+
detailLevel,
|
|
4657
|
+
includeErrorHistory,
|
|
4658
|
+
errorHistoryLimit
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
collectSocketTransportDiagnostics(ctx, diagnosticsEntries) {
|
|
4069
4662
|
const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
|
|
4070
4663
|
const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
|
|
4071
|
-
const
|
|
4664
|
+
const entries = { ...diagnosticsEntries };
|
|
4665
|
+
this.pruneDiagnosticsEntries(entries);
|
|
4666
|
+
const states = Object.values(entries).sort(
|
|
4072
4667
|
(a, b) => a.fetchId.localeCompare(b.fetchId)
|
|
4073
4668
|
);
|
|
4074
4669
|
const summary = {
|
|
@@ -4086,10 +4681,7 @@ var SocketController = class _SocketController {
|
|
|
4086
4681
|
0
|
|
4087
4682
|
),
|
|
4088
4683
|
connectErrors: states.reduce((acc, state) => acc + state.connectErrors, 0),
|
|
4089
|
-
reconnectErrors: states.reduce(
|
|
4090
|
-
(acc, state) => acc + state.reconnectErrors,
|
|
4091
|
-
0
|
|
4092
|
-
),
|
|
4684
|
+
reconnectErrors: states.reduce((acc, state) => acc + state.reconnectErrors, 0),
|
|
4093
4685
|
socketErrors: states.reduce((acc, state) => acc + state.socketErrors, 0),
|
|
4094
4686
|
latestError: states.slice().sort((a, b) => b.lastErrorAt - a.lastErrorAt).find((state) => state.lastError)?.lastError ?? null
|
|
4095
4687
|
};
|
|
@@ -7576,6 +8168,14 @@ var CadenzaService = class {
|
|
|
7576
8168
|
options.isMeta = true;
|
|
7577
8169
|
this.createDatabaseService(name, schema, description, options);
|
|
7578
8170
|
}
|
|
8171
|
+
static createActor(spec, options = {}) {
|
|
8172
|
+
this.bootstrap();
|
|
8173
|
+
return new import_core3.Actor(spec, options);
|
|
8174
|
+
}
|
|
8175
|
+
static createActorFromDefinition(definition, options = {}) {
|
|
8176
|
+
this.bootstrap();
|
|
8177
|
+
return import_core3.default.createActorFromDefinition(definition, options);
|
|
8178
|
+
}
|
|
7579
8179
|
/**
|
|
7580
8180
|
* Creates and registers a new task with the provided name, function, and optional details.
|
|
7581
8181
|
*
|
|
@@ -7993,6 +8593,7 @@ var import_core4 = require("@cadenza.io/core");
|
|
|
7993
8593
|
var index_default = CadenzaService;
|
|
7994
8594
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7995
8595
|
0 && (module.exports = {
|
|
8596
|
+
Actor,
|
|
7996
8597
|
DatabaseTask,
|
|
7997
8598
|
DebounceTask,
|
|
7998
8599
|
DeputyTask,
|