Nodes/Comfyui-zhenzhen/Concurrent Submit | zhenzhen-flux-3-image(文生/图像编辑)
ComfyUI Node

Concurrent Submit | zhenzhen-flux-3-image(文生/图像编辑)

The concurrent submit node for people who don't want to babysit a queue

By T8mars·Created about a year ago·Updated 3 days ago· 755
Concurrent Submit | zhenzhen-flux-3-image(文生/图像编辑)
  • api_config
  • image1
  • image2
  • image3
  • image4
  • image5
  • image6
  • image7
  • image8
  • image9
  • image10
  • task
◄prompt►
◄resolution1k►
◄aspect_ratioauto►
◄groundingtrue►
◄safety_tolerance2►
◄skip_errorfalse►
◄seed0►

If you've run API nodes for a while you know the rhythm: hit Queue, wait 40 seconds, look at one image, tweak the prompt, hit Queue again. That's fine for one image. It's miserable when you want twelve variants, or a folder of product shots re-lit, or the same character across five looks.

This node exists to break the rhythm. It is the FLUX 3 Image node's identical twin - same widget list, same ten reference slots - except instead of returning an image it returns a task, fires the job into a shared pool of 30 workers, and hands you the handle immediately so ComfyUI can go submit the next one. Thirty clauses, one wait.

Be precise about what that is: 30 concurrent HTTP requests against a relay. It doesn't parallelize GPU work, because there is no GPU work - FLUX 3 Image is an early-access API model with no downloadable weights, so the limit is the relay and whatever BFL gives it, not your VRAM.

How the plumbing works

The pack builds these nodes automatically at import. It walks its own node registry, finds every node whose primary output is an IMAGE or a VIDEO, and mints a sibling class for it - deep-copying the original's INPUT_TYPES and VALIDATE_INPUTS, changing only the return type (COMFLY_IMAGE_FUTURE) and the function. The original node is never modified or replaced, which is why you can keep a serial node and a concurrent node in the same graph.

Behind it is a module-level thread pool shared across the whole pack: 30 image workers, 10 video workers, plus a bounded queue of pending jobs, all overridable from the environment before ComfyUI starts:

COMFLY_IMAGE_CONCURRENCY=30   # image workers
COMFLY_IMAGE_PENDING=30       # extra jobs allowed to wait
COMFLY_VIDEO_CONCURRENCY=10
COMFLY_VIDEO_PENDING=10

The pool is chosen by the node's output type, not by a setting - an image node draws from the 30-wide pool, a video node from the 10-wide one.

Wiring it: the part everyone gets wrong

A task is not an IMAGE. Wire this node straight into Save Image and you'll get a type error, because COMFLY_IMAGE_FUTURE has nowhere to go. You need the collector - Concurrent Collect Images (30) - which takes task_1 through task_30 (only task_1 is required; the rest are optional) and returns image_1 … image_30 plus a status string.

The collector is what waits, and it's the reason the chain runs at all: the submit nodes aren't output nodes, and the collector is, so ComfyUI executes everything upstream of it. Give it 2 tasks or 30; unconnected slots come back as not_connected and are skipped. Results are reordered by slot, so task_7 always lands on image_7 regardless of which job finished first - which is the whole reason to fan out this way instead of eyeballing a website's async task list.

failure_mode has two settings and the choice matters:

  • fail_fast (the default) - first failure raises and cancels the still-queued jobs. Use it when you're debugging or when a partial batch is useless.
  • placeholder - a failed slot gets a red 64×64 placeholder image and the batch completes. Use it for unattended runs; the status output is a JSON report telling you exactly which slots failed and why, with API keys and URLs stripped out of the error text.

The shipped example workflow (flux-3-image-concurrent-lowprice.json) is the minimal shape: settings node, two submits with different prompts, one collector, two Save Images.

Using the FLUX 3 node's inputs from here

The widget list is identical to the serial node's, because it's the same INPUT_TYPES - prompt, resolution, aspect_ratio, grounding, safety_tolerance, image1 … image10, skip_error, seed. Nothing to relearn, and the seed still only decides whether ComfyUI re-runs the node (a cache seed, never sent upstream), so thirty nodes hold thirty independent seeds and fixed keeps a re-queue cheap. The output list is the real change: no image / image_url / task_id / response here, just task.

Installing it

It arrives with the pack, so there's nothing separate to do:

cd ComfyUI/custom_nodes
git clone https://github.com/T8mars/Comfyui-zhenzhen
# restart ComfyUI, then search "Concurrent" in the node menu

Both node names show up under zhenzhen/…​/Concurrent Submit and zhenzhen/Concurrent Collect. Key setup is unchanged - Zhenzhen API Settings wired into each submit node's api_config.

Where people get burned

The queue looks frozen because it is. Once 30 jobs are running and 30 more are waiting, the pool's capacity gate blocks, and job 61 parks the ComfyUI execution thread while it waits. Cancel interrupts it cleanly; nothing else will. Drop COMFLY_IMAGE_CONCURRENCY if you're collecting relay-side 429s anyway - thirty simultaneous jobs on a reseller endpoint is a good way to earn them.

fail_fast on a 30-wide batch is a gamble. One flaky job kills the other 29. If any part of the batch is likely to be refused or rate-limited, use placeholder.

skip_error is on both layers now. The submit node's own skip_error returns a white 512×512 image as a success, and the collector reports it green. If you switch it on, read the status JSON instead of trusting the tick.

Reusing a graph while it's still running. Every submit node with a fixed seed and unchanged inputs caches, so re-queuing is usually cheap - but a randomize seed or a changed prompt is a new paid job, every time, thirty at once.

Categoryzhenzhen/Seedance2 Low Price/Concurrent Submit

Inputs (18)

NameTypeDefaultDescription
promptSTRING—
resolutionCOMBO1k5 options: 768sq, 1k, 1.5k, 2k, 4k
aspect_ratioCOMBOauto16 options: auto, 1:1, 16:9, 9:16, 21:9, 9:21, +10
groundingBOOLEANtrue—
safety_toleranceINT20–4—
api_configoptZHENZHEN_SEEDANCE2_CONFIG—
image1optIMAGE—
image2optIMAGE—
image3optIMAGE—
image4optIMAGE—
image5optIMAGE—
image6optIMAGE—
image7optIMAGE—
image8optIMAGE—
image9optIMAGE—
image10optIMAGE—
skip_erroroptBOOLEANfalse—
seedoptINT00–18446744073709550000ComfyUI cache seed only; not sent to the API.

Outputs (1)

NameTypeDescription
taskCOMFLY_IMAGE_FUTURE—