plugin-cluster-manager 1.1.11 → 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.
- 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.5dc1105cf3ada6a6.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/ClusterManagerLayout.tsx +6 -0
- package/src/client/ClusterNodes.tsx +8 -1
- package/src/client/ContainerOrchestrator.tsx +184 -102
- package/src/client/QueueAssignment.tsx +355 -0
- package/src/client/TaskManager.tsx +194 -187
- package/src/client/WorkflowExecutions.tsx +243 -238
- 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 +3 -7
- package/src/server/actions/doctor.ts +2 -6
- package/src/server/actions/orchestrator.ts +54 -2
- package/src/server/actions/queue-mappings.ts +94 -0
- 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 +12 -10
- 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
package/src/locale/zh-CN.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"Cluster Manager": "集群管理",
|
|
2
|
+
"Cluster Manager": "集群管理",
|
|
3
3
|
"Async Tasks": "异步任务",
|
|
4
4
|
"Workflow Executions": "工作流执行",
|
|
5
5
|
"Redis Monitor": "Redis 监控",
|
|
@@ -66,127 +66,142 @@
|
|
|
66
66
|
"This will clear all cached data across all stores.": "这将清除所有存储中的缓存数据。",
|
|
67
67
|
"All caches flushed": "所有缓存已清空",
|
|
68
68
|
"Failed to flush caches": "清空缓存失败",
|
|
69
|
-
"Sync Messages": "同步消息",
|
|
70
|
-
"Subscribers": "订阅者",
|
|
71
|
-
"Plugins": "插件",
|
|
72
|
-
"Plugin": "插件",
|
|
73
|
-
"Enabled": "已启用",
|
|
74
|
-
"Disabled": "已禁用",
|
|
75
|
-
"Installed": "已安装",
|
|
76
|
-
"Not installed": "未安装",
|
|
77
|
-
"Loaded": "已加载",
|
|
78
|
-
"Not loaded": "未加载",
|
|
79
|
-
"Protected": "受保护",
|
|
80
|
-
"Description": "描述",
|
|
81
|
-
"Force disable": "强制禁用",
|
|
82
|
-
"Force remove": "强制移除",
|
|
83
|
-
"Force disable this plugin?": "强制禁用此插件?",
|
|
84
|
-
"Force remove this plugin?": "强制移除此插件?",
|
|
85
|
-
"This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.": "此操作会直接更新插件注册表。需要重启或重新加载后才能完全卸载运行时钩子。",
|
|
86
|
-
"This removes the plugin registry record. Package files are not deleted. Restart or reload is required.": "此操作会移除插件注册记录。不会删除 package 文件。需要重启或重新加载。",
|
|
87
|
-
"Force operations bypass plugin lifecycle hooks": "强制操作会绕过插件生命周期钩子",
|
|
88
|
-
"Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.": "仅在普通插件管理器无法禁用或移除异常插件时使用。操作成功后请重启或重新加载应用。",
|
|
89
|
-
"Search plugins": "搜索插件",
|
|
90
|
-
"Plugin force disabled": "插件已强制禁用",
|
|
91
|
-
"Plugin force removed": "插件已强制移除",
|
|
92
|
-
"Failed to load plugins": "加载插件失败",
|
|
93
|
-
"Failed to force disable plugin": "强制禁用插件失败",
|
|
94
|
-
"Failed to force remove plugin": "强制移除插件失败",
|
|
95
|
-
"Nginx Cache": "Nginx 缓存",
|
|
96
|
-
"Nginx configuration file found at": "已找到 Nginx 配置文件于",
|
|
97
|
-
"Nginx cache paths detected": "检测到的 Nginx 缓存路径",
|
|
98
|
-
"Nginx is not detected on this node. You can still input a custom cache directory.": "此节点未检测到 Nginx。您仍可以输入自定义缓存目录。",
|
|
99
|
-
"Clearing Method": "清除方式",
|
|
100
|
-
"Physical Files": "物理文件",
|
|
101
|
-
"HTTP Purge Request": "HTTP Purge 请求",
|
|
102
|
-
"Select Cache Path": "选择缓存路径",
|
|
103
|
-
"Custom Path": "自定义路径",
|
|
104
|
-
"Purge URL": "Purge URL",
|
|
105
|
-
"Headers (JSON)": "Headers (JSON)",
|
|
106
|
-
"Clear Nginx Cache": "清除 Nginx 缓存",
|
|
107
|
-
"Are you sure you want to clear Nginx cache? This will permanently delete all files in this directory.": "确定要清除 Nginx 缓存吗?这将永久删除该目录下的所有文件。",
|
|
108
|
-
"Cache cleared successfully. Cleared {count} items.": "缓存清除成功。已清除 {count} 项。",
|
|
109
|
-
"HTTP Purge request completed. Status: {status}": "HTTP Purge 请求已完成。状态:{status}",
|
|
110
|
-
"Custom Cache Path": "自定义缓存路径",
|
|
111
|
-
"HTTP Method": "HTTP 方法",
|
|
112
|
-
"Send Purge Request": "发送 Purge 请求",
|
|
113
|
-
"Please select or enter a cache path": "请选择或输入缓存路径",
|
|
114
|
-
"Please enter a valid Purge URL": "请输入有效的 Purge URL",
|
|
115
|
-
"Nginx cache path is required": "必须提供 Nginx 缓存路径",
|
|
116
|
-
"Invalid headers JSON structure": "Headers JSON 结构无效",
|
|
117
|
-
"Nginx Cache Status": "Nginx 缓存状态",
|
|
118
|
-
"Nginx is installed": "Nginx 已安装",
|
|
119
|
-
"Nginx is NOT installed": "Nginx 未安装",
|
|
120
|
-
"Nginx cache clearing method": "Nginx 缓存清除方式",
|
|
121
|
-
"Execution Logs": "执行日志",
|
|
122
|
-
"Clear Nginx Cache?": "清除 Nginx 缓存?"
|
|
123
|
-
,
|
|
124
|
-
"Rolling Restart": "Rolling Restart",
|
|
125
|
-
"Worker nodes only": "Worker nodes only",
|
|
126
|
-
"App nodes only": "App nodes only",
|
|
127
|
-
"Sandbox nodes only": "Sandbox nodes only",
|
|
128
|
-
"All nodes": "All nodes",
|
|
129
|
-
"Soft restart": "Soft restart",
|
|
130
|
-
"Hard restart": "Hard restart",
|
|
131
|
-
"Start rolling restart?": "Start rolling restart?",
|
|
132
|
-
"Nodes will receive restart commands one-by-one with the configured delay.": "Nodes will receive restart commands one-by-one with the configured delay.",
|
|
133
|
-
"Start": "Start",
|
|
134
|
-
"Rolling restart dispatched for {count} node(s)": "Rolling restart dispatched for {count} node(s)",
|
|
135
|
-
"Failed to dispatch rolling restart": "Failed to dispatch rolling restart",
|
|
136
|
-
"Cluster Drift": "Cluster Drift",
|
|
137
|
-
"No cluster drift detected": "No cluster drift detected",
|
|
138
|
-
"Cluster drift detected": "Cluster drift detected",
|
|
139
|
-
"Reference version": "Reference version",
|
|
140
|
-
"No reference version available": "No reference version available",
|
|
141
|
-
"Checked Nodes": "Checked Nodes",
|
|
142
|
-
"Version Drift": "Version Drift",
|
|
143
|
-
"Runtime Drift": "Runtime Drift",
|
|
144
|
-
"Package Drift": "Package Drift",
|
|
145
|
-
"Runtime": "Runtime",
|
|
146
|
-
"Role": "Role",
|
|
147
|
-
"Expected": "Expected",
|
|
148
|
-
"Actual": "Actual",
|
|
149
|
-
"Package Status": "Package Status",
|
|
150
|
-
"Missing Packages": "Missing Packages",
|
|
151
|
-
"No missing packages": "No missing packages",
|
|
152
|
-
"Legacy Multi-app Diagnostics": "Legacy Multi-app Diagnostics",
|
|
153
|
-
"No legacy multi-app risk detected": "No legacy multi-app risk detected",
|
|
154
|
-
"Legacy multi-app risk detected": "Legacy multi-app risk detected",
|
|
155
|
-
"Legacy app records": "Legacy app records",
|
|
156
|
-
"Deprecated multi-app manager is active. It runs apps in shared process memory and should not be used for production cluster isolation.": "Deprecated multi-app manager is active. It runs apps in shared process memory and should not be used for production cluster isolation.",
|
|
157
|
-
"Deprecated multi-app share collection is active. Avoid schema/table sharing for new cluster deployments.": "Deprecated multi-app share collection is active. Avoid schema/table sharing for new cluster deployments.",
|
|
158
|
-
"{count} legacy application record(s) were found in the applications collection.": "{count} legacy application record(s) were found in the applications collection.",
|
|
159
|
-
"App Supervisor is not enabled. Use it for new multi-application management instead of deprecated multi-app plugins.": "App Supervisor is not enabled. Use it for new multi-application management instead of deprecated multi-app plugins.",
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"Diagnostic
|
|
167
|
-
"
|
|
168
|
-
"Failed to
|
|
169
|
-
"Failed to
|
|
170
|
-
"Failed to
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
|
|
69
|
+
"Sync Messages": "同步消息",
|
|
70
|
+
"Subscribers": "订阅者",
|
|
71
|
+
"Plugins": "插件",
|
|
72
|
+
"Plugin": "插件",
|
|
73
|
+
"Enabled": "已启用",
|
|
74
|
+
"Disabled": "已禁用",
|
|
75
|
+
"Installed": "已安装",
|
|
76
|
+
"Not installed": "未安装",
|
|
77
|
+
"Loaded": "已加载",
|
|
78
|
+
"Not loaded": "未加载",
|
|
79
|
+
"Protected": "受保护",
|
|
80
|
+
"Description": "描述",
|
|
81
|
+
"Force disable": "强制禁用",
|
|
82
|
+
"Force remove": "强制移除",
|
|
83
|
+
"Force disable this plugin?": "强制禁用此插件?",
|
|
84
|
+
"Force remove this plugin?": "强制移除此插件?",
|
|
85
|
+
"This updates the plugin registry directly. Restart or reload is required to fully unload runtime hooks.": "此操作会直接更新插件注册表。需要重启或重新加载后才能完全卸载运行时钩子。",
|
|
86
|
+
"This removes the plugin registry record. Package files are not deleted. Restart or reload is required.": "此操作会移除插件注册记录。不会删除 package 文件。需要重启或重新加载。",
|
|
87
|
+
"Force operations bypass plugin lifecycle hooks": "强制操作会绕过插件生命周期钩子",
|
|
88
|
+
"Use this only when the normal plugin manager cannot disable or remove a broken plugin. Restart or reload the app after a successful operation.": "仅在普通插件管理器无法禁用或移除异常插件时使用。操作成功后请重启或重新加载应用。",
|
|
89
|
+
"Search plugins": "搜索插件",
|
|
90
|
+
"Plugin force disabled": "插件已强制禁用",
|
|
91
|
+
"Plugin force removed": "插件已强制移除",
|
|
92
|
+
"Failed to load plugins": "加载插件失败",
|
|
93
|
+
"Failed to force disable plugin": "强制禁用插件失败",
|
|
94
|
+
"Failed to force remove plugin": "强制移除插件失败",
|
|
95
|
+
"Nginx Cache": "Nginx 缓存",
|
|
96
|
+
"Nginx configuration file found at": "已找到 Nginx 配置文件于",
|
|
97
|
+
"Nginx cache paths detected": "检测到的 Nginx 缓存路径",
|
|
98
|
+
"Nginx is not detected on this node. You can still input a custom cache directory.": "此节点未检测到 Nginx。您仍可以输入自定义缓存目录。",
|
|
99
|
+
"Clearing Method": "清除方式",
|
|
100
|
+
"Physical Files": "物理文件",
|
|
101
|
+
"HTTP Purge Request": "HTTP Purge 请求",
|
|
102
|
+
"Select Cache Path": "选择缓存路径",
|
|
103
|
+
"Custom Path": "自定义路径",
|
|
104
|
+
"Purge URL": "Purge URL",
|
|
105
|
+
"Headers (JSON)": "Headers (JSON)",
|
|
106
|
+
"Clear Nginx Cache": "清除 Nginx 缓存",
|
|
107
|
+
"Are you sure you want to clear Nginx cache? This will permanently delete all files in this directory.": "确定要清除 Nginx 缓存吗?这将永久删除该目录下的所有文件。",
|
|
108
|
+
"Cache cleared successfully. Cleared {count} items.": "缓存清除成功。已清除 {count} 项。",
|
|
109
|
+
"HTTP Purge request completed. Status: {status}": "HTTP Purge 请求已完成。状态:{status}",
|
|
110
|
+
"Custom Cache Path": "自定义缓存路径",
|
|
111
|
+
"HTTP Method": "HTTP 方法",
|
|
112
|
+
"Send Purge Request": "发送 Purge 请求",
|
|
113
|
+
"Please select or enter a cache path": "请选择或输入缓存路径",
|
|
114
|
+
"Please enter a valid Purge URL": "请输入有效的 Purge URL",
|
|
115
|
+
"Nginx cache path is required": "必须提供 Nginx 缓存路径",
|
|
116
|
+
"Invalid headers JSON structure": "Headers JSON 结构无效",
|
|
117
|
+
"Nginx Cache Status": "Nginx 缓存状态",
|
|
118
|
+
"Nginx is installed": "Nginx 已安装",
|
|
119
|
+
"Nginx is NOT installed": "Nginx 未安装",
|
|
120
|
+
"Nginx cache clearing method": "Nginx 缓存清除方式",
|
|
121
|
+
"Execution Logs": "执行日志",
|
|
122
|
+
"Clear Nginx Cache?": "清除 Nginx 缓存?"
|
|
123
|
+
,
|
|
124
|
+
"Rolling Restart": "Rolling Restart",
|
|
125
|
+
"Worker nodes only": "Worker nodes only",
|
|
126
|
+
"App nodes only": "App nodes only",
|
|
127
|
+
"Sandbox nodes only": "Sandbox nodes only",
|
|
128
|
+
"All nodes": "All nodes",
|
|
129
|
+
"Soft restart": "Soft restart",
|
|
130
|
+
"Hard restart": "Hard restart",
|
|
131
|
+
"Start rolling restart?": "Start rolling restart?",
|
|
132
|
+
"Nodes will receive restart commands one-by-one with the configured delay.": "Nodes will receive restart commands one-by-one with the configured delay.",
|
|
133
|
+
"Start": "Start",
|
|
134
|
+
"Rolling restart dispatched for {count} node(s)": "Rolling restart dispatched for {count} node(s)",
|
|
135
|
+
"Failed to dispatch rolling restart": "Failed to dispatch rolling restart",
|
|
136
|
+
"Cluster Drift": "Cluster Drift",
|
|
137
|
+
"No cluster drift detected": "No cluster drift detected",
|
|
138
|
+
"Cluster drift detected": "Cluster drift detected",
|
|
139
|
+
"Reference version": "Reference version",
|
|
140
|
+
"No reference version available": "No reference version available",
|
|
141
|
+
"Checked Nodes": "Checked Nodes",
|
|
142
|
+
"Version Drift": "Version Drift",
|
|
143
|
+
"Runtime Drift": "Runtime Drift",
|
|
144
|
+
"Package Drift": "Package Drift",
|
|
145
|
+
"Runtime": "Runtime",
|
|
146
|
+
"Role": "Role",
|
|
147
|
+
"Expected": "Expected",
|
|
148
|
+
"Actual": "Actual",
|
|
149
|
+
"Package Status": "Package Status",
|
|
150
|
+
"Missing Packages": "Missing Packages",
|
|
151
|
+
"No missing packages": "No missing packages",
|
|
152
|
+
"Legacy Multi-app Diagnostics": "Legacy Multi-app Diagnostics",
|
|
153
|
+
"No legacy multi-app risk detected": "No legacy multi-app risk detected",
|
|
154
|
+
"Legacy multi-app risk detected": "Legacy multi-app risk detected",
|
|
155
|
+
"Legacy app records": "Legacy app records",
|
|
156
|
+
"Deprecated multi-app manager is active. It runs apps in shared process memory and should not be used for production cluster isolation.": "Deprecated multi-app manager is active. It runs apps in shared process memory and should not be used for production cluster isolation.",
|
|
157
|
+
"Deprecated multi-app share collection is active. Avoid schema/table sharing for new cluster deployments.": "Deprecated multi-app share collection is active. Avoid schema/table sharing for new cluster deployments.",
|
|
158
|
+
"{count} legacy application record(s) were found in the applications collection.": "{count} legacy application record(s) were found in the applications collection.",
|
|
159
|
+
"App Supervisor is not enabled. Use it for new multi-application management instead of deprecated multi-app plugins.": "App Supervisor is not enabled. Use it for new multi-application management instead of deprecated multi-app plugins.",
|
|
160
|
+
"License": "License",
|
|
161
|
+
"Doctor": "诊断",
|
|
162
|
+
"Duration": "Duration",
|
|
163
|
+
"Start Doctor": "Start Doctor",
|
|
164
|
+
"Stop Doctor": "Stop Doctor",
|
|
165
|
+
"Download Report": "Download Report",
|
|
166
|
+
"Diagnostic session started": "Diagnostic session started",
|
|
167
|
+
"Diagnostic report is ready": "Diagnostic report is ready",
|
|
168
|
+
"Failed to load diagnostic status": "Failed to load diagnostic status",
|
|
169
|
+
"Failed to start diagnostic session": "Failed to start diagnostic session",
|
|
170
|
+
"Failed to stop diagnostic session": "Failed to stop diagnostic session",
|
|
171
|
+
"Failed to download diagnostic report": "Failed to download diagnostic report",
|
|
172
|
+
"Running": "Running",
|
|
173
|
+
"Run ID": "Run ID",
|
|
174
|
+
"Started At": "Started At",
|
|
175
|
+
"Finished At": "Finished At",
|
|
176
|
+
"Finish Reason": "Finish Reason",
|
|
177
|
+
"Report Status": "Report Status",
|
|
178
|
+
"Nodes": "Nodes",
|
|
179
|
+
"Errors": "Errors",
|
|
180
|
+
"Warnings": "Warnings",
|
|
181
|
+
"Plugin Drift": "Plugin Drift",
|
|
182
|
+
"Findings": "Findings",
|
|
183
|
+
"Node Log Distribution": "Node Log Distribution",
|
|
184
|
+
"Top Error Signatures": "Top Error Signatures",
|
|
185
|
+
"Level": "Level",
|
|
186
|
+
"Count": "Count",
|
|
187
|
+
"Signature": "Signature",
|
|
188
|
+
"Node": "Node",
|
|
189
|
+
"Log Files": "Log Files",
|
|
190
|
+
"Package": "Package",
|
|
191
|
+
"DB Version": "DB Version",
|
|
192
|
+
"Runtime Versions": "Runtime Versions",
|
|
193
|
+
"Queue Assignment": "队列分配",
|
|
194
|
+
"Queue Name": "队列名称",
|
|
195
|
+
"Map queues to worker stacks. Unassigned queues run on all workers.": "将队列映射到工作节点栈。未分配的队列将在所有工作节点上运行。",
|
|
196
|
+
"Scan Queues": "扫描队列",
|
|
197
|
+
"Auto-map ({count})": "自动映射 ({count})",
|
|
198
|
+
"Register": "注册",
|
|
199
|
+
"Unregister": "注销",
|
|
200
|
+
"Assigned Stack": "分配栈",
|
|
201
|
+
"All (default)": "全部(默认)",
|
|
202
|
+
"Delete this mapping?": "删除此映射?",
|
|
203
|
+
"No queues discovered. Click \"Scan Queues\" to detect registered queues.": "未发现队列。点击\"扫描队列\"以检测已注册的队列。",
|
|
204
|
+
"Auto-mapped {count} queue(s)": "已自动映射 {count} 个队列",
|
|
205
|
+
"Queue Assignment updated": "队列分配已更新",
|
|
206
|
+
"Unassigned (worker runs all queues)": "未分配(工作节点运行所有队列)"
|
|
207
|
+
}
|
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import crypto from 'crypto';
|
|
6
6
|
import { RedisNodeRegistry } from '../adapters/redis-node-registry';
|
|
7
7
|
import { getRedis } from '../utils/redis';
|
|
8
|
-
import { getLocalNodeId } from '../utils/node';
|
|
8
|
+
import { getLocalNodeId, getNodeRoleFrom, isWorkerMode } from '../utils/node';
|
|
9
9
|
import { packagesFromConfig, type CustomPackageMap, type WorkerPackageMap } from '../../shared/packages';
|
|
10
10
|
|
|
11
11
|
const LOG_RESPONSE_KEY_PREFIX = 'cluster-manager:log-response:';
|
|
@@ -162,11 +162,7 @@ function getErrorMessage(error: unknown) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
function getNodeRole(node: ClusterNodeRecord): 'app' | 'worker' | 'sandbox' {
|
|
165
|
-
|
|
166
|
-
return 'sandbox';
|
|
167
|
-
}
|
|
168
|
-
const workerMode = node.workerMode || 'main';
|
|
169
|
-
return workerMode === 'worker' || workerMode === 'task' || workerMode === '*' ? 'worker' : 'app';
|
|
165
|
+
return getNodeRoleFrom({ workerMode: node.workerMode, isSandbox: node.isSandbox });
|
|
170
166
|
}
|
|
171
167
|
|
|
172
168
|
function getReferenceVersion(nodes: ClusterNodeRecord[]) {
|
|
@@ -304,7 +300,7 @@ export const clusterActions = {
|
|
|
304
300
|
*/
|
|
305
301
|
async current(ctx: Context, next: () => Promise<void>) {
|
|
306
302
|
const currentMode = process.env.WORKER_MODE || 'main';
|
|
307
|
-
const isApp =
|
|
303
|
+
const isApp = !isWorkerMode(process.env.WORKER_MODE);
|
|
308
304
|
|
|
309
305
|
if (isApp) {
|
|
310
306
|
// This process IS the APP node — return local data directly
|
|
@@ -6,7 +6,7 @@ import os from 'os';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { RedisNodeRegistry } from '../adapters/redis-node-registry';
|
|
8
8
|
import type { ContainerInfo, StackConfig } from '../orchestrator/types';
|
|
9
|
-
import { getLocalNodeId } from '../utils/node';
|
|
9
|
+
import { getLocalNodeId, getNodeRoleFrom } from '../utils/node';
|
|
10
10
|
import { getRedisClient, scanKeys } from '../utils/redis';
|
|
11
11
|
import { packagesFromConfig, type CustomPackageMap, type WorkerPackageMap } from '../../shared/packages';
|
|
12
12
|
|
|
@@ -282,11 +282,7 @@ function countPackages(packages: NormalizedPackages) {
|
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
function getNodeRole(node: { workerMode?: string; isSandbox?: boolean }): 'app' | 'worker' | 'sandbox' {
|
|
285
|
-
|
|
286
|
-
return 'sandbox';
|
|
287
|
-
}
|
|
288
|
-
const workerMode = node.workerMode || 'main';
|
|
289
|
-
return workerMode === 'worker' || workerMode === 'task' || workerMode === '*' ? 'worker' : 'app';
|
|
285
|
+
return getNodeRoleFrom({ workerMode: node.workerMode, isSandbox: node.isSandbox });
|
|
290
286
|
}
|
|
291
287
|
|
|
292
288
|
function getSafeEnv() {
|
|
@@ -41,7 +41,12 @@ async function getStack(ctx: Context, stackId?: number | string): Promise<StackC
|
|
|
41
41
|
return stack.toJSON() as StackConfig;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
async function assertManagedContainer(
|
|
44
|
+
async function assertManagedContainer(
|
|
45
|
+
ctx: Context,
|
|
46
|
+
adapter: IOrchestratorAdapter,
|
|
47
|
+
stack: StackConfig,
|
|
48
|
+
containerId: string,
|
|
49
|
+
) {
|
|
45
50
|
try {
|
|
46
51
|
await adapter.assertManagedByStack(stack, containerId);
|
|
47
52
|
} catch (err: any) {
|
|
@@ -87,7 +92,9 @@ export const orchestratorActions = {
|
|
|
87
92
|
if (rawStatus && typeof rawStatus === 'string') {
|
|
88
93
|
(c as any).packageStatus = JSON.parse(rawStatus);
|
|
89
94
|
}
|
|
90
|
-
} catch {
|
|
95
|
+
} catch {
|
|
96
|
+
// Redis may not be configured — skip package status
|
|
97
|
+
}
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
100
|
|
|
@@ -114,6 +121,10 @@ export const orchestratorActions = {
|
|
|
114
121
|
* POST /workerOrchestrator:scale
|
|
115
122
|
* Body: { stackId: 1, replicas: 3 }
|
|
116
123
|
* Leader-only
|
|
124
|
+
*
|
|
125
|
+
* Before scaling, resolves queue-to-stack mappings and injects
|
|
126
|
+
* WORKER_MODE into the stack's envVars so new containers only
|
|
127
|
+
* process assigned queues.
|
|
117
128
|
*/
|
|
118
129
|
async scale(ctx: Context, next: () => Promise<void>) {
|
|
119
130
|
assertLeader(ctx);
|
|
@@ -124,6 +135,47 @@ export const orchestratorActions = {
|
|
|
124
135
|
if (replicas < 0 || replicas > 20) ctx.throw(400, 'replicas must be between 0 and 20');
|
|
125
136
|
|
|
126
137
|
const stack = await getStack(ctx, stackId);
|
|
138
|
+
|
|
139
|
+
// ── Resolve queue assignments for this stack ──
|
|
140
|
+
try {
|
|
141
|
+
const mappingsRepo = ctx.db.getRepository('workerQueueMappings');
|
|
142
|
+
if (mappingsRepo) {
|
|
143
|
+
const assigned = await mappingsRepo.find({
|
|
144
|
+
filter: {
|
|
145
|
+
stackId: stack.id,
|
|
146
|
+
enabled: true,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const queueNames = assigned.map((m: any) => m.get('queueName') as string).filter(Boolean);
|
|
151
|
+
|
|
152
|
+
if (queueNames.length > 0) {
|
|
153
|
+
const workerMode = queueNames.join(',');
|
|
154
|
+
ctx.app.logger.info(
|
|
155
|
+
`[Orchestrator] Injecting WORKER_MODE=${workerMode} for stack "${stack.name}" (${queueNames.length} queue(s) assigned)`,
|
|
156
|
+
);
|
|
157
|
+
// Merge into envVars; adapter code merges envVars over inherited env
|
|
158
|
+
stack.envVars = {
|
|
159
|
+
...(stack.envVars || {}),
|
|
160
|
+
WORKER_MODE: workerMode,
|
|
161
|
+
};
|
|
162
|
+
} else {
|
|
163
|
+
// No specific assignment → default to all queues (backwards compatible)
|
|
164
|
+
stack.envVars = {
|
|
165
|
+
...(stack.envVars || {}),
|
|
166
|
+
WORKER_MODE: '*',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} catch (err: any) {
|
|
171
|
+
// If workerQueueMappings table doesn't exist yet, fall back gracefully
|
|
172
|
+
ctx.app.logger.debug(`[Orchestrator] Queue mappings not available: ${err.message}`);
|
|
173
|
+
stack.envVars = {
|
|
174
|
+
...(stack.envVars || {}),
|
|
175
|
+
WORKER_MODE: '*',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
127
179
|
const result = await adapter.scale(stack, Number(replicas));
|
|
128
180
|
|
|
129
181
|
// Update DB
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queue Mappings Actions
|
|
3
|
+
*
|
|
4
|
+
* CRUD for workerQueueMappings + scanQueues action that discovers
|
|
5
|
+
* all registered queues via QueueScanner.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Context } from '@nocobase/actions';
|
|
9
|
+
import { scanQueues } from '../queue-scanner';
|
|
10
|
+
|
|
11
|
+
export const queueMappingsActions = {
|
|
12
|
+
/**
|
|
13
|
+
* GET /workerQueueMappings:scanQueues
|
|
14
|
+
* Scans all registered queues (EventQueue + Redis) and merges with existing mappings.
|
|
15
|
+
*/
|
|
16
|
+
async scanQueues(ctx: Context, next: () => Promise<void>) {
|
|
17
|
+
const result = await scanQueues(ctx.app);
|
|
18
|
+
|
|
19
|
+
// Load existing mappings from DB
|
|
20
|
+
const repo = ctx.db.getRepository('workerQueueMappings');
|
|
21
|
+
let existingMappings: any[] = [];
|
|
22
|
+
try {
|
|
23
|
+
existingMappings = await repo.find();
|
|
24
|
+
} catch {
|
|
25
|
+
// Table may not exist yet
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const mappedNames = new Set(existingMappings.map((m) => m.get('queueName') as string));
|
|
29
|
+
|
|
30
|
+
ctx.body = {
|
|
31
|
+
discovered: result.queues,
|
|
32
|
+
total: result.total,
|
|
33
|
+
registered: existingMappings.map((m) => ({
|
|
34
|
+
id: m.get('id'),
|
|
35
|
+
queueName: m.get('queueName'),
|
|
36
|
+
label: m.get('label'),
|
|
37
|
+
stackId: m.get('stackId'),
|
|
38
|
+
enabled: m.get('enabled'),
|
|
39
|
+
type: m.get('type'),
|
|
40
|
+
})),
|
|
41
|
+
unmapped: result.queues
|
|
42
|
+
.filter((q) => !mappedNames.has(q.name))
|
|
43
|
+
.map((q) => ({
|
|
44
|
+
name: q.name,
|
|
45
|
+
type: q.type,
|
|
46
|
+
label: q.label,
|
|
47
|
+
description: q.description,
|
|
48
|
+
})),
|
|
49
|
+
};
|
|
50
|
+
await next();
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* POST /workerQueueMappings:autoMap
|
|
55
|
+
* Auto-create mappings for any discovered queues that don't have one yet.
|
|
56
|
+
* Body: { stackId?: number } — optional default stack for new mappings
|
|
57
|
+
*/
|
|
58
|
+
async autoMap(ctx: Context, next: () => Promise<void>) {
|
|
59
|
+
const { stackId } = ctx.action.params.values || {};
|
|
60
|
+
const result = await scanQueues(ctx.app);
|
|
61
|
+
const repo = ctx.db.getRepository('workerQueueMappings');
|
|
62
|
+
|
|
63
|
+
let existingMappings: any[] = [];
|
|
64
|
+
try {
|
|
65
|
+
existingMappings = await repo.find();
|
|
66
|
+
} catch {
|
|
67
|
+
// Table may not exist yet
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const mappedNames = new Set(existingMappings.map((m) => m.get('queueName') as string));
|
|
71
|
+
const created: string[] = [];
|
|
72
|
+
|
|
73
|
+
for (const q of result.queues) {
|
|
74
|
+
if (mappedNames.has(q.name)) continue;
|
|
75
|
+
await repo.create({
|
|
76
|
+
values: {
|
|
77
|
+
queueName: q.name,
|
|
78
|
+
label: q.label,
|
|
79
|
+
description: q.description,
|
|
80
|
+
type: q.type,
|
|
81
|
+
stackId: stackId || null,
|
|
82
|
+
enabled: true,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
created.push(q.name);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ctx.body = {
|
|
89
|
+
created,
|
|
90
|
+
count: created.length,
|
|
91
|
+
};
|
|
92
|
+
await next();
|
|
93
|
+
},
|
|
94
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection: workerQueueMappings
|
|
3
|
+
*
|
|
4
|
+
* Maps queue names to worker stacks (orchestratorStacks).
|
|
5
|
+
* When a stack has assigned queues, the orchestrator adapter sets
|
|
6
|
+
* WORKER_MODE=<comma-separated-queue-names> on new containers.
|
|
7
|
+
*
|
|
8
|
+
* If no mappings exist for a stack, WORKER_MODE=* is preserved
|
|
9
|
+
* (backwards compatibility).
|
|
10
|
+
*/
|
|
11
|
+
export default {
|
|
12
|
+
name: 'workerQueueMappings',
|
|
13
|
+
autoGenId: true,
|
|
14
|
+
createdAt: true,
|
|
15
|
+
updatedAt: true,
|
|
16
|
+
fields: [
|
|
17
|
+
{
|
|
18
|
+
name: 'queueName',
|
|
19
|
+
type: 'string',
|
|
20
|
+
unique: true,
|
|
21
|
+
interface: 'input',
|
|
22
|
+
uiSchema: {
|
|
23
|
+
title: 'Queue Name',
|
|
24
|
+
'x-component': 'Input',
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'label',
|
|
30
|
+
type: 'string',
|
|
31
|
+
interface: 'input',
|
|
32
|
+
uiSchema: {
|
|
33
|
+
title: 'Label',
|
|
34
|
+
'x-component': 'Input',
|
|
35
|
+
description: 'Human-readable display name',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'description',
|
|
40
|
+
type: 'text',
|
|
41
|
+
interface: 'textarea',
|
|
42
|
+
uiSchema: {
|
|
43
|
+
title: 'Description',
|
|
44
|
+
'x-component': 'Input.TextArea',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'type',
|
|
49
|
+
type: 'string',
|
|
50
|
+
interface: 'select',
|
|
51
|
+
defaultValue: 'event-queue',
|
|
52
|
+
uiSchema: {
|
|
53
|
+
title: 'Source Type',
|
|
54
|
+
'x-component': 'Select',
|
|
55
|
+
enum: [
|
|
56
|
+
{ value: 'event-queue', label: 'EventQueue' },
|
|
57
|
+
{ value: 'redis-list', label: 'Redis List' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'stackId',
|
|
63
|
+
type: 'integer',
|
|
64
|
+
interface: 'select',
|
|
65
|
+
uiSchema: {
|
|
66
|
+
title: 'Assigned Stack',
|
|
67
|
+
'x-component': 'Select',
|
|
68
|
+
'x-component-props': {
|
|
69
|
+
allowClear: true,
|
|
70
|
+
placeholder: 'Unassigned (worker runs all queues)',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'enabled',
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
defaultValue: true,
|
|
78
|
+
interface: 'checkbox',
|
|
79
|
+
uiSchema: {
|
|
80
|
+
title: 'Enabled',
|
|
81
|
+
'x-component': 'Checkbox',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import { getRedisClient } from '../utils/redis';
|
|
3
|
-
import { getLocalNodeId } from '../utils/node';
|
|
3
|
+
import { getLocalNodeId, getLocalRole } from '../utils/node';
|
|
4
4
|
import { promises as fsp } from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import Application from '@nocobase/server';
|
|
@@ -67,15 +67,7 @@ function redactUrl(value: string): string {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function getCurrentRole(): Exclude<TargetRole, 'all'> {
|
|
70
|
-
|
|
71
|
-
return process.env.APP_ROLE;
|
|
72
|
-
}
|
|
73
|
-
if (process.env.SKILL_HUB_SANDBOX === 'true') {
|
|
74
|
-
return 'sandbox';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const workerMode = process.env.WORKER_MODE || 'main';
|
|
78
|
-
return workerMode === 'worker' || workerMode === 'task' || workerMode === '*' ? 'worker' : 'app';
|
|
70
|
+
return getLocalRole();
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
function formatCommand(command: string, args: string[]): string {
|