plugin-cluster-manager 1.1.11 → 1.1.15
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/client-v2.d.ts +2 -0
- package/client-v2.js +1 -0
- package/dist/client/index.js +1 -1
- package/dist/client-v2/914.c0bce51908fd81d7.js +10 -0
- package/dist/client-v2/index.js +10 -0
- package/dist/externalVersion.js +6 -5
- package/dist/locale/en-US.json +138 -124
- package/dist/locale/vi-VN.json +139 -125
- package/dist/locale/zh-CN.json +140 -125
- package/dist/server/actions/cluster-nodes.js +2 -6
- package/dist/server/actions/doctor.js +1 -5
- package/dist/server/actions/orchestrator.js +37 -0
- package/dist/server/actions/queue-mappings.js +107 -0
- package/dist/server/collections/worker-queue-mappings.js +106 -0
- package/dist/server/orchestrator/PackageManager.js +1 -8
- package/dist/server/orchestrator/docker-adapter.js +49 -27
- package/dist/server/plugin.js +10 -8
- package/dist/server/queue-scanner.js +141 -0
- package/dist/server/utils/node.js +30 -2
- package/package.json +46 -42
- package/src/client/AclCacheManager.tsx +292 -287
- package/src/client/CacheMonitor.tsx +2 -2
- package/src/client/ClusterManagerLayout.tsx +6 -0
- package/src/client/ClusterNodes.tsx +11 -4
- package/src/client/ContainerOrchestrator.tsx +186 -104
- package/src/client/Doctor.tsx +2 -2
- package/src/client/EventQueueMonitor.tsx +2 -2
- package/src/client/LockMonitor.tsx +2 -2
- package/src/client/NginxCacheManager.tsx +2 -2
- package/src/client/PackageInstaller.tsx +2 -2
- package/src/client/PluginOperations.tsx +2 -2
- package/src/client/QueueAssignment.tsx +355 -0
- package/src/client/RedisMonitor.tsx +3 -3
- package/src/client/TaskManager.tsx +194 -187
- package/src/client/WorkflowExecutions.tsx +243 -238
- package/src/client/utils.ts +1 -1
- package/src/client-v2/plugin.tsx +24 -0
- package/src/locale/en-US.json +138 -124
- package/src/locale/vi-VN.json +139 -125
- package/src/locale/zh-CN.json +140 -125
- package/src/server/actions/cluster-nodes.ts +4 -7
- package/src/server/actions/doctor.ts +11 -9
- package/src/server/actions/orchestrator.ts +54 -2
- package/src/server/actions/queue-mappings.ts +94 -0
- package/src/server/adapters/redis-node-registry.ts +126 -131
- package/src/server/collections/worker-queue-mappings.ts +85 -0
- package/src/server/orchestrator/PackageManager.ts +2 -10
- package/src/server/orchestrator/docker-adapter.ts +74 -37
- package/src/server/plugin.ts +15 -12
- package/src/server/queue-scanner.ts +154 -0
- package/src/server/utils/node.ts +48 -0
- package/dist/client/AclCacheManager.d.ts +0 -2
- package/dist/client/CacheMonitor.d.ts +0 -2
- package/dist/client/ClusterManagerLayout.d.ts +0 -2
- package/dist/client/ClusterNodes.d.ts +0 -2
- package/dist/client/ContainerOrchestrator.d.ts +0 -2
- package/dist/client/Doctor.d.ts +0 -2
- package/dist/client/EventQueueMonitor.d.ts +0 -2
- package/dist/client/LockMonitor.d.ts +0 -2
- package/dist/client/NginxCacheManager.d.ts +0 -2
- package/dist/client/PackageInstaller.d.ts +0 -2
- package/dist/client/PluginOperations.d.ts +0 -2
- package/dist/client/RedisMonitor.d.ts +0 -2
- package/dist/client/TaskManager.d.ts +0 -2
- package/dist/client/WorkflowExecutions.d.ts +0 -2
- package/dist/client/index.d.ts +0 -5
- package/dist/client/utils/clientSafeCache.d.ts +0 -3
- package/dist/client/utils/requestDedupInterceptor.d.ts +0 -2
- package/dist/client/utils.d.ts +0 -12
- package/dist/index.d.ts +0 -2
- package/dist/server/actions/acl-cache.d.ts +0 -53
- package/dist/server/actions/cache-monitor.d.ts +0 -33
- package/dist/server/actions/cluster-nodes.d.ts +0 -64
- package/dist/server/actions/doctor.d.ts +0 -82
- package/dist/server/actions/event-queue-monitor.d.ts +0 -13
- package/dist/server/actions/lock-monitor.d.ts +0 -19
- package/dist/server/actions/orchestrator.d.ts +0 -58
- package/dist/server/actions/package-manager.d.ts +0 -6
- package/dist/server/actions/plugin-operations.d.ts +0 -6
- package/dist/server/actions/redis-monitor.d.ts +0 -12
- package/dist/server/actions/tasks.d.ts +0 -7
- package/dist/server/actions/workflow-executions.d.ts +0 -7
- package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
- package/dist/server/adapters/redis-node-registry.d.ts +0 -12
- package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
- package/dist/server/collections/app.d.ts +0 -8
- package/dist/server/collections/cluster-manager-acl-cache.d.ts +0 -22
- package/dist/server/collections/cluster-manager-cache-mgr.d.ts +0 -22
- package/dist/server/collections/cluster-manager-cluster.d.ts +0 -22
- package/dist/server/collections/cluster-manager-doctor-runs.d.ts +0 -3
- package/dist/server/collections/cluster-manager-doctor.d.ts +0 -18
- package/dist/server/collections/cluster-manager-lock.d.ts +0 -22
- package/dist/server/collections/cluster-manager-plugins.d.ts +0 -18
- package/dist/server/collections/cluster-manager-queue.d.ts +0 -22
- package/dist/server/collections/cluster-manager-redis.d.ts +0 -22
- package/dist/server/collections/cluster-manager-workflow.d.ts +0 -22
- package/dist/server/collections/cluster-manager.d.ts +0 -22
- package/dist/server/collections/orchestrator-settings.d.ts +0 -59
- package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
- package/dist/server/collections/worker-orchestrator.d.ts +0 -22
- package/dist/server/collections/worker-packages-configs.d.ts +0 -3
- package/dist/server/collections/worker-packages.d.ts +0 -22
- package/dist/server/hooks/cacheInvalidationHooks.d.ts +0 -1
- package/dist/server/middlewares/listMetaCacheMiddleware.d.ts +0 -2
- package/dist/server/orchestrator/PackageManager.d.ts +0 -39
- package/dist/server/orchestrator/docker-adapter.d.ts +0 -41
- package/dist/server/orchestrator/index.d.ts +0 -4
- package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
- package/dist/server/orchestrator/leader-election.d.ts +0 -48
- package/dist/server/orchestrator/types.d.ts +0 -84
- package/dist/server/plugin.d.ts +0 -26
- package/dist/server/utils/node.d.ts +0 -6
- package/dist/server/utils/redis.d.ts +0 -29
- package/dist/server/utils/versionManager.d.ts +0 -10
- package/dist/shared/packages.d.ts +0 -23
- /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
|
+
}
|
package/src/server/utils/node.ts
CHANGED
|
@@ -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
|
package/dist/client/Doctor.d.ts
DELETED
package/dist/client/index.d.ts
DELETED
package/dist/client/utils.d.ts
DELETED
|
@@ -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,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,33 +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
|
-
/**
|
|
24
|
-
* GET /clusterManagerCacheMgr:nginxCacheStatus
|
|
25
|
-
* Detect if Nginx is installed, locate conf, and auto-load cache paths
|
|
26
|
-
*/
|
|
27
|
-
nginxCacheStatus(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
* POST /clusterManagerCacheMgr:clearNginxCache
|
|
30
|
-
* Clear physical cache files or send an HTTP Purge request
|
|
31
|
-
*/
|
|
32
|
-
clearNginxCache(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
33
|
-
};
|
|
@@ -1,64 +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:drift
|
|
29
|
-
* Reports version/runtime/package drift across active cluster nodes.
|
|
30
|
-
*/
|
|
31
|
-
drift(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* GET /clusterManagerCluster:legacyDiagnostics
|
|
34
|
-
* Detects deprecated legacy multi-app plugins and leftover application records.
|
|
35
|
-
*/
|
|
36
|
-
legacyDiagnostics(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* GET /clusterManagerCluster:health
|
|
39
|
-
* Health check for all subsystems
|
|
40
|
-
*/
|
|
41
|
-
health(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
42
|
-
/**
|
|
43
|
-
* POST /clusterManagerCluster:restart
|
|
44
|
-
* Publishes a restart signal to target nodes orchestrating a soft NocoBase restart or a hard docker daemon rebirth
|
|
45
|
-
*/
|
|
46
|
-
restart(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
47
|
-
/**
|
|
48
|
-
* POST /clusterManagerCluster:rollingRestart
|
|
49
|
-
* Restarts online nodes one-by-one, optionally filtered by role.
|
|
50
|
-
*/
|
|
51
|
-
rollingRestart(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* GET /clusterManagerCluster:logs?targetNodeId=xxx&lines=200
|
|
54
|
-
*
|
|
55
|
-
* HA-aware log viewer. Reads logs from a specific node in the cluster.
|
|
56
|
-
*
|
|
57
|
-
* Flow:
|
|
58
|
-
* 1. If targetNodeId matches current node (or is empty) → read local FS directly
|
|
59
|
-
* 2. Otherwise → publish a log request via PubSub → target node reads its local FS
|
|
60
|
-
* and writes the result to a Redis key → this handler polls Redis until the
|
|
61
|
-
* response arrives (max 10s) → returns it to the client
|
|
62
|
-
*/
|
|
63
|
-
logs(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
64
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { Context } from '@nocobase/actions';
|
|
3
|
-
import Application from '@nocobase/server';
|
|
4
|
-
interface DiagnosticLogLine {
|
|
5
|
-
source: string;
|
|
6
|
-
line: string;
|
|
7
|
-
timestamp?: string;
|
|
8
|
-
level?: string;
|
|
9
|
-
message?: string;
|
|
10
|
-
stack?: string;
|
|
11
|
-
}
|
|
12
|
-
interface LogSignature {
|
|
13
|
-
signature: string;
|
|
14
|
-
level: string;
|
|
15
|
-
count: number;
|
|
16
|
-
firstSeen?: string;
|
|
17
|
-
lastSeen?: string;
|
|
18
|
-
sources: string[];
|
|
19
|
-
samples: string[];
|
|
20
|
-
}
|
|
21
|
-
interface LogAnalysis {
|
|
22
|
-
totalLines: number;
|
|
23
|
-
levels: Record<string, number>;
|
|
24
|
-
signatures: LogSignature[];
|
|
25
|
-
}
|
|
26
|
-
interface PluginSnapshot {
|
|
27
|
-
name?: string;
|
|
28
|
-
packageName?: string;
|
|
29
|
-
enabled?: boolean;
|
|
30
|
-
dbVersion?: string;
|
|
31
|
-
loaded: boolean;
|
|
32
|
-
runtimeVersion?: string;
|
|
33
|
-
}
|
|
34
|
-
interface DoctorNodeSnapshot {
|
|
35
|
-
nodeId: string;
|
|
36
|
-
node: {
|
|
37
|
-
hostname: string;
|
|
38
|
-
pid: number;
|
|
39
|
-
workerMode: string;
|
|
40
|
-
role: string;
|
|
41
|
-
appVersion: string;
|
|
42
|
-
nodeVersion: string;
|
|
43
|
-
platform: string;
|
|
44
|
-
arch: string;
|
|
45
|
-
uptime: number;
|
|
46
|
-
isSandbox: boolean;
|
|
47
|
-
};
|
|
48
|
-
memory: NodeJS.MemoryUsage;
|
|
49
|
-
os: {
|
|
50
|
-
totalMemory: number;
|
|
51
|
-
freeMemory: number;
|
|
52
|
-
cpuCount: number;
|
|
53
|
-
loadAvg: number[];
|
|
54
|
-
};
|
|
55
|
-
env: Record<string, string | undefined>;
|
|
56
|
-
plugins: PluginSnapshot[];
|
|
57
|
-
logs: {
|
|
58
|
-
files: Array<{
|
|
59
|
-
file: string;
|
|
60
|
-
lineCount: number;
|
|
61
|
-
}>;
|
|
62
|
-
lines: DiagnosticLogLine[];
|
|
63
|
-
analysis: LogAnalysis;
|
|
64
|
-
};
|
|
65
|
-
collectedAt: string;
|
|
66
|
-
error?: string;
|
|
67
|
-
}
|
|
68
|
-
interface DoctorSnapshotOptions {
|
|
69
|
-
runId?: string;
|
|
70
|
-
sinceMs?: number;
|
|
71
|
-
untilMs?: number;
|
|
72
|
-
maxLines?: number;
|
|
73
|
-
}
|
|
74
|
-
export declare function collectLocalDoctorSnapshot(app: Application, options?: DoctorSnapshotOptions): Promise<DoctorNodeSnapshot>;
|
|
75
|
-
export declare const doctorActions: {
|
|
76
|
-
start(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
77
|
-
stop(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
78
|
-
status(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
79
|
-
report(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
80
|
-
download(ctx: Context, next: () => Promise<void>): Promise<void>;
|
|
81
|
-
};
|
|
82
|
-
export {};
|
|
@@ -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
|
-
};
|