shuzhiren-comfyui/OPTIMIZATION_REPORT.md

22 KiB
Raw Blame History

ComfyUI Cluster Bridge 优化报告

生成日期2026-05-12 分析范围backend / frontend / message-dispatcher / 任务队列后端 四个子项目


一、严重问题Critical

1.1 任务状态机断裂 — 死代码导致任务永远无法进入 running 状态

文件task-forwarder/index.js

问题sendTaskToInstance 方法中catch 块通过 throw new Error(errorMessage) 重新抛出异常,导致 task.status = 'submitted'L191-L192作为死代码永远无法被执行。这意味着所有成功提交的任务状态永远是 pending,而非 submitted。进而 handleExecutionStart 中的状态检查L209-L212总是失败任务永远无法进入 running 状态。

影响:核心业务流程断裂,任务的完整生命周期无法正常流转。


1.2 临时文件泄漏 — 磁盘空间耗尽风险

文件file-uploader/index.js

问题L118-L121 的临时文件清理代码(fs.existsSync + fs.unlinkSync)被整块注释。结合 task-forwarder/index.jsuploadImage 方法每次都写入 uploads/ 目录,所有通过 HTTP API 下载的临时文件永远不会被删除。

影响:生产环境运行一段时间后磁盘空间会被耗尽。


1.3 心跳定时器泄漏 — 停止后仍在发送心跳

文件task-queue-client/index.js

问题L37-L39 中 setInterval 创建的定时器引用未存储在实例属性上。调用 stop() 时无法 clearInterval,导致即使 stop 后心跳仍在尝试发送。

影响:关闭连接后产生大量错误日志,资源泄漏。


1.4 Token 刷新失败时请求永久挂起

文件request.js

问题L76-L79 中 token 刷新失败后,refreshSubscribers 中的回调永远不会被执行(既不 resolve 也不 reject导致堆积在队列中的请求 Promise 永久挂起,造成内存泄漏

影响:用户体验卡死,内存持续增长。


1.5 废弃 API 导致实例增删改功能永远失败

文件api/index.js

问题addInstanceupdateInstancedeleteInstanceL220-L233被标记为废弃并始终 Promise.reject,但 Config.vueInstances.vue 仍在调用它们。

影响:用户看到的添加/编辑/删除操作永远提示失败,属于功能缺陷


1.6 app.js 与 webSocket.js 严重代码重复

文件app.js / webSocket.js

问题:两个文件(各 370+ 行)的 WebSocket 逻辑、Worker 线程创建、sendMessageToClientcreateWebSocketServergracefulShutdown 等功能超过 90% 完全相同。如果同时启动会导致端口冲突。

影响:维护成本翻倍,修改时极易遗漏,已存在多处逻辑不一致。


1.7 Worker 线程崩溃后无重启机制

文件app.js / webSocket.js

问题Worker 线程的 exit 事件仅记录日志L42-L49没有任何重启逻辑。

影响Worker 线程意外崩溃后,该线程负责的整个任务处理管道将永久停滞。


1.8 socketMap 内存泄漏

文件app.js / webSocket.js

问题socket.on('close') 处理中L280-L284只清除定时器并记录日志未从 socketMap 中删除已关闭的连接

影响:长时间运行后 socketMap 持续增长,内存泄漏。


1.9 服务器重启直接丢弃等待队列

文件initQueue.js

问题L95-L98 在检测到 existingInfo 存在时,直接 redis.del(waitName) 删除所有等待队列数据,没有尝试将任务恢复或迁移。

影响:服务器重启会导致所有等待中的任务永久丢失。


1.10 回调接口先发 200 再异步处理

文件callback.js

问题L7 先向客户端发送 200 成功响应,再异步处理数据。如果后续处理失败,客户端已收到成功响应,无法感知。

影响:数据完整性风险,错误无法通知上游系统。


1.11 配置文件加载无异常保护

文件Config.js

问题fs.readFileSync + JSON.parse 未包裹 try-catch。如果 model.jsonPlatform.jsoncost.json 损坏或丢失,整个进程直接崩溃。

影响:配置文件损坏导致服务不可用,毫无恢复能力。


1.12 容量配置的 falsy 值判断错误

文件taskDistributor.js

问题L6 使用 parseInt(...) || 10,当 EXTERNAL_CAPACITY_MAX=0 时(意为"禁止外部任务"0 是 falsy 值,会错误回退到默认值 10。应使用 ?? 或显式 isNaN 检查。

影响:配置语义被曲解,无法正确禁用外部任务。


1.13 Config.vue 与 Instances.vue 100% 代码重复

文件Config.vue / Instances.vue

问题:两个文件内容完全一致。路由标题是"配置管理",但显示的是实例管理页面。显然是复制粘贴后忘记修改。

影响:语义混乱,无法区分配置管理和实例管理功能。


1.14 登录页明文展示默认账号密码

文件Login.vue

问题L54 在模板底部直接展示"默认账号: admin / admin123"且表单初始值L73-L76硬编码了这些凭据。

影响:严重安全隐患,即使是内部管理系统也不应在 UI 明文展示凭据。


1.15 监控页面 ECharts 全量导入 + 假数据

文件Monitor.vue

问题

  • L102import * as echarts from 'echarts' 全量导入,增加约 1MB 未压缩体积
  • L126-L135趋势图使用硬编码随机模拟数据无实际业务价值
  • L389-L398首次加载时先刷新数据再初始化图表导致首次渲染显示全 0 数据

影响Bundle 体积暴增,监控数据无实际意义。


1.16 task-scheduler 超时检查定时器无法清除

文件task-scheduler/index.js

问题L385-L389 的 startTimeoutCheck()setInterval 返回值未存储,导致 shutdown 时无法清除,定时器回调在服务停止后仍可能执行。


1.17 Redis 多连接实例浪费

文件jwt.js / rate-limit.js

问题:两个文件各自创建独立的 new Redis() 实例连接到同一个 Redis 服务器,浪费 TCP 连接资源。应抽取共享 Redis 单例模块。


1.18 速率限制的竞态条件

文件rate-limit.js

问题L28-L41 使用 exists + incr/setex 模式,存在竞态条件。两个并发请求同时到达且 key 不存在时,第二次 setex 会覆盖第一次的计数器。应改为 incr + 条件 expire 模式。


1.19 密码验证的时序竞态

文件routes.js

问题L15-L23 通过顶层 IIFE 异步计算 hashedAdminPassword。在该 Promise 完成之前到达的登录请求会退化为明文比较L46造成短期安全窗口。


1.20 WebSocket Server 任务发送失败未回调调度器

文件websocket-server/index.js

问题sendTaskToInstance 立即失败路径L299-L301释放了实例锁但未调用 taskScheduler.handleTaskFailure,导致任务在 processingTasks Map 中残留。


二、高优先级问题High

2.1 多个模块缺少过期清理机制

文件 对象 说明
task-forwarder/index.js this.tasks Map 已完成任务永不清理,内存持续增长
workflow-converter/index.js this.cache Map 无限增长的工作流缓存

建议:添加 TTL 或 LRU 淘汰策略,定期清理过期条目。


2.2 硬编码敏感信息

多处代码中存在硬编码的 IP 地址、Token、凭证等

文件 行号 内容
workflow-converter/index.js L6 http://117.72.204.159/AIGC/static/public/workflows
file-uploader/index.js L35-L36 内网地址 + Token '123456'
task-queue-client/index.js L43 wss://www.whjbjm.com/message-dispatcher
task-scheduler/index.js L24-L27 队列大小限制硬编码
jwt.js L4 JWT_SECRET 默认值

建议:所有敏感配置和外部依赖地址应全部通过环境变量配置。


2.3 console.log 调试残留 / 日志不一致

文件 说明
task-queue-client/index.js L176 生产环境残留 console.log
websocket-server/index.js 大量 console.log/warn 混用,未统一使用 winston logger

2.4 全量注册 Element Plus 图标

文件main.js L14-L16

问题for...of 循环将整个图标库(约 300+ 个)全部注册为全局组件,预估增加 ~400KB bundle。实际只使用了约 13 个图标。

建议:删除全局注册循环,改为按需导入。


2.5 refreshToken 命名冲突

文件user.js

问题L7 的 state refreshToken 与 L78 的 action refreshToken(由 refreshTokens 别名)同名,导致代码可读性严重下降。


2.6 两个 axios 实例 token 处理逻辑不一致

文件api/index.js

问题messageDispatcherRequestrequest.js 是两个独立 axios 实例token 拦截逻辑重复实现且行为不一致。


2.7 bridge-manager 锁超时不匹配

文件bridge-manager/index.js

问题LOCK_TIMEOUT 仅 30 秒,但 TASK_TIMEOUT 为 30 分钟。任务确认可能因长耗时而在锁超时之后到达,此时锁已被自动释放。


2.8 schedulePendingTasks 缺乏并发保护

文件task-scheduler/index.js

问题L170-L178 被多个异步路径同时调用addTask、handleTaskComplete、handleTaskFailure、handleInstanceOffline、setCurrentCapacity、定时器没有并发保护极端情况下可能导致任务重复分配或丢失。


2.9 Worker 线程管道配置未统一

文件initQueue.js

问题

  • addPlatformsProcessL238-L256taskCountMapcount 值被完全忽略,仅按 Map 条目计数
  • recoverPlatformCountsL109-L125计算了 pollingCount 但从未写回 Redis实际上没有执行恢复操作
  • reducePlatformsProcessSingleL260-L285在整个代码库中从未被调用死代码

2.10 部分 fetch 请求无超时设置

文件generat.js / polling.js / record.js

问题fetch() 调用未设置超时,外部平台无响应时请求可能挂起极长时间。


三、中优先级问题Medium

3.1 缺少优雅关闭处理

文件index.jsbackend / index.js任务队列

问题:没有 SIGTERM/SIGINT 信号处理,进程被 kill 时无法执行清理(关闭 WebSocket 连接、停止健康检查等)。


3.2 健康检查的 setInterval 堆积风险

文件cluster-manager/index.js

问题L52-L55 使用 setInterval 顺序检查实例。如果某次检查耗时超过 interval任务会堆积。建议改用 setTimeout 递归模式。


3.3 负载均衡未使用实际负载数据

文件cluster-manager/index.js

问题selectInstance 使用简单轮询Round-Robin不利用已维护的 load 字段。建议实现加权轮询或最少连接算法。


3.4 工作流缓存的深拷贝效率

文件workflow-converter/index.js

问题:多处使用 JSON.parse(JSON.stringify(...)) 做深拷贝,对于大型工作流效率较低。可考虑使用 structuredCloneNode 17+ 支持)。


3.5 前端路由缺少 404 页面

文件router/index.js

问题:没有通配 404 路由,未匹配路径显示空白页面。


3.6 实例管理端口号计算不可靠

文件Instances.vue L147

问题openAddDialog 中端口号计算 8001 + instances.value.length,如果有删除操作,端口号可能重复。


3.7 健康检查后不必要的全量刷新

文件instance.js L33-L58

问题:每次健康检查操作成功后调用 fetchInstances() 重新拉取全部实例,建议仅更新被检查实例的状态。


3.8 任务列表缺少分页

文件Tasks.vue / task.js

问题fetchTasks 一次性拉取所有任务,无 page/limit 参数。数据量大时会造成性能问题。


3.9 移动端响应式适配缺失

文件MainLayout.vue

问题:侧边栏仅支持折叠模式,无移动端的抽屉式导航适配。


3.10 垃圾回收 / 清理脚本分散

项目中存在多个一次性清理脚本(clear_coze_tokens.jsclear_old_platforms.jsreset_pqtasks.jscheckQueue.jscheck_redis.js),缺乏统一的运维工具入口。


3.11 mdWebSocketServer 能力状态 external 永远为 0

文件mdWebSocketServer.js

问题L105-L106 只更新了 this.currentCapacity.internal,而 external 从未更新,始终为 0。


3.12 消息 key 并发冲突风险

文件messagePersistence.js

问题L33 使用 Date.now() 生成 messageKey同一毫秒内多消息会导致 key 冲突,消息丢失。


3.13 redis.keys() 应改为 SCAN

文件queueRecovery.js L112

问题redis.keys() 是 O(N) 阻塞操作,生产环境应使用 SCAN 游标方式遍历。


3.14 capacityGuard 使用忙等待自旋锁

文件capacityGuard.js

问题L7-L12 使用 setTimeout(resolve, 10) 实现忙等待,高并发时产生大量定时器。建议改用 Promise 队列模式。


3.15 前端缺少全局错误处理器

文件main.js

问题:没有 app.config.errorHandler 设置,未捕获错误不会上报或友好提示。


四、架构层面建议

4.1 项目结构

问题 建议
根 package.json 的依赖与实际使用的子项目依赖不一致 使用 pnpm workspace 或 nx/turborepo 统一管理 monorepo
任务队列后端目录名含中文(任务队列后端 改为英文目录名,避免跨平台兼容问题
app.js 和 webSocket.js 重复 提取公共逻辑到共享模块
.env 文件中含敏感信息Redis 密码、JWT Secret 等) 从代码仓库中移除(如果已提交,需轮换密钥并清理历史)

4.2 统一日志管理

当前三个子项目backend、message-dispatcher、任务队列后端都使用了 winston

  • 部分模块仍使用 console.log
  • 日志级别和格式未统一
  • 缺少结构化日志JSON 格式)支持,不利于日志聚合分析

建议:提取共享 logger 包,统一日志格式,支持生产环境 JSON 输出。

4.3 统一错误处理

各子项目 HTTP API 的错误响应格式不统一,建议定义统一的错误响应结构(如 { code, message, data }),并在中间件层面统一处理。

4.4 环境变量管理

多个 .env 文件中存在重复定义(如 REDIS_HOST、JWT_SECRET部分配置优先从 config 文件读取,部分从环境变量读取,读取优先级不统一。建议:

  • 使用单一配置加载策略
  • 环境变量优先级始终高于配置文件
  • 文档化所有配置项

4.5 测试覆盖

当前项目没有明显的测试文件(根 package.json 的 vitest 仅声明未使用),建议为核心模块添加单元测试,特别是:


五、优先级排序(按修复建议)

优先级 编号 问题 预估工时
P0 1.1 任务状态机断裂(死代码)
P0 1.2 临时文件泄漏
P0 1.3 心跳定时器泄漏
P0 1.4 Token 刷新失败请求挂起
P0 1.5 废弃 API 导致功能失败
P0 1.11 配置文件无异常保护
P0 1.12 容量配置 falsy 判断错误
P0 1.15 监控页面假数据
P0 1.14 登录页明文凭据
P1 1.6 app.js/webSocket.js 重复
P1 1.7 Worker 无重启机制
P1 1.8 socketMap 内存泄漏
P1 1.9 重启丢弃队列
P1 1.10 回调先 200 再处理
P1 1.13 Config/Instances 重复
P1 1.16-1.20 message-dispatcher 问题集
P1 2.1 内存泄漏Map 无清理)
P1 2.4 Element Plus 图标全量导入
P2 2.2-2.10 高优改进项
P3 3.1-3.15 中优改进项 中-大

报告结束。以上问题均仅作分析记录,未对代码进行任何修改。