shuzhiren-comfyui/AI实现指导提示词.md

1084 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI 实现指导提示词
## 任务概述
你需要实现将任务队列后端的 runninghub 任务优先分发到内部 message-dispatcher 系统的功能。请按照以下详细指导进行修改。
---
## 一、任务队列后端项目修改指导
### 项目路径
`d:\Ke_xue_web\独立项目\comfyui桥接器\任务队列后端\`
---
### 修改点 0新增 WebSocket 通信模块
**文件:** `utils/mdWebSocketClient.js`(新建)
**通信架构说明:**
- message-dispatcher 主动通过 WebSocket 连接任务队列后端
- WebSocket 用于:
- JWT Token 接收与定期更新
- 算力状态上报
- 实例状态变化同步
- 健康检查
- **仅任务提交通过 HTTP 接口完成**
- 任务提交接口 URL 通过环境变量获取,与 runninghub 保持一致
- **所有其他通信(包括 Token 获取)均通过 WebSocket**
**功能要求:**
1. 作为 WebSocket 服务端,等待 message-dispatcher 连接
2. 接收 JWT Token 消息JWT_UPDATE
3. 接收算力状态更新消息CAPACITY_UPDATE
4. 接收实例状态变化消息INSTANCE_ONLINE/INSTANCE_OFFLINE 等)
5. 发送心跳响应
6. 提供 Token、算力状态查询接口
**核心方法:**
```javascript
class MDWebSocketServer {
constructor() {
this.wss = null;
this.connectedClients = new Map();
this.currentJwtToken = null;
this.currentCapacity = { internal: 0, external: 0 };
this.instances = new Map();
}
// 初始化并启动 WebSocket 服务
async init()
// 获取当前 JWT Token
getJwtToken()
// 获取当前内部算力可用数
getInternalCapacity()
// 获取当前外部容量
getExternalCapacity()
// 获取所有实例状态
getInstances()
// 检查是否有连接的客户端
hasConnectedClients()
}
```
**WebSocket 消息处理:**
```javascript
// JWT Token 更新
handleJwtUpdate(data) {
this.currentJwtToken = data.token;
console.log('[MDWebSocketServer] JWT Token 已更新');
}
// 算力状态更新
handleCapacityUpdate(data) {
this.currentCapacity.internal = data.summary.onlineInstances - data.summary.busyInstances;
}
// 实例上线
handleInstanceOnline(data) {
this.instances.set(data.instanceId, { ...data, status: 'online' });
}
// 实例下线
handleInstanceOffline(data) {
this.instances.set(data.instanceId, { ...data, status: 'offline' });
}
// 心跳响应
handleHeartbeat(data, ws) {
ws.send(JSON.stringify({
type: 'HEARTBEAT_ACK',
data: { timestamp: new Date().toISOString() }
}));
}
```
**WebSocket 消息格式:**
```javascript
// message-dispatcher 发送的 JWT 更新消息
{
type: 'JWT_UPDATE',
data: {
token: 'eyJhbGciOiJIUzI1NiIs...',
expiresAt: '2024-01-02T00:00:00.000Z',
timestamp: '2024-01-01T00:00:00.000Z'
}
}
// message-dispatcher 发送的心跳
{
type: 'HEARTBEAT',
data: {
timestamp: '2024-01-01T00:00:00.000Z'
}
}
```
---
### 修改点 1新增 messageDispatcher 平台适配器
**文件:** `outside/outPlatforms/messageDispatcher.js`(新建)
**核心原则:**
- 与 runninghub.js 保持完全一致的接口方法签名
- 仅修改请求地址和 apiKey 字段的值
- 请求体所有字段名称、类型、格式与 runninghub 完全一致
- 任务提交通过 HTTP 接口URL 通过环境变量获取
**要求:**
- 参考 `runninghub.js` 的接口设计,保持方法签名完全一致
- 实现以下 6 个核心方法:
```javascript
getGenerateUrl() // 返回 message-dispatcher 的任务提交接口(从环境变量获取)
getGenerateHeader(apikey) // 返回请求头(包含 JWT Token 作为 apiKey
getGenerateBody(task) // 构造请求体(与 runninghub 完全一致)
getSuccessTasks(response) // 处理成功响应,转换为 runninghub 兼容格式
getTaskResult(response) // 处理结果回调
getQueryUrl() // 返回回调地址(与 runninghub 保持一致)
```
**请求体标准化规则:**
| 字段名称 | 类型 | 是否修改 | 说明 |
|---------|------|---------|------|
| `workflow_id` | String | 否 | 原样保留 |
| `node_info_list` | Array | 否 | 原样保留 |
| `apiKey` | String | 是 | 值改为 JWT Token |
| `webhookUrl` | String | 否 | 原样保留 |
| 其他所有字段 | - | 否 | 原样保留 |
**请求体示例对比:**
```javascript
// runninghub 请求体(原样)
{
"workflow_id": "123",
"node_info_list": [...],
"apiKey": "runninghub-api-key-xxx",
"webhookUrl": "http://callback-url"
}
// message-dispatcher 请求体(仅修改 apiKey 值)
{
"workflow_id": "123",
"node_info_list": [...],
"apiKey": "eyJhbGciOiJIUzI1NiIs...", // JWT Token
"webhookUrl": "http://callback-url"
}
```
**响应转换规则:**
```javascript
// message-dispatcher 响应
{ success: true, data: { requestId: "xxx" } }
// 转换为
{ msg: "success", code: 0, data: { taskId: "xxx" } }
```
---
### 修改点 2简化 JWT Token 获取(不再需要独立模块)
**重要说明:**
- 不再需要独立的 JWTManager 模块
- JWT Token 由 message-dispatcher 通过 WebSocket 主动推送
- Token 定期更新也通过 WebSocket 推送
- 从 MDWebSocketServer 获取 Token 即可
**Token 获取方式:**
```javascript
// 从 WebSocket 服务端获取当前 Token
const jwtToken = mdWebSocketServer.getJwtToken();
```
---
### 修改点 3新增任务分流模块
**文件:** `utils/taskDistributor.js`(新建)
**功能要求:**
1. 移除高低优先级区分
2. 实现统一的任务分流逻辑
3. 从 WebSocket 服务端获取实时容量信息
4. 根据容量进行任务分配
**核心计算公式:**
```
内部算力可用数 = 从 MDWebSocketClient 获取
外部容量上限 = 从配置/环境变量获取(如 10
总可分发任务上限 = 内部算力可用数 + 外部容量上限
```
**分流策略:**
| 待分发任务数 | 内部容量 | 外部容量 | 分配结果 |
|------------|---------|---------|---------|
| ≤ 内部 | 实时 | 10 | 全部走内部 |
| > 内部 ≤ 总 | 实时 | 10 | 前N内部超出部分走外部 |
| > 总 | 实时 | 10 | 内部 + 外部,剩余等待 |
**具体示例:**
```
示例 1
内部 = 30实时, 外部 = 10, 待分发 = 25
结果:全部 25 个走内部
示例 2
内部 = 30实时, 外部 = 10, 待分发 = 35
结果30 个内部5 个外部
示例 3
内部 = 30实时, 外部 = 10, 待分发 = 45
结果30 个内部10 个外部5 个等待
```
**核心实现:**
```javascript
async function distributeTasks(tasks, mdWebSocketServer) {
const internalCapacity = mdWebSocketServer.getInternalCapacity();
const externalCapacity = await getExternalCapacityFromConfig();
const internalTasks = tasks.slice(0, internalCapacity);
const externalTasks = tasks.slice(internalCapacity, internalCapacity + externalCapacity);
const remainingTasks = tasks.slice(internalCapacity + externalCapacity);
return { internalTasks, externalTasks, remainingTasks };
}
```
---
### 修改点 4修改任务分发逻辑批量
**文件:** `worker_threads/wait/waiting.js`
**修改位置:** 任务批量获取和分发逻辑
**要求:**
- 引入 MDWebSocketServer
- 在获取任务后,先调用 taskDistributor 进行分流(传入 WebSocket 服务端)
- 根据分流结果分别分发到内部/外部
- 剩余任务返回队列
---
### 修改点 5修改任务分发逻辑单个
**文件:** `outside/generat.js`
**修改位置:** `externalPostRequest()` 函数
**决策逻辑:**
```javascript
if (platform === 'runninghub') {
if (使用内部算力) {
尝试使用 messageDispatcher 平台发送任务
if (成功) {
返回内部结果
} else {
记录降级日志
降级使用 runninghub
}
} else {
使用 runninghub
}
} else {
使用原平台
}
```
**关键实现:**
- 引入 MDWebSocketServer从这里获取 JWT Token
- 引入 messageDispatcher 平台适配器
- 增加降级日志记录
- 保持原有错误处理逻辑不变
---
### 修改点 6更新平台管理
**文件:** `outside/outPlatforms/outside.js`
**修改内容:**
- 导入 messageDispatcher 模块
- 将其添加到导出对象中
```javascript
import * as runninghub from './runninghub.js';
import * as jimuai from './JimuAI.js';
import coze from './coze/coze.js';
import * as messageDispatcher from './messageDispatcher.js'; // 新增
export default { runninghub, jimuai, coze, messageDispatcher }; // 新增
```
---
### 修改点 7更新环境变量配置
**文件:** `.env`
**新增配置:**
```env
# Message Dispatcher 配置
MESSAGE_DISPATCHER_URL=http://localhost:4000
MESSAGE_DISPATCHER_WS_PORT=8087
MESSAGE_DISPATCHER_ENABLED=true
MESSAGE_DISPATCHER_TIMEOUT=30000
# 外部容量配置
EXTERNAL_CAPACITY_MAX=10
```
**说明:**
- `MESSAGE_DISPATCHER_URL`HTTP 任务提交接口 URL
- `MESSAGE_DISPATCHER_WS_PORT`:任务队列后端 WebSocket 服务端口
- 不再需要 MD_USERNAME 和 MD_PASSWORDToken 通过 WebSocket 推送)
---
### 修改点 9新增配置文件
**文件:** `config/messageDispatcher.json`(新建)
```json
{
"enabled": true,
"priority": true,
"task": {
"timeout": 30000,
"retryCount": 1
},
"capacity": {
"external": 10
},
"websocket": {
"port": 8087
}
}
```
---
### 修改点 10算力更新逻辑检查与修复
**文件:** `worker_threads/wait/waiting.js`、`worker_threads/callback_result/result.js`、`redis/initQueue.js` 等相关文件
**核心需求:**
- 详细检查任务状态管理与算力更新相关代码
- 验证 30 个任务未全部完成,收到算力更新通知的场景
- 实现未用算力数计算边界检查,防止负值
- 添加防御性编程,避免空转或无限循环
- 实现完整单元测试
#### 9.1 检查清单
| 检查项 | 检查文件 | 风险级别 |
|---------|---------|---------|
| 算力计数更新原子性 | `redis/initQueue.js` | 高 |
| 任务完成回调时算力计数 | `worker_threads/callback_result/result.js` | 高 |
| 算力减少时的任务处理 | `worker_threads/wait/waiting.js` | 高 |
| 负数检查与防御 | 所有相关文件 | 高 |
| 并发安全 | 所有相关文件 | 中 |
#### 9.2 核心修复方案
**修复 1添加算力计数边界检查**
**文件:** `redis/initQueue.js`
**问题:** 任务完成后PQtasks处理中任务数可能减为负数
**修复代码:**
```javascript
async function reducePlatformsProcess(platformKey) {
const key = `${prefix}:platforms:${platformKey}`;
try {
const current = await redis.hGet(key, 'PQtasks');
let newValue = parseInt(current) - 1;
// 边界检查:确保不小于 0
if (newValue < 0) {
console.warn(`[CapacityManager] 检测到负值: ${platformKey} PQtasks = ${newValue}, 已修正为 0`);
newValue = 0;
}
await redis.hSet(key, 'PQtasks', newValue.toString());
console.log(`[CapacityManager] ${platformKey} PQtasks: ${current} -> ${newValue}`);
return newValue;
} catch (error) {
console.error(`[CapacityManager] 更新 PQtasks 失败:`, error);
throw error;
}
}
```
**修复 2添加算力更新状态锁**
**文件:** `utils/capacityGuard.js`(新建)
**功能:** 防止算力更新期间的并发问题
```javascript
class CapacityGuard {
constructor() {
this.updateLock = false;
this.pendingUpdates = [];
}
async acquireLock() {
while (this.updateLock) {
await new Promise(resolve => setTimeout(resolve, 10));
}
this.updateLock = true;
}
releaseLock() {
this.updateLock = false;
// 处理排队的更新
if (this.pendingUpdates.length > 0) {
const nextUpdate = this.pendingUpdates.shift();
nextUpdate();
}
}
async executeWithLock(fn) {
await this.acquireLock();
try {
return await fn();
} finally {
this.releaseLock();
}
}
}
export default new CapacityGuard();
```
**修复 3处理算力突然降低场景**
**文件:** `worker_threads/wait/waiting.js`
**场景:** 已发送 30 个任务,算力降低至 20任务未全部完成
**修复代码:**
```javascript
async function handleCapacityReductionFromMD(newInternalCapacity) {
console.log(`[Waiting] 收到算力更新: 内部容量 -> ${newInternalCapacity}`);
await capacityGuard.executeWithLock(async () => {
// 获取当前正在处理的任务数
const currentProcessing = await getCurrentProcessingCount();
if (currentProcessing <= newInternalCapacity) {
console.log(`[Waiting] 当前处理数 ${currentProcessing} ≤ 新容量 ${newInternalCapacity}, 无需调整`);
return;
}
const excess = currentProcessing - newInternalCapacity;
console.warn(`[Waiting] 检测到算力降低: 当前处理 ${currentProcessing} > 新容量 ${newInternalCapacity}, 超出 ${excess} 个任务`);
// 记录超出情况,但不主动取消任务
// 让任务自然完成,通过回调正确更新计数
console.log(`[Waiting] 将等待任务自然完成,确保计数正确`);
});
}
```
**修复 4添加空转防御**
**文件:** `worker_threads/wait/waiting.js`
**问题:** 无任务时可能无限循环
**修复代码:**
```javascript
// 主循环
(async () => {
let idleCount = 0;
const MAX_IDLE_COUNT = 10; // 最大连续空转次数
const IDLE_SLEEP_MS = 10000; // 空转时的睡眠时间
while (true) {
try {
const wDeficiency = await judgConcurrency();
if (wDeficiency.length > 0) {
idleCount = 0; // 重置空转计数
logger.info('有可进行处理的队列,数量: ' + wDeficiency.length);
// ... 原有处理逻辑 ...
} else {
idleCount++;
if (idleCount >= MAX_IDLE_COUNT) {
logger.debug(`连续空转 ${idleCount} 次,进入长睡眠`);
await new Promise(resolve => setTimeout(resolve, IDLE_SLEEP_MS));
idleCount = 0;
} else {
logger.debug('没有可处理的队列');
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
} catch (error) {
logger.error('批量处理任务失败:', error);
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
})();
```
#### 9.3 单元测试方案
**测试文件:** `test/capacity.test.js`(新建)
**测试用例:**
```javascript
describe('Capacity Management Tests', () => {
test('正常情况: 任务完成后算力正确增加', async () => {
await initQueue.addPlatformsProcess({ 'digitalHuman:runninghub': 1 });
const result = await initQueue.reducePlatformsProcess('digitalHuman:runninghub');
assert.strictEqual(result, 0);
});
test('边界情况: 算力为0时尝试减少', async () => {
await initQueue.addPlatformsProcess({ 'digitalHuman:runninghub': 0 });
const result = await initQueue.reducePlatformsProcess('digitalHuman:runninghub');
assert.strictEqual(result, 0, '应该保持为0');
});
test('边界情况: 算力从30降低到20时的处理', async () => {
// 模拟发送30个任务
for (let i = 0; i < 30; i++) {
await initQueue.addPlatformsProcess({ 'digitalHuman:runninghub': 1 });
}
// 模拟收到算力降低通知
await handleCapacityReductionFromMD(20);
// 验证不会导致负数
const currentPQtasks = await getCurrentPQtasks();
assert(currentPQtasks >= 0, 'PQtasks 不能为负数');
});
test('防御性测试: 并发更新', async () => {
const promises = [];
for (let i = 0; i < 100; i++) {
promises.push(initQueue.addPlatformsProcess({ 'digitalHuman:runninghub': 1 }));
promises.push(initQueue.reducePlatformsProcess('digitalHuman:runninghub'));
}
await Promise.all(promises);
const finalCount = await getCurrentPQtasks();
assert(finalCount >= 0, '并发更新后不能为负数');
});
test('防御性测试: 空转检测', async () => {
const startTime = Date.now();
// 模拟无任务场景
await simulateIdleLoop();
const duration = Date.now() - startTime;
assert(duration < 60000, '不应该无限循环');
});
});
```
#### 9.4 验证检查清单
| 验证项 | 验证方法 | 预期结果 |
|--------|---------|---------|
| 算力不出现负值 | 检查日志中是否有负值警告 | 如有警告,确认已自动修正为 0 |
| 任务完成后计数正确 | 发送 10 个任务,全部完成 | 最终 PQtasks = 0 |
| 算力降低时不崩溃 | 发送 30 个任务,降低算力到 20 | 系统稳定运行,无错误 |
| 无任务时不空转 | 监控无任务时的 CPU | 进入睡眠,不占用 CPU |
| 并发更新安全 | 100 次并发增减 | 最终计数正确,无负值 |
---
## 二、message-dispatcher 项目修改指导
### 项目路径
`d:\Ke_xue_web\独立项目\comfyui桥接器\message-dispatcher\`
---
### 修改点 1新增 WebSocket 客户端模块
**文件:** `src/md-websocket-client/index.js`(新建)
**通信架构说明:**
- message-dispatcher 作为 WebSocket 客户端,主动连接任务队列后端
- WebSocket 用于:
- JWT Token 主动推送与定期更新
- 算力状态上报
- 实例状态变化同步
- 心跳保活
- **仅任务提交通过 HTTP 接口完成**
- **所有其他通信(包括 Token 推送)均通过 WebSocket**
**功能要求:**
1. 建立与任务队列后端的 WebSocket 连接
2. 连接成功后立即推送当前 JWT Token
3. 定期推送 JWT Token 更新(如每 20 小时)
4. 定期推送算力状态CAPACITY_UPDATE
5. 实例状态变化时推送INSTANCE_ONLINE/INSTANCE_OFFLINE 等)
6. 发送心跳保持连接
7. 自动重连机制(指数退避)
**核心方法:**
```javascript
class MDWebSocketClient {
constructor() {
this.ws = null;
this.connected = false;
this.reconnectAttempts = 0;
this.tokenPushInterval = null;
this.capacityPushInterval = null;
}
// 初始化并连接
async init()
// 连接到任务队列后端
async connect()
// 断开连接
disconnect()
// 推送 JWT Token
pushJwtToken()
// 推送算力状态
pushCapacityState()
// 推送实例上线
pushInstanceOnline(instanceId)
// 推送实例下线
pushInstanceOffline(instanceId)
// 发送消息
send(message)
// 处理接收到的消息
handleMessage(message)
}
```
**WebSocket 消息格式message-dispatcher 发送):**
```javascript
// JWT Token 更新推送
{
type: 'JWT_UPDATE',
data: {
token: 'eyJhbGciOiJIUzI1NiIs...',
expiresAt: '2024-01-02T00:00:00.000Z',
timestamp: '2024-01-01T00:00:00.000Z'
}
}
// 算力状态更新推送
{
type: 'CAPACITY_UPDATE',
data: {
timestamp: '2024-01-01T00:00:00.000Z',
bridges: [...],
summary: {
totalBridges: 2,
totalInstances: 8,
onlineInstances: 6,
busyInstances: 2,
availableCapacity: 4
}
}
}
// 心跳
{
type: 'HEARTBEAT',
data: {
timestamp: '2024-01-01T00:00:00.000Z'
}
}
```
---
### 修改点 2修改启动流程集成 WebSocket 客户端
**文件:** `src/index.js`
**修改内容:**
- 导入并初始化 MDWebSocketClient
- 在服务启动后启动 WebSocket 客户端
- 在服务关闭时断开 WebSocket 连接
---
### 修改点 3新增 runninghub 兼容接口(可选)
**目标:** 确保接口兼容性,新增 runninghub 兼容的任务提交接口
**文件:** `src/api/index.js`
**新增接口(可选):**
```javascript
// 兼容 runninghub 格式的任务提交接口
router.post('/task/runninghub', authMiddleware, async (req, res) => {
// 请求体已经是 runninghub 格式,直接使用
// 调用现有 /api/task 逻辑
});
```
---
### 修改点 4确保回调兼容
**说明:** message-dispatcher 已支持 `webhookUrl` 参数,任务完成后会调用该回调。需要确保回调格式与 runninghub 保持一致。
**检查点:**
- 确认 `TASK_END` 消息处理中正确调用 webhookUrl
- 确保回调数据格式与 runninghub 兼容
---
### 修改点 5新增任务处理与算力动态调整机制
**文件:** `src/task-scheduler/index.js`(新建)
**核心需求:**
- 当任务队列后端发送 30 个任务,而系统算力突然降低至 20 时,实现任务保留机制
- 将超出当前算力的任务存入缓存队列
- 实时监控算力变化,有空闲算力时按 FIFO 取出任务处理
- 管理缓存任务状态(等待中、处理中、已完成、失败重试等)
**数据结构设计:**
| 数据结构 | 类型 | 说明 |
|---------|------|------|
| `pendingTaskQueue` | Array | 待执行任务缓存队列FIFO |
| `processingTasks` | Map | 执行中任务 |
| `completedTasks` | List | 已完成任务(最近 1000 条) |
| `failedTasks` | List | 失败任务(最近 100 条) |
**任务状态定义:**
```javascript
const TASK_STATES = {
PENDING: 'pending', // 等待中
PROCESSING: 'processing', // 处理中
COMPLETED: 'completed', // 已完成
FAILED: 'failed', // 失败
RETRYING: 'retrying' // 重试中
};
```
**核心类设计:**
```javascript
class TaskScheduler {
constructor() {
this.pendingTaskQueue = []; // FIFO 队列
this.processingTasks = new Map(); // taskId -> taskInfo
this.currentCapacity = 0; // 当前可用算力
this.maxCapacity = 0; // 最大算力
this.schedulerLoop = null;
}
// 初始化调度器
async init()
// 设置当前可用算力
setCurrentCapacity(capacity)
// 添加任务到缓存队列
addTaskToPending(task)
// 从缓存队列取出任务
getTaskFromPending()
// 将任务标记为处理中
markTaskAsProcessing(taskId, instanceId)
// 将任务标记为已完成
markTaskAsCompleted(taskId, result)
// 将任务标记为失败
markTaskAsFailed(taskId, error)
// 主调度循环
async schedulerLoop()
// 检查是否有空闲算力
hasAvailableCapacity()
// 获取可用任务数
getAvailableSlots()
// 处理算力降低
handleCapacityReduction(newCapacity)
// 处理算力增加
handleCapacityIncrease(newCapacity)
}
```
**场景处理示例:**
**场景 1算力从 30 降低至 20**
```javascript
async handleCapacityReduction(newCapacity) {
const currentProcessingCount = this.processingTasks.size;
// 如果处理中的任务数超过新容量
if (currentProcessingCount > newCapacity) {
const excessCount = currentProcessingCount - newCapacity;
// 获取最早开始的 excessCount 个任务
const tasksToMoveBack = Array.from(this.processingTasks.values())
.sort((a, b) => a.startTime - b.startTime)
.slice(0, excessCount);
// 将任务移回 pending 队列头部(优先级高)
for (const task of tasksToMoveBack.reverse()) {
this.processingTasks.delete(task.taskId);
this.pendingTaskQueue.unshift({
...task,
state: TASK_STATES.PENDING,
movedBackAt: new Date().toISOString()
});
}
console.log(`[TaskScheduler] 算力降低: ${this.currentCapacity} -> ${newCapacity}, 已将 ${excessCount} 个任务移回缓存队列`);
}
this.currentCapacity = newCapacity;
}
```
**场景 2有空闲算力时调度任务**
```javascript
async schedulePendingTasks() {
const availableSlots = this.getAvailableSlots();
if (availableSlots <= 0 || this.pendingTaskQueue.length === 0) {
return;
}
const tasksToSchedule = this.pendingTaskQueue.splice(0, availableSlots);
for (const task of tasksToSchedule) {
// 分配任务到可用实例
const instanceId = await this.selectAvailableInstance();
this.markTaskAsProcessing(task.taskId, instanceId);
// 发送任务到实例
await this.sendTaskToInstance(task, instanceId);
}
console.log(`[TaskScheduler] 已调度 ${tasksToSchedule.length} 个任务`);
}
```
**算力更新监听:**
```javascript
// 监听来自任务队列后端的算力更新(通过 WebSocket
handleCapacityUpdateFromBackend(data) {
const newCapacity = data.summary.availableCapacity;
if (newCapacity < this.currentCapacity) {
this.handleCapacityReduction(newCapacity);
} else if (newCapacity > this.currentCapacity) {
this.handleCapacityIncrease(newCapacity);
} else {
this.currentCapacity = newCapacity;
}
}
```
---
### 修改点 6集成任务调度器到主流程
**文件:** `src/index.js`
**修改内容:**
- 导入并初始化 TaskScheduler
- 在 WebSocket 客户端收到算力更新时通知调度器
- 在任务开始/完成时通知调度器更新状态
- 在服务关闭时优雅关闭调度器
---
## 三、技术要求
### 3.1 代码规范
- 遵循现有代码风格ES Module, async/await
- 保持与 runninghub.js 相同的接口签名
- 请求体字段名称、类型、格式必须与 runninghub 完全一致
- 仅修改 apiKey 字段的值为 JWT Token
- 添加充分的日志记录(使用 console.log/console.error
### 3.2 错误处理
- 健康检查失败不应导致主进程崩溃
- 降级机制必须可靠
- 超时处理完善
- JWT Token 更新失败不应中断服务
### 3.3 性能要求
- 健康检查间隔不小于 10 秒
- 决策时间不超过 100ms
- 不影响现有系统吞吐量
---
## 四、验收标准
### 4.1 功能验收
- [ ] 任务分流逻辑正确:≤内部容量全部走内部,超出部分走外部
- [ ] message-dispatcher 不可用时自动降级至 runninghub
- [ ] 请求体与 runninghub 完全一致(仅 apiKey 值不同)
- [ ] JWT Token 自动更新机制正常工作
- [ ] 任务成功执行并返回正确结果
- [ ] 回调接口正常工作
- [ ] 现有功能不受影响jimuai、coze 等平台正常工作)
### 4.2 接口兼容性验收
- [ ] messageDispatcher.js 接口方法签名与 runninghub.js 完全一致
- [ ] 请求体字段名称、类型、格式与 runninghub 完全一致
- [ ] 响应格式与 runninghub 兼容
- [ ] 不修改 runninghub.js 的任何代码
### 4.3 容量边界验收
- [ ] WebSocket 服务正常启动message-dispatcher 成功连接
- [ ] JWT Token 成功通过 WebSocket 接收
- [ ] JWT Token 定期更新通过 WebSocket 接收
- [ ] 算力状态实时同步(通过 WebSocket
- [ ] 实例状态变化实时同步(通过 WebSocket
- [ ] 场景 125个任务 → 全部25个走内部实时容量
- [ ] 场景 230个任务 → 全部30个走内部实时容量
- [ ] 场景 335个任务 → 30个内部5个外部实时容量
- [ ] 场景 440个任务 → 30个内部10个外部实时容量
- [ ] 场景 545个任务 → 30个内部10个外部5个等待实时容量
### 4.4 日志验收
- [ ] 记录每次分发决策(使用内部/外部)
- [ ] 记录容量使用统计
- [ ] 记录降级事件及原因
- [ ] 记录 JWT Token 接收/更新日志(通过 WebSocket
- [ ] 记录 WebSocket 连接/断开日志
### 4.5 可靠性验收
- [ ] message-dispatcher 重启后自动恢复
- [ ] 网络波动不影响降级逻辑
- [ ] JWT Token 自动更新不中断服务
- [ ] 连续运行 24 小时无崩溃
### 4.6 算力管理验收
- [ ] 算力计数从不出现负值
- [ ] 任务完成后算力计数正确增加
- [ ] 算力从 30 降低到 20 时系统稳定
- [ ] 无任务时进入睡眠,不空转
- [ ] 100 次并发更新后计数正确
- [ ] 单元测试覆盖正常、边界、异常情况
---
## 五、关键文件参考
### 任务队列后端
- `outside/outPlatforms/runninghub.js` - 参考接口设计
- `outside/generat.js` - 修改任务分发逻辑
- `outside/outPlatforms/outside.js` - 平台注册
- `worker_threads/wait/waiting.js` - 批量任务分流
- `worker_threads/wait/generatTask.js` - 任务处理流程
### message-dispatcher
- `src/api/index.js` - API 接口定义
- `src/bridge-manager/index.js` - 桥接器管理
- `src/websocket-server/index.js` - 任务发送逻辑
---
## 六、实现顺序建议
### 任务队列后端实现顺序
1. **第一步:** 创建 `mdWebSocketServer.js` WebSocket 服务模块
2. **第二步:** 创建 `taskDistributor.js` 任务分流模块
3. **第三步:** 创建 `messageDispatcher.js` 平台适配器
4. **第四步:** 修改 `waiting.js` 实现批量任务分流
5. **第五步:** 修改 `generat.js` 实现单任务分发决策
6. **第六步:** 更新 `outside.js` 和配置文件
7. **第七步:** 检查并修复 `redis/initQueue.js` 算力计数(添加边界检查)
8. **第八步:** 创建 `capacityGuard.js` 算力更新锁
9. **第九步:** 修改 `waiting.js` 添加空转防御
10. **第十步:** 创建单元测试 `test/capacity.test.js`
11. **第十一步:** 测试验证功能
### message-dispatcher 实现顺序
1. **第一步:** 创建 `md-websocket-client/index.js` WebSocket 客户端模块
2. **第二步:** 修改 `src/index.js` 集成 WebSocket 客户端
3. **第三步:** 创建 `task-scheduler/index.js` 任务调度器
4. **第四步:** 修改 `src/index.js` 集成任务调度器
5. **第五步:** 添加 runninghub 兼容接口(可选)
6. **第六步:** 确保回调兼容
7. **第七步:** 测试验证功能
---
## 七、注意事项
⚠️ **重要提醒:**
1. **不要修改** `runninghub.js` 的现有代码
2. **保持** `externalPostRequest()` 的返回值格式不变
3. **确保** 请求体与 runninghub 完全一致(仅 apiKey 值不同)
4. **确保** 回调接口格式与 runninghub 完全一致
5. **不要** 破坏现有其他平台jimuai、coze的功能
6. **移除** 所有高低优先级任务的区分逻辑
7. **新增** 日志时使用清晰的前缀,如 `[MessageDispatcher]`、`[JWTManager]`、`[TaskDistributor]`
---
## 八、验证方法
### 8.1 接口兼容性验证
**验证步骤:**
1. 对比 messageDispatcher.js 与 runninghub.js 的方法签名
2. 验证 getGenerateBody() 返回的请求体字段名称
3. 验证 getGenerateBody() 返回的请求体字段类型
4. 确认仅 apiKey 字段的值被修改
**验证代码:**
```javascript
// 对比两个平台适配器的接口
const runninghubMethods = Object.keys(runninghub);
const messageDispatcherMethods = Object.keys(messageDispatcher);
assert.deepEqual(runninghubMethods, messageDispatcherMethods, '接口方法必须一致');
```
### 8.2 任务分流验证
**验证场景:**
1. 构造不同数量的待分发任务
2. 检查内部/外部任务分配比例
3. 验证不超过各自容量上限
---
现在,请按照以上指导开始实现!