diff --git a/comfyui_modal_sync_cloud.py b/comfyui_modal_sync_cloud.py index 8739ed1..a1f075c 100644 --- a/comfyui_modal_sync_cloud.py +++ b/comfyui_modal_sync_cloud.py @@ -1348,7 +1348,6 @@ def _remote_engine_cls_options(settings: Any, vol: Any, image: Any) -> dict[str, "volumes": {settings.remote_storage_root: vol}, "scaledown_window": settings.scaledown_window_seconds, "min_containers": settings.min_containers, - "allow_concurrent_inputs": 2, "image": image, "enable_memory_snapshot": settings.enable_memory_snapshot, } @@ -1433,6 +1432,7 @@ if modal is not None: # pragma: no branch - remote entrypoint configuration. ) @app.cls(**_remote_engine_cls_options(settings, vol, image)) + @modal.concurrent(max_inputs=2) class RemoteEngine: """Modal runtime class that executes proxied ComfyUI payloads.""" diff --git a/docs/LEARNINGS.md b/docs/LEARNINGS.md index 376bf13..988327d 100644 --- a/docs/LEARNINGS.md +++ b/docs/LEARNINGS.md @@ -7,7 +7,7 @@ - `comfy node pack` is not git-aware by default; it uses `.gitignore` as its practical packaging filter. For a clean registry artifact, this repo needs an allowlist-style `.gitignore` so untracked local files like logs, caches, virtualenvs, and scratch docs cannot leak into `node.zip`. - Remote per-node phase events are not enough to mirror sampler progress in the local UI. The Modal worker also needs a headless equivalent of ComfyUI's global progress hook so `ProgressBar` updates feed `progress_state`, and the local relay should forward those numeric updates as a separate high-frequency UI event rather than overloading coarse execution-phase messages. - ComfyUI prompt cancellation does not need a separate frontend API hook to reach Modal. The proxy node can watch ComfyUI's existing `processing_interrupted()` flag while it waits on the remote call, send one targeted remote interrupt for the active `(prompt_id, component_id)`, and then re-raise ComfyUI's own `InterruptProcessingException` so the local executor reports a normal `execution_interrupted`. -- On the Modal side, that targeted interrupt cannot share a fully serialized class input lane with the long-running streamed execution. The remote runtime needs at least a small `allow_concurrent_inputs` budget on the deployed class, or the `interrupt_payload` RPC just sits behind `execute_payload_stream` and arrives too late to be useful. +- On the Modal side, that targeted interrupt cannot share a fully serialized class input lane with the long-running streamed execution. The remote runtime needs a small class-level `@modal.concurrent(max_inputs=...)` budget, or the `interrupt_payload` RPC just sits behind `execute_payload_stream` and arrives too late to be useful. Older `allow_concurrent_inputs` class options now hard-fail on current Modal SDKs. - Streaming intermediate remote UI outputs back into local ComfyUI is safest when it reuses ComfyUI's native websocket event shapes. Forwarding remote `executed` payloads and preview-image frames through the local `PromptServer` gives the browser real mid-run previews without pretending those inner remote node values are now available as local graph inputs. - Queue-time remote-boundary fixes should come from the backend's actual rewrite logic, not from parsing error text in the browser. A small dry-run analysis route can reuse the same prompt-id resolution and upstream auto-expansion rules, then return workflow-node paths for the frontend to mark directly from a context-menu action, including nested subgraph nodes. - For ComfyUI node right-click menus, patch `getExtraMenuOptions` at node-definition time in `beforeRegisterNodeDef`, not per-instance in `nodeCreated`. The prototype-level hook matches how working extensions inject menu entries and avoids menu items silently disappearing even when other per-node UI changes still show up. diff --git a/tests/test_modal_executor_node.py b/tests/test_modal_executor_node.py index dc74c4f..7b8c634 100644 --- a/tests/test_modal_executor_node.py +++ b/tests/test_modal_executor_node.py @@ -1207,10 +1207,10 @@ def test_modal_cloud_uses_comfy_prompt_executor_cache_defaults( assert cache_args == {"lru": 0, "ram": 4.0} -def test_modal_cloud_allows_concurrent_inputs_for_interrupts( +def test_modal_cloud_class_options_do_not_use_deprecated_concurrency_flag( modal_cloud_module: Any, ) -> None: - """The deployed Modal class should keep one spare input slot for interrupt RPCs.""" + """The deployed Modal class options should avoid deprecated concurrency flags.""" fake_settings = types.SimpleNamespace( modal_gpu="A100", remote_storage_root="/vol/data", @@ -1226,7 +1226,9 @@ def test_modal_cloud_allows_concurrent_inputs_for_interrupts( image=object(), ) - assert options["allow_concurrent_inputs"] == 2 + assert "allow_concurrent_inputs" not in options + module_source = Path(modal_cloud_module.__file__).read_text(encoding="utf-8") + assert "@modal.concurrent(max_inputs=2)" in module_source def test_modal_cloud_reuses_prompt_executor_for_same_cache_scope(