POST /v2/models/{provider}/{model} 会一直保持连接,直到模型完成。队列投递使用相同的模型 ID 和相同的原生请求体,但一旦 Router 接纳了本次运行就会立即返回。你会立刻拿到一个 request_id,并在结果就绪时获取它,可以在同一进程中,也可以在另一个进程中。
同步路由有 10 分钟的上限。 这个上限正是本页存在的原因:Router 的默认截止时间为 10 分钟(可按部署配置),同步调用一旦达到该时限就会被切断,返回 504 / deadline_exceeded,不论提供商是否仍在工作。如果一次生成的运行时间可能超过这个上限,或者调用方无法将连接保持打开十分钟,就必须使用队列。关于截止时间会告诉你什么、不会告诉你关于计费的什么,请参阅调用会在服务器截止时间被切断。
在以下情况使用队列:一次生成可能超出你能保持的连接时长;Web 请求必须立即返回;你在一个进程中提交、在另一个进程中收集结果;或者你希望同时进行多次生成。排序、接纳、重试、超时、计费和过期都由服务器决定。SDK 只是在其上增加了轮询和易用性封装,别无其他。
两种交付模式,一个请求
SDK(
comfy-sdk 和 @comfyorg/sdk,0.3.0 或更高版本)在 run 旁边通过三个方法暴露队列:
submit(model, body)发送请求并立即返回一个句柄。该句柄带有status()、get()、cancel()以及一个事件迭代器(Python 中为iter_events(),TypeScript 中为events())。subscribe(model, body, ...)通过一次调用完成提交、轮询和收集,并带有进度回调。handle(model, request_id)根据这两个 ID 在另一个进程中重建句柄,而无需发起任何调用。
/v2/models/{provider}/{model}/requests/{request_id}。
这里的
events() 不是 Comfy Cloud 客户端的 job.events()。这里的是轮询状态路由,并为 Router 请求产生队列观测结果(状态和队列位置)。Comfy Cloud 的那个则是 ComfyUI 工作流任务的实时 SSE 流,携带进度、预览和输出。subscribe() 又是另一种东西:它根本不是迭代器,而是把提交、轮询和收集合并到一次调用中。请参阅 events() 不是 subscribe()。四种路由
status 是 IN_QUEUE、IN_PROGRESS 或 COMPLETED 之一。不存在单独的失败或已取消状态:未成功的请求会处于 COMPLETED 并携带 error_type,因此请根据该字段是否存在来分支处理,而不是依据第四个状态值。SDK 已经替你处理好了这一点:get() 会抛出或以类型化的 Router 错误拒绝,而不是把失败作为结果返回。
没有进度事件、webhook 或优先级等级:跟踪请求的方式就是状态路由。API 参考 包含每个路由的完整约定。
将请求加入队列
这会将快速开始 所发送的同一请求加入队列,并收集生成的图像。请先将你的密钥导出为COMFY_API_KEY。
一次调用中跟踪进度并收集结果
当你确实想要等待、同时也想展示进度时,subscribe 会将提交、轮询和收集合并为一次调用:
subscribe 会在抛出之前尽力执行一次取消。取消只对尚未开始运行的请求生效:已经在合作方那里进行中的一次生成会照常完成并计费,无论是否有人收集它。当请求的生命周期需要长于调用者时,请使用 submit。
从另一个进程收集结果
请把request_id 与模型 ID 一起保存。重建句柄需要这两者,而在你使用它之前不会发起任何调用。
检查状态或取消
status() 只进行一次轮询并返回当前状态。cancel() 请求服务器停止一个尚未完成的请求。这是一次请求,而不是保证:已经在合作方那里发出的运行可能依然会完成,而随后一次 status() 才是真实情况。
异步 Python
AsyncComfy 对应了每一个名称、参数和参数顺序。没有 submit_async,原因与没有 run_async 相同。
SDK 抛出的错误
已完成但未成功的请求会以COMPLETED 并携带 error_type 的形式上报。get() 和 subscribe() 会把它转换为该类别的类型化 Router 错误:Python 中是 comfy_sdk.router_exceptions 里的类,TypeScript 中是 routerErrors.*。事件迭代器在该情况下不会抛出,因为它只是队列进度的视图:携带 error_type 的完成会作为最后一次观测产出,而由 get() 负责收集。提交时的 403 not_enabled 会以 NotEnabled 到达,并且是终止性的,因此 SDK 不会重试它。
响应是什么样的
提交,201。 此时 status 始终为 IN_QUEUE。这三个 URL 都是绝对地址,并使用与提交时相同的密钥进行身份验证。
request_id 同时也是提交请求的 X-Comfy-Request-Id 头部的值。请把模型 ID 和它一起记下来:请求需要靠这两者来寻址。
状态查询,200。 结构相同,只是展示当前状态。queue_position 统计排在你前面的请求数量,当本次运行位于队首时该值为 0。此响应中的 Retry-After 是 Router 对何时再次轮询才值得往返一次的估计。它只是一个提示,并非硬性限制,而且排在队尾的请求被告知要等待的时间会比已经在运行的请求更长。轮询得更快并不会让你更早获知任何信息,反而会消耗你自己的速率限制额度。
COMPLETED,并带有 error_type,其携带的粗分类与结果读取在 X-Comfy-Error-Type 中标出的一致。该字段在成功时是缺失的,而不是 null。
200 携带模型自身的原生输出,与同步路由针对相同模型和输入返回的内容逐字节一致,并使用提供商自己的 Content-Type。当请求尚未完成时,该读取会返回 202 以及上面的状态响应体,因此只轮询结果 URL 的客户端只需解析一种类型。失败的请求会以设置了 X-Comfy-Error-Type 的错误响应返回,分类与同步路由相同。
取消。 返回 202 和 CANCELLATION_REQUESTED 表示取消请求已被接受,并不代表运行已经停止。已经在合作伙伴侧开始执行的运行仍可能照常完成,而合作伙伴完成的生成无论是否有人取回,都会被计费。之后请读取状态:已生效的取消会显示为 COMPLETED 并带有 error_type: cancelled。在能够运行之前就已超时的请求,会以相同方式显示 queue_timeout。已经完成的请求会返回 409 和 ALREADY_COMPLETED。
幂等性与计费
- 与同步路由收费相同。 费用在提供商向 Comfy 计费时产生。在队列中等待的时间不计费。
- 每次提交使用一个
Idempotency-Key。 SDK 会为每次submit调用生成一个新的键,因此对同一输入的两次有意提交就是两个请求。在同一个键下重试同一个调用不会再次排队运行:它会返回原始句柄,并带有Idempotent-Replayed: true。当响应丢失可能让你损失request_id时,请传入你自己的键。参见 Headers。 - 结果会过期。 已完成的请求在完成后会保留 24 小时。之后,状态和结果读取会返回
410,结果也就消失了。请及时收集,并下载输出中包含的任何资产 URL。 - 轮询也是请求。 状态和结果读取会计入每个调用者的请求速率。请遵守
Retry-After,而不是以固定的短间隔进行轮询。
错误
每个错误响应都带有
X-Comfy-Request-Id。联系支持时请提供该 ID。
下一步
快速开始
同一模型的同步调用,从无到有生成图像。
模型
每个模型页面都包含针对其自身模型和请求体的队列代码片段。
请求头
认证、幂等性、请求 ID、错误分桶、重试节奏。
API 参考
四个队列路由,逐字段说明。