神慧
Sun Jul 05 2026 08:00:00 GMT+0800 (China Standard Time)·6 min readAI

AI 出图任务队列:GPU 调度与失败重试

多用户批量出图时,队列设计决定你是「能用」还是「排队炸掉」。

#GPU#Redis#队列#ComfyUI

商图批量场景下,GPU 是稀缺资源。没有队列,服务端会被同步 HTTP 请求打穿;有队列但没有优先级与重试策略,用户会感觉「任务石沉大海」。我用 Redis 做任务队列与分布式锁,Worker 专责调 ComfyUI API——Web 层只负责入队和查状态,绝不占 GPU。

队列模型

  • 任务表:参数快照、模板版本、优先级、状态、重试次数、创建时间
  • Worker 拉取 → 锁定 → 调用 ComfyUI → 轮询或 webhook 收结果 → 回写对象存储
  • 心跳续租:Worker 挂了,锁过期后任务可被其他 Worker 接管,状态回到「待执行」

优先级建议分档:人工催审 > 上新 deadline > 普通批量。同档内 FIFO,避免 starvation 可通过 aging 提升等待过久任务的权重。

失败分类与重试

可重试:临时 OOM、ComfyUI 节点超时、对象存储上传抖、网络瞬断。采用指数退避,上限 3 次,并记录最后一次错误栈。

不可重试:工作流 JSON 损坏、非法参数、模型文件缺失、模板版本已下架。快速失败,给业务可读原因(如「模型 xxx 未安装」),避免空转占 GPU。

常见坑

  • 重试时不清理 ComfyUI 侧半成品,磁盘被 temp 撑满
  • 无并发上限,多 Worker 同时拉满显存,集体 OOM
  • 任务状态只有「进行中」,Worker 崩溃后永远卡住——必须有锁超时与接管逻辑

观测与容量

队列长度、平均等待时间、P95 等待、GPU 利用率、失败率分类型统计。出图系统的 SLA,往往卡在「等」而不是「算」——扩容 GPU 前先看清是算力不足还是队列策略不合理。

告警阈值示例:等待队列持续增长超过 N 分钟、失败率突增、单卡显存长期顶满。

与 ComfyUI 的边界

Worker 不应把 ComfyUI 当黑盒一直 poll:要设置单次执行超时、并发槽位与显存预估。大 workflow 与小 workflow 可分到不同队列或不同 GPU 池,避免一张超 heavy 的图拖死整批 SKU 任务。ComfyUI 升级前,暂停入队并 drain 现有任务,防止 API 行为变更导致批量失败。

Redis 锁的 TTL 要大于单任务 P99 耗时,但不宜过长;否则坏 Worker 会长时间占坑。我会把「执行中」任务的 progress 写回任务表,前端轮询时能看到当前阶段(排队、渲染、上传),焦虑感会小很多。

业务侧体验

前台用户只需要看到:排队位置、预计等待、失败原因与「重试」按钮。不要在 UI 暴露 ComfyUI 原始栈——把错误映射成「模板缺失」「参数非法」等业务语言。批量导入任务时,接口应异步返回 batchId,而不是 HTTP 挂到 GPU 算完。

检查清单

  • [ ] 任意 taskId 可追踪:入参、Worker、ComfyUI prompt_id、输出 URL
  • [ ] Worker 进程 kill 后,任务可在锁过期后被重新执行
  • [ ] 不可重试错误不会进入死循环
  • [ ] 管理端可暂停入队,便于升级 ComfyUI 或换模型

队列不是「加个 Redis 就行」,而是 GPU 时代的流量整形器。把失败分类、锁续租、观测做扎实,批量出图才能从 demo 变成生产线。

容量规划时,我会先量单任务平均显存占用与耗时,再反推每卡并发与 Worker 数。盲目加 Worker 只会放大 OOM 重试风暴。闲时批量任务可降优先级或改跑低步数预览图,把高峰算力留给临近上架的 SKU。

对象存储 URL 建议带过期时间与签名,Worker 回写后任务表只存 key。否则素材库迁移或权限变更时,历史任务详情页会大面积失效。失败任务保留参数快照,用户一键重试时不应重新填表。

小结

出图队列的目标不是把 GPU 跑满,而是让业务侧对「何时出图、为何失败」有稳定预期。把优先级、心跳续租、失败分类和观测面板一次设计清楚,后续扩容 Worker 才会线性有效。上线前务必用积压演练验证:峰值任务涌入时,系统是排队等待,而不是同步打穿推理服务。