@camstack/server 1.2.688 → 1.2.689
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/CHANGELOG.md +10 -0
- package/dist/agent/agent-service.js +8 -3
- package/dist/api/core/cap-providers.js +5 -3
- package/dist/api/core/cluster-nodes.router.js +3 -3
- package/dist/api/trpc/generated-cap-mounts.js +4 -1
- package/dist/api/trpc/generated-cap-routers.js +1254 -1134
- package/dist/core/agent/agent-registry.service.js +30 -22
- package/package.json +7 -7
|
@@ -418,27 +418,17 @@ class AgentRegistryService {
|
|
|
418
418
|
* nothing re-announces it, and the operator has no reason to wait for a
|
|
419
419
|
* timer they cannot see.
|
|
420
420
|
*
|
|
421
|
-
* An ONLINE node is
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
421
|
+
* An ONLINE node is forgotten too (operator ruling 2026-10-29, D966). The old refusal said a
|
|
422
|
+
* live node re-registers at once; since D857 its leaf is on the CRL, so it cannot. The order
|
|
423
|
+
* matters: (1) revoke (the revoker also closes the node's mutual-TLS sockets, because the CRL is
|
|
424
|
+
* only read at a handshake), (2) `disconnected` in the catalog, which unregisters its services and
|
|
425
|
+
* rejects the cap calls still waiting on it with `RequestRejectedError` - a bare `nodes.delete`
|
|
426
|
+
* would leave both behind, (3) the delete and the rest of the cleanup. The agent finds out on
|
|
427
|
+
* its own: refused at the next handshake, it asks the hub (`agent-membership-watch`) and resets
|
|
428
|
+
* to unpaired after two CA-signed `revoked` answers. `stillListed` is read back at the end, so a
|
|
429
|
+
* node that came straight back (revocation failed) is reported as listed, never as forgotten.
|
|
425
430
|
*/
|
|
426
431
|
async forgetClusterNode(nodeId) {
|
|
427
|
-
if (this.isNodeOnline(nodeId)) {
|
|
428
|
-
const message = `Refused: ${nodeId} is ONLINE. Take the node down first — a live node re-registers immediately.`;
|
|
429
|
-
this.logger?.warn('forget cluster node refused', {
|
|
430
|
-
tags: { nodeId },
|
|
431
|
-
meta: { reason: 'node-online' },
|
|
432
|
-
});
|
|
433
|
-
return {
|
|
434
|
-
forgotten: false,
|
|
435
|
-
historyRemoved: false,
|
|
436
|
-
registryRemoved: false,
|
|
437
|
-
stillListed: true,
|
|
438
|
-
certificates: { outcome: 'not-attempted' },
|
|
439
|
-
message,
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
432
|
// First: a forgotten node whose leaf stays valid walks back in on its next boot (D857).
|
|
443
433
|
const certificates = await this.revokeForgottenNodeCertificates(nodeId);
|
|
444
434
|
const historyOutcome = this.historyStore
|
|
@@ -446,6 +436,8 @@ class AgentRegistryService {
|
|
|
446
436
|
: 'store-unavailable';
|
|
447
437
|
// The mirror still lists the forgotten node: the next directory re-reads.
|
|
448
438
|
this.historyMirror?.invalidate();
|
|
439
|
+
if (this.isNodeOnline(nodeId))
|
|
440
|
+
this.disconnectFromNodeCatalog(nodeId);
|
|
449
441
|
const registryRemoved = this.removeFromNodeCatalog(nodeId);
|
|
450
442
|
// Its intended set is gone with the row, so the back-fill breaker's memory
|
|
451
443
|
// of failed deliveries to it is meaningless — drop it too.
|
|
@@ -499,6 +491,20 @@ class AgentRegistryService {
|
|
|
499
491
|
message,
|
|
500
492
|
};
|
|
501
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Take a LIVE node out of routing the way Moleculer does when its transport drops: services
|
|
496
|
+
* unregistered, pending requests rejected (typed, not left to time out). Idempotent.
|
|
497
|
+
*/
|
|
498
|
+
disconnectFromNodeCatalog(nodeId) {
|
|
499
|
+
const nodes = this.nodeCatalogRegistry()?.nodes;
|
|
500
|
+
if (nodes?.disconnected === undefined) {
|
|
501
|
+
this.logger?.warn('cluster node catalog does not expose disconnected - calls may hang', {
|
|
502
|
+
tags: { nodeId },
|
|
503
|
+
});
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
nodes.disconnected(nodeId, false);
|
|
507
|
+
}
|
|
502
508
|
/** Is the node currently AVAILABLE in Moleculer's catalog? */
|
|
503
509
|
isNodeOnline(nodeId) {
|
|
504
510
|
return this.catalogNodeIds({ onlyAvailable: true }).includes(nodeId);
|
|
@@ -1173,7 +1179,8 @@ class AgentRegistryService {
|
|
|
1173
1179
|
status: {
|
|
1174
1180
|
activeCameras: 0,
|
|
1175
1181
|
cpuPercent: status.cpuPercent ?? 0,
|
|
1176
|
-
memoryPercent: status.memoryPercent
|
|
1182
|
+
memoryPercent: typeof status.memoryPercent === 'number' ? status.memoryPercent : null,
|
|
1183
|
+
processRssBytes: typeof status.processRssBytes === 'number' ? status.processRssBytes : null,
|
|
1177
1184
|
fps: {},
|
|
1178
1185
|
errors: [],
|
|
1179
1186
|
},
|
|
@@ -1237,7 +1244,7 @@ class AgentRegistryService {
|
|
|
1237
1244
|
status: {
|
|
1238
1245
|
activeCameras: 0,
|
|
1239
1246
|
cpuPercent: 0,
|
|
1240
|
-
memoryPercent:
|
|
1247
|
+
memoryPercent: null,
|
|
1241
1248
|
fps: {},
|
|
1242
1249
|
errors: [],
|
|
1243
1250
|
},
|
|
@@ -1254,7 +1261,7 @@ class AgentRegistryService {
|
|
|
1254
1261
|
// The cap contract only exposes async snapshots; the cached read is cheap
|
|
1255
1262
|
// because the addon's background sampler keeps the snapshot warm.
|
|
1256
1263
|
let cpuPercent = 0;
|
|
1257
|
-
let memoryPercent =
|
|
1264
|
+
let memoryPercent = null;
|
|
1258
1265
|
const registry = this.capabilityService.getRegistry();
|
|
1259
1266
|
if (registry) {
|
|
1260
1267
|
const metricsProvider = registry.getSingleton('metrics-provider');
|
|
@@ -1283,6 +1290,7 @@ class AgentRegistryService {
|
|
|
1283
1290
|
activeCameras: 0,
|
|
1284
1291
|
cpuPercent,
|
|
1285
1292
|
memoryPercent,
|
|
1293
|
+
processRssBytes: process.memoryUsage().rss,
|
|
1286
1294
|
fps: {},
|
|
1287
1295
|
errors: [],
|
|
1288
1296
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.689",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@camstack/addon-admin-ui": "1.2.
|
|
53
|
-
"@camstack/addon-agent-ui": "1.2.
|
|
52
|
+
"@camstack/addon-admin-ui": "1.2.517",
|
|
53
|
+
"@camstack/addon-agent-ui": "1.2.292",
|
|
54
54
|
"@camstack/addon-auth": "1.2.170",
|
|
55
|
-
"@camstack/addon-benchmark": "1.2.
|
|
55
|
+
"@camstack/addon-benchmark": "1.2.291",
|
|
56
56
|
"@camstack/addon-decoder-nodeav": "1.2.144",
|
|
57
57
|
"@camstack/addon-notifiers": "1.2.623",
|
|
58
58
|
"@camstack/addon-pipeline": "1.2.634",
|
|
@@ -60,9 +60,9 @@
|
|
|
60
60
|
"@camstack/addon-post-analysis": "1.2.651",
|
|
61
61
|
"@camstack/develop": "0.1.39",
|
|
62
62
|
"@camstack/sdk": "1.2.154",
|
|
63
|
-
"@camstack/system": "1.2.
|
|
64
|
-
"@camstack/types": "1.2.
|
|
65
|
-
"@camstack/ui-library": "1.2.
|
|
63
|
+
"@camstack/system": "1.2.518",
|
|
64
|
+
"@camstack/types": "1.2.444",
|
|
65
|
+
"@camstack/ui-library": "1.2.350",
|
|
66
66
|
"@fastify/compress": "^9.0.0",
|
|
67
67
|
"@fastify/cookie": "^11.0.2",
|
|
68
68
|
"@fastify/cors": "^11.2.0",
|