3.6 KiB
3.6 KiB
Learnings
2026-04-17
- The workflow metadata already rides along in
extra_data.extra_pnginfo.workflow, so the backend can discovernode.properties.is_modal_remotewithout any extra frontend metadata channel. - A single wildcard-output proxy node is not enough for server-side graph rewriting. ComfyUI validates downstream link indices and output arity against the replacement class, so the backend has to generate proxy node classes that mirror the original node’s output signature before validation runs.
- Keeping the sync engine content-addressable makes prompt rewrites cheap after the first upload. The route can block on sync safely as long as repeated requests collapse to a hash marker check.
- Hashing and zipping the entire
custom_nodes/tree inside the queue route is too expensive forCOMFY_MODAL_EXECUTION_MODE=local. Local mode should skip custom-node bundle sync by default, with an explicit override when that path needs to be exercised. - When rewriting a prompt node into a proxy, never reuse the same input dict for both
prompt_node["inputs"]andoriginal_node_data["inputs"]. Insertingoriginal_node_databack into the live prompt inputs creates a recursive structure that breaks ComfyUI cache signature hashing with aRecursionError. - Queue-time validation is necessary for remote nodes that still receive local Comfy runtime objects. Even if a node is marked remote, inputs like
MODELorCONDITIONINGcannot be serialized across the current boundary, so the prompt should be rejected before execution rather than failing inside the serializer. - Per-node proxying is not enough for real ComfyUI sampler graphs. Connected remote-marked nodes must be partitioned into a single remote component so internal edges like
MODEL,CLIP, andCONDITIONINGstay inside the remote subgraph and only the true local/remote boundary has to be transport-safe. - The local fallback runtime cannot call
PromptExecutor.execute()inline from inside a proxy node, because ComfyUI is already running inside an active asyncio loop. Running remote subgraph execution in a worker thread avoids nested-event-loop failures while still reusing ComfyUI’s executor. - Modal objects defined in-process are not directly callable from an arbitrary long-running app like ComfyUI unless they are inside a hydrated
app.run()session or looked up from a deployed app withmodal.Cls.from_name(...). Remote mode should prefer deployed lookup and only fall back toapp.run()when no deployment is available. - ComfyUI loads custom node packs from directories under synthetic module names derived from filesystem paths, and for directory-based packs that module key is not guaranteed to be a valid Python import path. Modal container startup requires a real importable module name for
@app.clsservices, so the cloud entrypoint has to live in a separate, stable module such ascomfyui_modal_sync_cloud.pyrather than on the custom-node package module itself. - Shipping the ComfyUI source tree into the Modal image is not enough by itself. The container also needs ComfyUI's import-time Python dependencies such as
psutil,aiohttp,einops,torchsde,torchvision, and related runtime packages, or the remote worker fails before it can execute any graph nodes. - The frontend can reuse ComfyUI's native
executing,execution_error, andexecution_successwebsocket events for remote component visuals as long as the queue route also publishes the representative-node-to-original-node mapping after rewrite. That keeps the UI in sync with actual proxy execution instead of inventing a separate polling channel.