Fix R2 configuration v3 class cloning
This commit is contained in:
@@ -99,7 +99,7 @@ New workflows declare every available remote capacity pool explicitly:
|
||||
3. Optionally add an **R2 Storage Configuration** node to provide shared object storage to Vast.ai and SSH targets.
|
||||
4. Connect every capacity and storage node's `REMOTE_CONFIGURATION` output to the configurator's growing input group.
|
||||
|
||||
The connected graph is authoritative. Connecting only Modal configurations produces a Modal-only plan; connecting several providers lets the planner choose among all of them. Each capacity configuration has its own name and limit, so one workflow can offer several Modal GPU types, several independent Vast marketplace searches, and several SSH hosts at the same time. Storage configurations are sibling values in the same configurator but never become scheduler targets or contribute capacity.
|
||||
The connected graph is authoritative. Connecting only Modal configurations produces a Modal-only plan; connecting several providers lets the planner choose among all of them. Each capacity configuration has its own name and limit, so one workflow can offer several Modal GPU types, several independent Vast marketplace searches, and several SSH hosts at the same time. Storage configurations are sibling values in the same configurator but never become scheduler targets or contribute capacity. All configuration nodes are concrete ComfyUI v3 data nodes, so the branch remains valid when ComfyUI executes it after queue-time planning.
|
||||
|
||||
Capacity limits are concurrency ceilings, not eager provisioning requests. Modal containers scale as work needs them, Vast instances are quoted during planning and rented only for selected slots, and SSH worker containers are prepared lazily on the declared host. Sequential components can reuse one slot; parallel components consume distinct slots or wait when that is cheaper than another environment.
|
||||
|
||||
|
||||
@@ -514,6 +514,7 @@
|
||||
- Treat the disconnected Vast configuration node as a local v3 output sink. This preserves it in the queued prompt without wiring it into user data flow, and it must remain in the local-only class set during automatic placement.
|
||||
- The durable execution-plan payload already carries safe metadata for both capacity and storage configurations. Configurator UI should split those concepts at render time: capacity configurations belong in assignment and readiness rows, while storage configurations belong in a distinct summary beneath the plan. That preserves the provider-neutral payload, avoids portraying storage as schedulable capacity, and lets provider-specific cards expose useful policy such as an R2 bucket, jurisdiction, write-back mode, and key prefix without surfacing credential references.
|
||||
- R2's account-level REST metrics do not provide a per-bucket total, while its bucket analytics use a separate Cloudflare API authorization surface. A controller that retains only bucket-scoped S3 credentials can still compute exact current bucket payload bytes and object count through paginated `ListObjectsV2`; cache that aggregate briefly so the Configurator can show useful usage without enumerating the bucket on every workflow submission.
|
||||
- ComfyUI's v3 execution path shallow-clones a node class and then rebuilds it with a metaclass that rejects class mutation. Adding Python's `ABC` to an intermediate v3 node base changes that clone to `ABCMeta`, whose construction writes `__abstractmethods__` and collides with ComfyUI's lock. Extension-owned v3 node bases must stay concrete (using an explicit `NotImplementedError` for provider hooks) unless ComfyUI's class-lock implementation becomes ABC-aware.
|
||||
- Revalidate every offer response locally even when the marketplace query contains identical hard filters. Rank compatible offers deterministically by total hourly price, then reliability, DLPerf, download rate, and offer ID.
|
||||
- Keep idle retention separate from minimum offer duration. Retention is a billed lease-lifecycle decision; offer duration only describes how long the marketplace host claims it will remain available.
|
||||
- The offline Vast simulator should exercise offer disappearance between search and rent, loading-to-running polling, state changes, and destruction while never recording authorization or per-instance API keys.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
@@ -63,13 +62,13 @@ RemoteConfigurationType = io.Custom(REMOTE_CONFIGURATION_IO_TYPE)
|
||||
RemoteConfigurationSetType = io.Custom(REMOTE_CONFIGURATION_SET_IO_TYPE)
|
||||
|
||||
|
||||
class StorageBackingConfigurationNode(io.ComfyNode, ABC):
|
||||
class StorageBackingConfigurationNode(io.ComfyNode):
|
||||
"""Base ComfyUI node for workflow-scoped shared storage configuration."""
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
"""Expose one concrete storage provider's non-secret settings."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class R2StorageConfiguration(StorageBackingConfigurationNode):
|
||||
|
||||
@@ -46,6 +46,33 @@ def test_configuration_nodes_expose_typed_outputs_and_autogrow_sink(
|
||||
)
|
||||
|
||||
|
||||
def test_r2_configuration_executes_through_locked_v3_clone(
|
||||
remote_configuration_nodes_module: Any,
|
||||
) -> None:
|
||||
"""R2's concrete v3 node must survive ComfyUI's execution-time class lock."""
|
||||
from comfy_api.internal import make_locked_method_func
|
||||
|
||||
module = remote_configuration_nodes_module
|
||||
node_class = module.R2StorageConfiguration
|
||||
class_clone = node_class.PREPARE_CLASS_CLONE(None)
|
||||
execute = make_locked_method_func(node_class, "execute", class_clone)
|
||||
|
||||
output = execute(
|
||||
configuration_name="shared-r2",
|
||||
account_id="a" * 32,
|
||||
bucket="comfy-models",
|
||||
credential_id="opaque-reference",
|
||||
jurisdiction="eu",
|
||||
write_back_mode="async",
|
||||
key_prefix="comfy-modal-cache/v1/blobs/sha256",
|
||||
)
|
||||
|
||||
assert output.result is not None
|
||||
configuration = output.result[0]
|
||||
assert configuration.configuration_id == "r2-storage"
|
||||
assert configuration.bucket == "comfy-models"
|
||||
|
||||
|
||||
def test_compiler_collects_r2_storage_without_treating_it_as_capacity(
|
||||
remote_configuration_nodes_module: Any,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user