plugin-cluster-manager 1.1.10 → 1.1.13

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 (119) hide show
  1. package/client-v2.d.ts +2 -0
  2. package/client-v2.js +1 -0
  3. package/client.js +1 -0
  4. package/dist/client/index.js +1 -1
  5. package/dist/client-v2/914.5dc1105cf3ada6a6.js +10 -0
  6. package/dist/client-v2/index.js +10 -0
  7. package/dist/externalVersion.js +6 -5
  8. package/dist/locale/en-US.json +138 -28
  9. package/dist/locale/vi-VN.json +139 -28
  10. package/dist/locale/zh-CN.json +140 -28
  11. package/dist/server/actions/cache-monitor.js +301 -0
  12. package/dist/server/actions/cluster-nodes.js +391 -11
  13. package/dist/server/actions/doctor.js +1246 -0
  14. package/dist/server/actions/orchestrator.js +37 -0
  15. package/dist/server/actions/queue-mappings.js +107 -0
  16. package/dist/server/collections/cluster-manager-doctor-runs.js +52 -0
  17. package/dist/server/collections/cluster-manager-doctor.js +44 -0
  18. package/dist/server/collections/worker-queue-mappings.js +106 -0
  19. package/dist/server/hooks/cacheInvalidationHooks.js +81 -0
  20. package/dist/server/middlewares/listMetaCacheMiddleware.js +79 -0
  21. package/dist/server/orchestrator/PackageManager.js +21 -24
  22. package/dist/server/orchestrator/docker-adapter.js +49 -27
  23. package/dist/server/plugin.js +71 -16
  24. package/dist/server/queue-scanner.js +141 -0
  25. package/dist/server/utils/node.js +30 -2
  26. package/dist/server/utils/versionManager.js +91 -0
  27. package/package.json +9 -5
  28. package/server.js +1 -0
  29. package/src/client/AclCacheManager.tsx +292 -287
  30. package/src/client/CacheMonitor.tsx +166 -179
  31. package/src/client/ClusterManagerLayout.tsx +54 -42
  32. package/src/client/ClusterNodes.tsx +698 -418
  33. package/src/client/ContainerOrchestrator.tsx +184 -102
  34. package/src/client/Doctor.tsx +559 -0
  35. package/src/client/NginxCacheManager.tsx +415 -0
  36. package/src/client/PluginOperations.tsx +234 -234
  37. package/src/client/QueueAssignment.tsx +355 -0
  38. package/src/client/TaskManager.tsx +194 -187
  39. package/src/client/WorkflowExecutions.tsx +243 -238
  40. package/src/client/index.tsx +22 -14
  41. package/src/client/utils/clientSafeCache.ts +41 -0
  42. package/src/client/utils/requestDedupInterceptor.ts +213 -0
  43. package/src/client-v2/plugin.tsx +24 -0
  44. package/src/locale/en-US.json +138 -28
  45. package/src/locale/vi-VN.json +139 -28
  46. package/src/locale/zh-CN.json +140 -28
  47. package/src/server/__tests__/doctor.test.ts +53 -0
  48. package/src/server/actions/acl-cache.ts +272 -272
  49. package/src/server/actions/cache-monitor.ts +453 -116
  50. package/src/server/actions/cluster-nodes.ts +878 -378
  51. package/src/server/actions/doctor.ts +1536 -0
  52. package/src/server/actions/orchestrator.ts +54 -2
  53. package/src/server/actions/queue-mappings.ts +94 -0
  54. package/src/server/collections/cluster-manager-doctor-runs.ts +23 -0
  55. package/src/server/collections/cluster-manager-doctor.ts +19 -0
  56. package/src/server/collections/worker-queue-mappings.ts +85 -0
  57. package/src/server/hooks/cacheInvalidationHooks.ts +58 -0
  58. package/src/server/middlewares/listMetaCacheMiddleware.ts +55 -0
  59. package/src/server/orchestrator/PackageManager.ts +20 -24
  60. package/src/server/orchestrator/docker-adapter.ts +74 -37
  61. package/src/server/plugin.ts +347 -270
  62. package/src/server/queue-scanner.ts +154 -0
  63. package/src/server/utils/node.ts +48 -0
  64. package/src/server/utils/versionManager.ts +69 -0
  65. package/dist/client/AclCacheManager.d.ts +0 -2
  66. package/dist/client/CacheMonitor.d.ts +0 -2
  67. package/dist/client/ClusterManagerLayout.d.ts +0 -2
  68. package/dist/client/ClusterNodes.d.ts +0 -2
  69. package/dist/client/ContainerOrchestrator.d.ts +0 -2
  70. package/dist/client/EventQueueMonitor.d.ts +0 -2
  71. package/dist/client/LockMonitor.d.ts +0 -2
  72. package/dist/client/PackageInstaller.d.ts +0 -2
  73. package/dist/client/PluginOperations.d.ts +0 -2
  74. package/dist/client/RedisMonitor.d.ts +0 -2
  75. package/dist/client/TaskManager.d.ts +0 -2
  76. package/dist/client/WorkflowExecutions.d.ts +0 -2
  77. package/dist/client/index.d.ts +0 -5
  78. package/dist/client/utils.d.ts +0 -12
  79. package/dist/index.d.ts +0 -2
  80. package/dist/server/actions/acl-cache.d.ts +0 -53
  81. package/dist/server/actions/cache-monitor.d.ts +0 -23
  82. package/dist/server/actions/cluster-nodes.d.ts +0 -49
  83. package/dist/server/actions/event-queue-monitor.d.ts +0 -13
  84. package/dist/server/actions/lock-monitor.d.ts +0 -19
  85. package/dist/server/actions/orchestrator.d.ts +0 -58
  86. package/dist/server/actions/package-manager.d.ts +0 -6
  87. package/dist/server/actions/plugin-operations.d.ts +0 -6
  88. package/dist/server/actions/redis-monitor.d.ts +0 -12
  89. package/dist/server/actions/tasks.d.ts +0 -7
  90. package/dist/server/actions/workflow-executions.d.ts +0 -7
  91. package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
  92. package/dist/server/adapters/redis-node-registry.d.ts +0 -12
  93. package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
  94. package/dist/server/collections/app.d.ts +0 -8
  95. package/dist/server/collections/cluster-manager-acl-cache.d.ts +0 -22
  96. package/dist/server/collections/cluster-manager-cache-mgr.d.ts +0 -22
  97. package/dist/server/collections/cluster-manager-cluster.d.ts +0 -22
  98. package/dist/server/collections/cluster-manager-lock.d.ts +0 -22
  99. package/dist/server/collections/cluster-manager-plugins.d.ts +0 -18
  100. package/dist/server/collections/cluster-manager-queue.d.ts +0 -22
  101. package/dist/server/collections/cluster-manager-redis.d.ts +0 -22
  102. package/dist/server/collections/cluster-manager-workflow.d.ts +0 -22
  103. package/dist/server/collections/cluster-manager.d.ts +0 -22
  104. package/dist/server/collections/orchestrator-settings.d.ts +0 -59
  105. package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
  106. package/dist/server/collections/worker-orchestrator.d.ts +0 -22
  107. package/dist/server/collections/worker-packages-configs.d.ts +0 -3
  108. package/dist/server/collections/worker-packages.d.ts +0 -22
  109. package/dist/server/orchestrator/PackageManager.d.ts +0 -39
  110. package/dist/server/orchestrator/docker-adapter.d.ts +0 -41
  111. package/dist/server/orchestrator/index.d.ts +0 -4
  112. package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
  113. package/dist/server/orchestrator/leader-election.d.ts +0 -48
  114. package/dist/server/orchestrator/types.d.ts +0 -84
  115. package/dist/server/plugin.d.ts +0 -26
  116. package/dist/server/utils/node.d.ts +0 -6
  117. package/dist/server/utils/redis.d.ts +0 -29
  118. package/dist/shared/packages.d.ts +0 -23
  119. /package/{dist/server/index.d.ts → src/client-v2/index.tsx} +0 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * QueueScanner — discovers all registered queues in the system.
3
+ *
4
+ * Two sources:
5
+ * 1. EventQueue events (registered via app.eventQueue.subscribe)
6
+ * 2. Redis List-based queues (convention *:plugin-*:queue)
7
+ *
8
+ * Used by the Queue Assignment UI to let admins map queues to worker stacks.
9
+ */
10
+
11
+ import type { Application } from '@nocobase/server';
12
+ import { getRedisClient } from './utils/redis';
13
+
14
+ export type QueueItem = {
15
+ name: string;
16
+ label: string;
17
+ description: string;
18
+ type: 'event-queue' | 'redis-list';
19
+ pending: number | null;
20
+ };
21
+
22
+ const KNOWN_QUEUE_LABELS: Record<string, { label: string; description: string }> = {
23
+ 'workflow:process': {
24
+ label: 'Workflow',
25
+ description: 'Process workflow executions (plugin-workflow)',
26
+ },
27
+ 'async-task:process': {
28
+ label: 'Async Tasks',
29
+ description: 'Execute async tasks (plugin-async-task-manager)',
30
+ },
31
+ 'knowledge-base:document-vectorize': {
32
+ label: 'Document Vectorization',
33
+ description: 'Vectorize knowledge base documents (plugin-knowledge-base)',
34
+ },
35
+ 'git-review:process': {
36
+ label: 'Git Review',
37
+ description: 'AI code review jobs (plugin-git-manager)',
38
+ },
39
+ 'build-guide:process': {
40
+ label: 'Build Guide',
41
+ description: 'Build user guide pages (plugin-build-guide-block)',
42
+ },
43
+ 'build-ui-template:process': {
44
+ label: 'Build UI Template',
45
+ description: 'Build UI template pages (plugin-build-ui-template)',
46
+ },
47
+ };
48
+
49
+ /** Redis key patterns for List-based queues (same as event-queue-monitor.ts) */
50
+ const REDIS_QUEUE_PATTERNS = ['*:plugin-git-manager:review:queue', '*:plugin-build-guide-block:build:queue'];
51
+
52
+ function describeRedisQueueKey(key: string): { label: string; description: string } {
53
+ const parts = String(key).split(':');
54
+ const plugin = parts[parts.length - 3] || 'unknown';
55
+ const queue = parts[parts.length - 2] || key;
56
+ return {
57
+ label: `${queue} (${plugin})`,
58
+ description: `Redis List queue from ${plugin}`,
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Discover all queues from EventQueue subscribers.
64
+ */
65
+ function scanEventQueue(app: Application): QueueItem[] {
66
+ const eq = (app as any).eventQueue;
67
+ if (!eq || !eq.events) return [];
68
+
69
+ const events: Map<string, { concurrency?: number; interval?: number; shared?: boolean }> = eq.events;
70
+ const items: QueueItem[] = [];
71
+
72
+ for (const [channel] of events.entries()) {
73
+ const known = KNOWN_QUEUE_LABELS[channel];
74
+ items.push({
75
+ name: channel,
76
+ label: known?.label ?? channel,
77
+ description: known?.description ?? `EventQueue channel: ${channel}`,
78
+ type: 'event-queue',
79
+ pending: null,
80
+ });
81
+ }
82
+
83
+ return items;
84
+ }
85
+
86
+ /**
87
+ * Discover Redis List-based queues via SCAN.
88
+ */
89
+ async function scanRedisQueues(app: Application): Promise<QueueItem[]> {
90
+ const redis = getRedisClient(app);
91
+ if (!redis) {
92
+ return [];
93
+ }
94
+
95
+ const seen = new Set<string>();
96
+ const items: QueueItem[] = [];
97
+
98
+ for (const pattern of REDIS_QUEUE_PATTERNS) {
99
+ try {
100
+ const keys: string[] = await redis.sendCommand(['SCAN', '0', 'MATCH', pattern, 'COUNT', '200']);
101
+ const keyList: string[] = typeof keys[1]?.length === 'number' ? keys[1] : [];
102
+
103
+ for (const key of keyList) {
104
+ if (seen.has(key)) continue;
105
+ seen.add(key);
106
+
107
+ const desc = describeRedisQueueKey(key);
108
+ let pending = 0;
109
+ try {
110
+ pending = Number(await redis.sendCommand(['LLEN', key])) || 0;
111
+ } catch {
112
+ pending = 0;
113
+ }
114
+
115
+ items.push({
116
+ name: key,
117
+ label: desc.label,
118
+ description: desc.description,
119
+ type: 'redis-list',
120
+ pending,
121
+ });
122
+ }
123
+ } catch {
124
+ // SCAN not supported or permission denied
125
+ }
126
+ }
127
+
128
+ return items;
129
+ }
130
+
131
+ /**
132
+ * Full queue scan — merges EventQueue + Redis results.
133
+ */
134
+ export async function scanQueues(app: Application): Promise<{ queues: QueueItem[]; total: number }> {
135
+ const eventQueues = scanEventQueue(app);
136
+ const redisQueues = await scanRedisQueues(app);
137
+
138
+ // Deduplicate: if a queue name appears in both sources, prefer EventQueue
139
+ const seenNames = new Set<string>();
140
+ const merged: QueueItem[] = [];
141
+
142
+ for (const q of eventQueues) {
143
+ merged.push(q);
144
+ seenNames.add(q.name);
145
+ }
146
+ for (const q of redisQueues) {
147
+ if (!seenNames.has(q.name)) {
148
+ merged.push(q);
149
+ seenNames.add(q.name);
150
+ }
151
+ }
152
+
153
+ return { queues: merged, total: merged.length };
154
+ }
@@ -1,5 +1,53 @@
1
1
  import os from 'os';
2
2
 
3
+ export type NodeRole = 'app' | 'worker' | 'sandbox';
4
+
5
+ /**
6
+ * Determine whether a WORKER_MODE value denotes a queue-processing worker
7
+ * (i.e. a node that does NOT serve HTTP), following NocoBase v2.1.x semantics:
8
+ * '' → app node (serves HTTP + every queue)
9
+ * '!' → app node (serves HTTP only)
10
+ * '*' → worker (serves all queues, no HTTP)
11
+ * 'a:b,c:d' → worker (serves the listed queue topics, no HTTP)
12
+ * '-' → transient subprocess (not a long-lived worker)
13
+ * Legacy literals 'worker' / 'task' are still tolerated for older deployments.
14
+ * A combined value containing '!' (e.g. '!,workflow:process') still serves
15
+ * HTTP, so it is treated as an app node.
16
+ */
17
+ export function isWorkerMode(workerMode?: string): boolean {
18
+ const mode = (workerMode ?? process.env.WORKER_MODE ?? '').trim();
19
+ if (!mode || mode === 'main' || mode === 'app') return false;
20
+ if (mode === '-') return false;
21
+ const topics = mode
22
+ .split(',')
23
+ .map((t) => t.trim())
24
+ .filter(Boolean);
25
+ if (topics.includes('!')) return false;
26
+ return true;
27
+ }
28
+
29
+ /**
30
+ * Resolve a node role from its descriptor. APP_ROLE (explicit) wins, then an
31
+ * explicit sandbox flag, then WORKER_MODE parsing. Works for both the local
32
+ * process (pass process.env values) and remote node records read from Redis.
33
+ */
34
+ export function getNodeRoleFrom(opts: { workerMode?: string; appRole?: string; isSandbox?: boolean }): NodeRole {
35
+ if (opts.appRole === 'app' || opts.appRole === 'worker' || opts.appRole === 'sandbox') {
36
+ return opts.appRole;
37
+ }
38
+ if (opts.isSandbox) return 'sandbox';
39
+ return isWorkerMode(opts.workerMode) ? 'worker' : 'app';
40
+ }
41
+
42
+ /** Resolve the role of the current Node.js process from its environment. */
43
+ export function getLocalRole(): NodeRole {
44
+ return getNodeRoleFrom({
45
+ workerMode: process.env.WORKER_MODE,
46
+ appRole: process.env.APP_ROLE,
47
+ isSandbox: process.env.SKILL_HUB_SANDBOX === 'true',
48
+ });
49
+ }
50
+
3
51
  /**
4
52
  * Generate a universally unique identifier for this specific Node.js process.
5
53
  * Combines app name, worker mode, hostname, port, and PID to ensure uniqueness
@@ -0,0 +1,69 @@
1
+ import { getRedisClient } from './redis';
2
+
3
+ const localCounters = new Map<string, number>();
4
+
5
+ async function getVersion(app: any, key: string): Promise<number> {
6
+ const redis = getRedisClient(app);
7
+ if (redis) {
8
+ try {
9
+ const val = await redis.sendCommand(['GET', key]);
10
+ return val ? parseInt(val, 10) : 1;
11
+ } catch {
12
+ // Fallback to local
13
+ }
14
+ }
15
+ return localCounters.get(key) || 1;
16
+ }
17
+
18
+ async function incrementVersion(app: any, key: string): Promise<number> {
19
+ const redis = getRedisClient(app);
20
+ if (redis) {
21
+ try {
22
+ const val = await redis.sendCommand(['INCR', key]);
23
+ return parseInt(val, 10);
24
+ } catch {
25
+ // Fallback to local
26
+ }
27
+ }
28
+ const next = (localCounters.get(key) || 1) + 1;
29
+ localCounters.set(key, next);
30
+ return next;
31
+ }
32
+
33
+ export const cacheVersionManager = {
34
+ async getCollectionVersion(app: any): Promise<number> {
35
+ return getVersion(app, 'nocobase:version:collections');
36
+ },
37
+
38
+ async incrementCollectionVersion(app: any): Promise<number> {
39
+ app.logger.info('[ClusterManager] Incrementing collections cache version due to schema change');
40
+ return incrementVersion(app, 'nocobase:version:collections');
41
+ },
42
+
43
+ async getSchemaVersion(app: any): Promise<number> {
44
+ return getVersion(app, 'nocobase:version:schemas');
45
+ },
46
+
47
+ async incrementSchemaVersion(app: any): Promise<number> {
48
+ app.logger.info('[ClusterManager] Incrementing uiSchemas cache version due to UI change');
49
+ return incrementVersion(app, 'nocobase:version:schemas');
50
+ },
51
+
52
+ async getAclVersion(app: any, roleName: string): Promise<number> {
53
+ return getVersion(app, `nocobase:version:acl:role:${roleName}`);
54
+ },
55
+
56
+ async incrementAclVersion(app: any, roleName: string): Promise<number> {
57
+ app.logger.info(`[ClusterManager] Incrementing ACL cache version for role: ${roleName}`);
58
+ return incrementVersion(app, `nocobase:version:acl:role:${roleName}`);
59
+ },
60
+
61
+ async incrementAllAclVersions(app: any): Promise<number> {
62
+ app.logger.info('[ClusterManager] Incrementing global ACL cache version');
63
+ return incrementVersion(app, 'nocobase:version:acl:global');
64
+ },
65
+
66
+ async getGlobalAclVersion(app: any): Promise<number> {
67
+ return getVersion(app, 'nocobase:version:acl:global');
68
+ },
69
+ };
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function AclCacheManager(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function CacheMonitor(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function ClusterManagerLayout(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function ClusterNodes(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function ContainerOrchestrator(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function EventQueueMonitor(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function LockMonitor(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare const PackageInstaller: React.FC;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function PluginOperations(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function RedisMonitor(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function TaskManager(): React.JSX.Element;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare function WorkflowExecutions(): React.JSX.Element;
@@ -1,5 +0,0 @@
1
- import { Plugin } from '@nocobase/client';
2
- export declare class PluginClusterManagerClient extends Plugin {
3
- load(): Promise<void>;
4
- }
5
- export default PluginClusterManagerClient;
@@ -1,12 +0,0 @@
1
- /**
2
- * Shared i18n hook for the cluster-manager plugin.
3
- */
4
- export declare function useT(): (key: string) => string;
5
- /**
6
- * Format bytes into human-readable string (B, KB, MB, GB).
7
- */
8
- export declare function formatBytes(bytes: number): string;
9
- /**
10
- * Format seconds into human-readable uptime string (e.g., "2d 5h 30m").
11
- */
12
- export declare function formatUptime(seconds: number): string;
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './server';
2
- export { default } from './server';
@@ -1,53 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- /**
3
- * In-memory ACL stats counter.
4
- * Tracks total checks, cache hits/misses per role:resource:action.
5
- */
6
- export interface AclCacheStats {
7
- totalChecks: number;
8
- cacheHits: number;
9
- cacheMisses: number;
10
- startedAt: string;
11
- detailByRole: Record<string, {
12
- checks: number;
13
- hits: number;
14
- misses: number;
15
- }>;
16
- }
17
- /**
18
- * Middleware that caches the permission object computed by the ACL middleware.
19
- * Install via: app.acl.use(aclCacheMiddleware, { tag: 'aclCache', before: 'core', after: 'allow-manager' })
20
- *
21
- * FIX: Previously monkey-patched ctx.app.acl.can per-request, which is a race condition
22
- * because acl is a shared singleton across concurrent requests. Now we use a post-check
23
- * approach that reads from cache first and writes after the ACL middleware runs, without
24
- * ever replacing the shared acl.can method.
25
- */
26
- export declare function createAclCacheMiddleware(app: any): (ctx: Context, next: () => Promise<void>) => Promise<void>;
27
- export declare const aclCacheActions: {
28
- /**
29
- * GET /clusterManagerAclCache:stats
30
- * Returns ACL cache hit/miss statistics
31
- */
32
- stats(ctx: Context, next: () => Promise<void>): Promise<void>;
33
- /**
34
- * GET /clusterManagerAclCache:listKeys
35
- * Lists all cached ACL permission keys
36
- */
37
- listKeys(ctx: Context, next: () => Promise<void>): Promise<void>;
38
- /**
39
- * POST /clusterManagerAclCache:clear
40
- * Clear all ACL cache entries and reset stats
41
- */
42
- clear(ctx: Context, next: () => Promise<void>): Promise<void>;
43
- /**
44
- * POST /clusterManagerAclCache:resetStats
45
- * Reset the in-memory ACL stats counters
46
- */
47
- resetStats(ctx: Context, next: () => Promise<void>): Promise<void>;
48
- /**
49
- * POST /clusterManagerAclCache:clearRole
50
- * Clear ACL cache entries for a specific role
51
- */
52
- clearRole(ctx: Context, next: () => Promise<void>): Promise<void>;
53
- };
@@ -1,23 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const cacheMonitorActions: {
3
- /**
4
- * GET /clusterManagerCacheMgr:stores
5
- * List all registered cache stores and their config
6
- */
7
- stores(ctx: Context, next: () => Promise<void>): Promise<void>;
8
- /**
9
- * GET /clusterManagerCacheMgr:caches
10
- * List all created named caches
11
- */
12
- caches(ctx: Context, next: () => Promise<void>): Promise<void>;
13
- /**
14
- * GET /clusterManagerCacheMgr:redisMemory
15
- * Get Redis memory usage for cache keys
16
- */
17
- redisMemory(ctx: Context, next: () => Promise<void>): Promise<void>;
18
- /**
19
- * POST /clusterManagerCacheMgr:flushAll
20
- * Flush all caches via CacheManager
21
- */
22
- flushAll(ctx: Context, next: () => Promise<void>): Promise<void>;
23
- };
@@ -1,49 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- /**
3
- * Read the last N lines from the local system log file.
4
- * Extracted so it can be called from both the HTTP action and the PubSub subscriber.
5
- */
6
- export declare function readLocalLogs(app: any, maxLines: number): Promise<{
7
- node: {
8
- hostname: string;
9
- pid: number;
10
- workerMode: string;
11
- };
12
- lines: string[];
13
- file: string;
14
- }>;
15
- export declare const clusterActions: {
16
- /**
17
- * GET /clusterManagerCluster:current
18
- * Always returns info about the APP node (not workers).
19
- * If this request is handled by a worker, we look up the APP node from Redis.
20
- */
21
- current(ctx: Context, next: () => Promise<void>): Promise<void>;
22
- /**
23
- * GET /clusterManagerCluster:list
24
- * Returns all known cluster environments/nodes (if discovery adapter supports it)
25
- */
26
- list(ctx: Context, next: () => Promise<void>): Promise<void>;
27
- /**
28
- * GET /clusterManagerCluster:health
29
- * Health check for all subsystems
30
- */
31
- health(ctx: Context, next: () => Promise<void>): Promise<void>;
32
- /**
33
- * POST /clusterManagerCluster:restart
34
- * Publishes a restart signal to target nodes orchestrating a soft NocoBase restart or a hard docker daemon rebirth
35
- */
36
- restart(ctx: Context, next: () => Promise<void>): Promise<void>;
37
- /**
38
- * GET /clusterManagerCluster:logs?targetNodeId=xxx&lines=200
39
- *
40
- * HA-aware log viewer. Reads logs from a specific node in the cluster.
41
- *
42
- * Flow:
43
- * 1. If targetNodeId matches current node (or is empty) → read local FS directly
44
- * 2. Otherwise → publish a log request via PubSub → target node reads its local FS
45
- * and writes the result to a Redis key → this handler polls Redis until the
46
- * response arrives (max 10s) → returns it to the client
47
- */
48
- logs(ctx: Context, next: () => Promise<void>): Promise<void>;
49
- };
@@ -1,13 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const eventQueueActions: {
3
- /**
4
- * GET /clusterManagerQueue:stats
5
- * Returns event queue statistics
6
- */
7
- stats(ctx: Context, next: () => Promise<void>): Promise<void>;
8
- /**
9
- * GET /clusterManagerQueue:messages
10
- * List pending messages in a specific channel (memory adapter only)
11
- */
12
- messages(ctx: Context, next: () => Promise<void>): Promise<void>;
13
- };
@@ -1,19 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const lockActions: {
3
- /**
4
- * GET /clusterManagerLock:info
5
- * Returns lock manager info
6
- */
7
- info(ctx: Context, next: () => Promise<void>): Promise<void>;
8
- /**
9
- * GET /clusterManagerLock:list
10
- * List active locks
11
- */
12
- list(ctx: Context, next: () => Promise<void>): Promise<void>;
13
- /**
14
- * POST /clusterManagerLock:release
15
- * Force release a stuck lock (admin emergency action)
16
- * Uses compare-and-swap via DEL for Redis locks with the correct key prefix.
17
- */
18
- release(ctx: Context, next: () => Promise<void>): Promise<void>;
19
- };
@@ -1,58 +0,0 @@
1
- /**
2
- * Orchestrator Actions
3
- *
4
- * API endpoints for container management. Write operations (scale, start, stop, remove)
5
- * are guarded by leader election — only the leader node can execute them.
6
- */
7
- import { Context } from '@nocobase/actions';
8
- export declare const orchestratorActions: {
9
- /**
10
- * GET /workerOrchestrator:ping
11
- * Test connectivity to the container runtime
12
- */
13
- ping(ctx: Context, next: () => Promise<void>): Promise<void>;
14
- /**
15
- * GET /workerOrchestrator:containers?stackId=1
16
- * List live containers for a stack
17
- */
18
- containers(ctx: Context, next: () => Promise<void>): Promise<void>;
19
- /**
20
- * POST /workerOrchestrator:scale
21
- * Body: { stackId: 1, replicas: 3 }
22
- * Leader-only
23
- */
24
- scale(ctx: Context, next: () => Promise<void>): Promise<void>;
25
- /**
26
- * POST /workerOrchestrator:start
27
- * Body: { stackId: 1, containerId: "abc123" }
28
- * Leader-only
29
- */
30
- start(ctx: Context, next: () => Promise<void>): Promise<void>;
31
- /**
32
- * POST /workerOrchestrator:stop
33
- * Body: { stackId: 1, containerId: "abc123" }
34
- * Leader-only
35
- */
36
- stop(ctx: Context, next: () => Promise<void>): Promise<void>;
37
- /**
38
- * POST /workerOrchestrator:remove
39
- * Body: { stackId: 1, containerId: "abc123" }
40
- * Leader-only
41
- */
42
- remove(ctx: Context, next: () => Promise<void>): Promise<void>;
43
- /**
44
- * GET /workerOrchestrator:stats?containerId=abc123
45
- * Get real-time stats for a container
46
- */
47
- stats(ctx: Context, next: () => Promise<void>): Promise<void>;
48
- /**
49
- * GET /workerOrchestrator:logs?containerId=abc123&tail=100
50
- * Get tail logs from a container
51
- */
52
- logs(ctx: Context, next: () => Promise<void>): Promise<void>;
53
- /**
54
- * GET /workerOrchestrator:networks
55
- * List available networks (if supported by adapter)
56
- */
57
- networks(ctx: Context, next: () => Promise<void>): Promise<void>;
58
- };
@@ -1,6 +0,0 @@
1
- export declare const packageManagerActions: {
2
- installPackages(ctx: any, next: () => Promise<void>): Promise<void>;
3
- getPackageConfig(ctx: any, next: () => Promise<void>): Promise<void>;
4
- savePackageConfig(ctx: any, next: () => Promise<void>): Promise<void>;
5
- resetInitStatus(ctx: any, next: () => Promise<void>): Promise<void>;
6
- };
@@ -1,6 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const pluginOperationsActions: {
3
- list(ctx: Context, next: () => Promise<void>): Promise<void>;
4
- forceDisable(ctx: Context, next: () => Promise<void>): Promise<void>;
5
- forceRemove(ctx: Context, next: () => Promise<void>): Promise<void>;
6
- };
@@ -1,12 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const redisActions: {
3
- info(ctx: Context, next: () => Promise<void>): Promise<void>;
4
- clients(ctx: Context, next: () => Promise<void>): Promise<void>;
5
- pubsub(ctx: Context, next: () => Promise<void>): Promise<void>;
6
- slowlog(ctx: Context, next: () => Promise<void>): Promise<void>;
7
- /**
8
- * GET /clusterManagerRedis:syncMessages
9
- * Returns info about NocoBase sync message channels (pub/sub layer)
10
- */
11
- syncMessages(ctx: Context, next: () => Promise<void>): Promise<void>;
12
- };
@@ -1,7 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const tasksActions: {
3
- list(ctx: Context, next: () => Promise<void>): Promise<void>;
4
- cancel(ctx: Context, next: () => Promise<void>): Promise<void>;
5
- retry(ctx: Context, next: () => Promise<void>): Promise<void>;
6
- purge(ctx: Context, next: () => Promise<void>): Promise<void>;
7
- };
@@ -1,7 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- export declare const workflowActions: {
3
- list(ctx: Context, next: () => Promise<void>): Promise<void>;
4
- getJobs(ctx: Context, next: () => Promise<void>): Promise<void>;
5
- cancel(ctx: Context, next: () => Promise<void>): Promise<void>;
6
- purge(ctx: Context, next: () => Promise<void>): Promise<void>;
7
- };
@@ -1,15 +0,0 @@
1
- import { ILockAdapter, ILock, Releaser } from '@nocobase/lock-manager';
2
- import { Application } from '@nocobase/server';
3
- export declare class RedisLockAdapter implements ILockAdapter {
4
- private options;
5
- private client;
6
- constructor(options: {
7
- url?: string;
8
- app: Application;
9
- });
10
- connect(): Promise<void>;
11
- close(): Promise<void>;
12
- acquire(key: string, ttl: number): Promise<Releaser>;
13
- runExclusive<T>(key: string, fn: () => Promise<T>, ttl: number): Promise<T>;
14
- tryAcquire(key: string, timeout?: number): Promise<ILock>;
15
- }
@@ -1,12 +0,0 @@
1
- export declare class RedisNodeRegistry {
2
- private app;
3
- private timer;
4
- private readonly ttlSecs;
5
- private readonly intervalMs;
6
- private readonly keyPrefix;
7
- constructor(app: any);
8
- start(): void;
9
- stop(): void;
10
- private heartbeat;
11
- getNodes(): Promise<any[]>;
12
- }