plugin-cluster-manager 1.1.7 → 1.1.11

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.
Files changed (108) hide show
  1. package/client.js +1 -0
  2. package/dist/client/AclCacheManager.d.ts +2 -0
  3. package/dist/client/CacheMonitor.d.ts +2 -0
  4. package/dist/client/ClusterManagerLayout.d.ts +2 -0
  5. package/dist/client/ClusterNodes.d.ts +2 -0
  6. package/dist/client/ContainerOrchestrator.d.ts +2 -0
  7. package/dist/client/Doctor.d.ts +2 -0
  8. package/dist/client/EventQueueMonitor.d.ts +2 -0
  9. package/dist/client/LockMonitor.d.ts +2 -0
  10. package/dist/client/NginxCacheManager.d.ts +2 -0
  11. package/dist/client/PackageInstaller.d.ts +2 -0
  12. package/dist/client/PluginOperations.d.ts +2 -0
  13. package/dist/client/RedisMonitor.d.ts +2 -0
  14. package/dist/client/TaskManager.d.ts +2 -0
  15. package/dist/client/WorkflowExecutions.d.ts +2 -0
  16. package/dist/client/index.d.ts +5 -0
  17. package/dist/client/index.js +1 -1
  18. package/dist/client/utils/clientSafeCache.d.ts +3 -0
  19. package/dist/client/utils/requestDedupInterceptor.d.ts +2 -0
  20. package/dist/client/utils.d.ts +12 -0
  21. package/dist/externalVersion.js +5 -5
  22. package/dist/index.d.ts +2 -0
  23. package/dist/locale/en-US.json +97 -1
  24. package/dist/locale/vi-VN.json +98 -1
  25. package/dist/locale/zh-CN.json +98 -1
  26. package/dist/server/actions/acl-cache.d.ts +53 -0
  27. package/dist/server/actions/acl-cache.js +1 -1
  28. package/dist/server/actions/cache-monitor.d.ts +33 -0
  29. package/dist/server/actions/cache-monitor.js +301 -0
  30. package/dist/server/actions/cluster-nodes.d.ts +64 -0
  31. package/dist/server/actions/cluster-nodes.js +394 -10
  32. package/dist/server/actions/doctor.d.ts +82 -0
  33. package/dist/server/actions/doctor.js +1250 -0
  34. package/dist/server/actions/event-queue-monitor.d.ts +13 -0
  35. package/dist/server/actions/lock-monitor.d.ts +19 -0
  36. package/dist/server/actions/orchestrator.d.ts +58 -0
  37. package/dist/server/actions/package-manager.d.ts +6 -0
  38. package/dist/server/actions/plugin-operations.d.ts +6 -0
  39. package/dist/server/actions/redis-monitor.d.ts +12 -0
  40. package/dist/server/actions/tasks.d.ts +7 -0
  41. package/dist/server/actions/workflow-executions.d.ts +7 -0
  42. package/dist/server/adapters/redis-lock-adapter.d.ts +15 -0
  43. package/dist/server/adapters/redis-node-registry.d.ts +12 -0
  44. package/dist/server/adapters/redis-pubsub-adapter.d.ts +16 -0
  45. package/dist/server/collections/app.d.ts +8 -0
  46. package/dist/server/collections/cluster-manager-acl-cache.d.ts +22 -0
  47. package/dist/server/collections/cluster-manager-cache-mgr.d.ts +22 -0
  48. package/dist/server/collections/cluster-manager-cluster.d.ts +22 -0
  49. package/dist/server/collections/cluster-manager-doctor-runs.d.ts +3 -0
  50. package/dist/server/collections/cluster-manager-doctor-runs.js +52 -0
  51. package/dist/server/collections/cluster-manager-doctor.d.ts +18 -0
  52. package/dist/server/collections/cluster-manager-doctor.js +44 -0
  53. package/dist/server/collections/cluster-manager-lock.d.ts +22 -0
  54. package/dist/server/collections/cluster-manager-plugins.d.ts +18 -0
  55. package/dist/server/collections/cluster-manager-queue.d.ts +22 -0
  56. package/dist/server/collections/cluster-manager-redis.d.ts +22 -0
  57. package/dist/server/collections/cluster-manager-workflow.d.ts +22 -0
  58. package/dist/server/collections/cluster-manager.d.ts +22 -0
  59. package/dist/server/collections/orchestrator-settings.d.ts +59 -0
  60. package/dist/server/collections/orchestrator-stacks.d.ts +102 -0
  61. package/dist/server/collections/worker-orchestrator.d.ts +22 -0
  62. package/dist/server/collections/worker-packages-configs.d.ts +3 -0
  63. package/dist/server/collections/worker-packages.d.ts +22 -0
  64. package/dist/server/hooks/cacheInvalidationHooks.d.ts +1 -0
  65. package/dist/server/hooks/cacheInvalidationHooks.js +81 -0
  66. package/dist/server/index.d.ts +1 -0
  67. package/dist/server/middlewares/listMetaCacheMiddleware.d.ts +2 -0
  68. package/dist/server/middlewares/listMetaCacheMiddleware.js +79 -0
  69. package/dist/server/orchestrator/PackageManager.d.ts +39 -0
  70. package/dist/server/orchestrator/PackageManager.js +83 -27
  71. package/dist/server/orchestrator/docker-adapter.d.ts +41 -0
  72. package/dist/server/orchestrator/index.d.ts +4 -0
  73. package/dist/server/orchestrator/k8s-adapter.d.ts +50 -0
  74. package/dist/server/orchestrator/leader-election.d.ts +48 -0
  75. package/dist/server/orchestrator/types.d.ts +84 -0
  76. package/dist/server/plugin.d.ts +26 -0
  77. package/dist/server/plugin.js +70 -8
  78. package/dist/server/utils/node.d.ts +6 -0
  79. package/dist/server/utils/redis.d.ts +29 -0
  80. package/dist/server/utils/versionManager.d.ts +10 -0
  81. package/dist/server/utils/versionManager.js +91 -0
  82. package/dist/shared/packages.d.ts +23 -0
  83. package/package.json +41 -41
  84. package/server.js +1 -0
  85. package/src/client/CacheMonitor.tsx +166 -179
  86. package/src/client/ClusterManagerLayout.tsx +48 -42
  87. package/src/client/ClusterNodes.tsx +691 -418
  88. package/src/client/Doctor.tsx +559 -0
  89. package/src/client/NginxCacheManager.tsx +415 -0
  90. package/src/client/PluginOperations.tsx +234 -234
  91. package/src/client/index.tsx +22 -14
  92. package/src/client/utils/clientSafeCache.ts +41 -0
  93. package/src/client/utils/requestDedupInterceptor.ts +213 -0
  94. package/src/locale/en-US.json +97 -1
  95. package/src/locale/vi-VN.json +98 -1
  96. package/src/locale/zh-CN.json +98 -1
  97. package/src/server/__tests__/doctor.test.ts +53 -0
  98. package/src/server/actions/acl-cache.ts +272 -272
  99. package/src/server/actions/cache-monitor.ts +453 -116
  100. package/src/server/actions/cluster-nodes.ts +882 -378
  101. package/src/server/actions/doctor.ts +1540 -0
  102. package/src/server/collections/cluster-manager-doctor-runs.ts +23 -0
  103. package/src/server/collections/cluster-manager-doctor.ts +19 -0
  104. package/src/server/hooks/cacheInvalidationHooks.ts +58 -0
  105. package/src/server/middlewares/listMetaCacheMiddleware.ts +55 -0
  106. package/src/server/orchestrator/PackageManager.ts +19 -15
  107. package/src/server/plugin.ts +353 -263
  108. package/src/server/utils/versionManager.ts +69 -0
@@ -0,0 +1,23 @@
1
+ import { CollectionOptions } from '@nocobase/database';
2
+
3
+ export default {
4
+ name: 'clusterManagerDoctorRuns',
5
+ title: 'Cluster Manager Doctor Runs',
6
+ fields: [
7
+ { name: 'id', type: 'bigInt', autoIncrement: true, primaryKey: true },
8
+ { name: 'runId', type: 'string', length: 64, unique: true, allowNull: false },
9
+ { name: 'status', type: 'string', length: 20, defaultValue: 'running', allowNull: false },
10
+ { name: 'durationMs', type: 'integer', defaultValue: 120000, allowNull: false },
11
+ { name: 'progress', type: 'integer', defaultValue: 0, allowNull: false },
12
+ { name: 'startedAt', type: 'date', allowNull: false },
13
+ { name: 'deadlineAt', type: 'date', allowNull: false },
14
+ { name: 'finishedAt', type: 'date', allowNull: true },
15
+ { name: 'finishReason', type: 'string', length: 40, allowNull: true },
16
+ { name: 'startedBy', type: 'string', length: 200, allowNull: true },
17
+ { name: 'summary', type: 'json', allowNull: true },
18
+ { name: 'report', type: 'json', allowNull: true },
19
+ { name: 'error', type: 'text', allowNull: true },
20
+ { name: 'createdAt', type: 'date' },
21
+ { name: 'updatedAt', type: 'date' },
22
+ ],
23
+ } as CollectionOptions;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * DUMMY COLLECTION
3
+ * Keeps the `clusterManagerDoctor` resourcer compatible with NocoBase
4
+ * workflow/ACL collection lookups. Diagnostic run data lives in
5
+ * `clusterManagerDoctorRuns`.
6
+ */
7
+ export default {
8
+ name: 'clusterManagerDoctor',
9
+ dumpRules: 'skip',
10
+ autoGenId: true,
11
+ createdAt: false,
12
+ updatedAt: false,
13
+ fields: [
14
+ {
15
+ name: 'name',
16
+ type: 'string',
17
+ },
18
+ ],
19
+ };
@@ -0,0 +1,58 @@
1
+ import { cacheVersionManager } from '../utils/versionManager';
2
+
3
+ export function registerCacheHooks(app: any) {
4
+ const db = app.db;
5
+
6
+ // 1. Collections & Fields changes (Metadata)
7
+ db.on('collections.afterSave', async () => {
8
+ await cacheVersionManager.incrementCollectionVersion(app);
9
+ });
10
+ db.on('collections.afterDestroy', async () => {
11
+ await cacheVersionManager.incrementCollectionVersion(app);
12
+ });
13
+ db.on('fields.afterSave', async () => {
14
+ await cacheVersionManager.incrementCollectionVersion(app);
15
+ });
16
+ db.on('fields.afterDestroy', async () => {
17
+ await cacheVersionManager.incrementCollectionVersion(app);
18
+ });
19
+
20
+ // 2. UI Schemas changes (Dynamic Layouts)
21
+ db.on('uiSchemas.afterSave', async () => {
22
+ await cacheVersionManager.incrementSchemaVersion(app);
23
+ });
24
+ db.on('uiSchemas.afterDestroy', async () => {
25
+ await cacheVersionManager.incrementSchemaVersion(app);
26
+ });
27
+
28
+ // 3. ACL, Roles & Scopes changes
29
+ const invalidateRole = async (model: any) => {
30
+ const roleName = model.get?.('roleName') || model.get?.('name');
31
+ if (roleName) {
32
+ await cacheVersionManager.incrementAclVersion(app, roleName);
33
+ } else {
34
+ await cacheVersionManager.incrementAllAclVersions(app);
35
+ }
36
+ };
37
+
38
+ db.on('roles.afterSave', invalidateRole);
39
+ db.on('roles.afterDestroy', invalidateRole);
40
+
41
+ db.on('rolesResources.afterSave', invalidateRole);
42
+ db.on('rolesResources.afterDestroy', invalidateRole);
43
+
44
+ db.on('rolesResourcesActions.afterSave', invalidateRole);
45
+ db.on('rolesResourcesActions.afterDestroy', invalidateRole);
46
+
47
+ db.on('rolesUsers.afterSave', invalidateRole);
48
+ db.on('rolesUsers.afterDestroy', invalidateRole);
49
+
50
+ db.on('scopes.afterSave', async () => {
51
+ await cacheVersionManager.incrementAllAclVersions(app);
52
+ });
53
+ db.on('scopes.afterDestroy', async () => {
54
+ await cacheVersionManager.incrementAllAclVersions(app);
55
+ });
56
+
57
+ app.logger.info('[ClusterManager] Cache invalidation hooks registered successfully');
58
+ }
@@ -0,0 +1,55 @@
1
+ import { Context } from '@nocobase/actions';
2
+ import { cacheVersionManager } from '../utils/versionManager';
3
+
4
+ const LIST_META_CACHE_TTL = 1000 * 60 * 10; // 10 minutes cache duration
5
+
6
+ function getErrorMessage(error: unknown) {
7
+ return error instanceof Error ? error.message : String(error);
8
+ }
9
+
10
+ export function createListMetaCacheMiddleware(app: any) {
11
+ return async function listMetaCacheMiddleware(ctx: Context, next: () => Promise<void>) {
12
+ const cache = app.cache;
13
+ // Skip caching if cache manager is not initialized or this is not collections:listMeta
14
+ if (!cache || ctx.action?.resourceName !== 'collections' || ctx.action?.actionName !== 'listMeta') {
15
+ return next();
16
+ }
17
+
18
+ const currentRole = ctx.state?.currentRole || 'anonymous';
19
+ const appName = ctx.headers['x-app'] || 'main';
20
+ const dataSource = ctx.headers['x-data-source'] || 'main';
21
+ const locale = ctx.headers['x-locale'] || ctx.headers['accept-language'] || 'en-US';
22
+ let cacheKey = '';
23
+ let version = 0;
24
+
25
+ try {
26
+ version = await cacheVersionManager.getCollectionVersion(app);
27
+ cacheKey = `nb:cache:${appName}:meta:v${version}:ds:${dataSource}:role:${currentRole}:lang:${locale}`;
28
+
29
+ // Try reading from NocoBase shared cache manager (Redis or Memory)
30
+ const cached = await cache.get(cacheKey);
31
+ if (cached !== undefined && cached !== null) {
32
+ ctx.body = typeof cached === 'string' ? JSON.parse(cached) : cached;
33
+ ctx.set?.('X-Cache', 'HIT');
34
+ ctx.set?.('X-Collection-Version', String(version));
35
+ return;
36
+ }
37
+ } catch (err) {
38
+ app.logger.warn(`[ClusterManager] listMeta cache read skipped: ${getErrorMessage(err)}`);
39
+ }
40
+
41
+ await next();
42
+
43
+ // If the response is valid, write to cache manager. This must not call next() again.
44
+ if (ctx.status === 200 && ctx.body && cacheKey) {
45
+ try {
46
+ const valueToCache = typeof ctx.body === 'string' ? ctx.body : JSON.stringify(ctx.body);
47
+ await cache.set(cacheKey, valueToCache, LIST_META_CACHE_TTL);
48
+ ctx.set?.('X-Cache', 'MISS');
49
+ ctx.set?.('X-Collection-Version', String(version));
50
+ } catch (err) {
51
+ app.logger.warn(`[ClusterManager] listMeta cache write skipped: ${getErrorMessage(err)}`);
52
+ }
53
+ }
54
+ };
55
+ }
@@ -1,5 +1,6 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { getRedisClient } from '../utils/redis';
3
+ import { getLocalNodeId } from '../utils/node';
3
4
  import { promises as fsp } from 'fs';
4
5
  import path from 'path';
5
6
  import Application from '@nocobase/server';
@@ -451,21 +452,24 @@ export class PackageManager {
451
452
  const redisClient = getRedisClient(this.app);
452
453
  const podName = process.env.POD_NAME || require('os').hostname();
453
454
  if (redisClient) {
454
- const key = `orchestrator:pkg-status:${podName}`;
455
- await redisClient.sendCommand([
456
- 'SET',
457
- key,
458
- JSON.stringify({
459
- initStatus,
460
- initProgressPercent,
461
- initProgressLog,
462
- lastInitAt: new Date(),
463
- lastInitLog: logs.join('\n'),
464
- ...extraValues,
465
- }),
466
- 'EX',
467
- '86400', // expire after 1 day
468
- ]);
455
+ const statusPayload = JSON.stringify({
456
+ initStatus,
457
+ initProgressPercent,
458
+ initProgressLog,
459
+ lastInitAt: new Date(),
460
+ lastInitLog: logs.join('\n'),
461
+ ...extraValues,
462
+ });
463
+ const keys = [`orchestrator:pkg-status:${podName}`, `cluster-manager:pkg-status:${getLocalNodeId(this.app)}`];
464
+ for (const key of keys) {
465
+ await redisClient.sendCommand([
466
+ 'SET',
467
+ key,
468
+ statusPayload,
469
+ 'EX',
470
+ '86400', // expire after 1 day
471
+ ]);
472
+ }
469
473
  }
470
474
 
471
475
  // We can also keep the global DB record as a fallback/historical record