Skip to content

Commit 6fb44c4

Browse files
authored
Make adding links/nodes to ExecutionList non-recursive (#4886)
Graphs with 300+ chained nodes run into maximum recursion depth error (limit is 1000 in CPython)
1 parent d2247c1 commit 6fb44c4

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

comfy_execution/graph.py

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -99,30 +99,44 @@ def make_input_strong_link(self, to_node_id, to_input):
9999
self.add_strong_link(from_node_id, from_socket, to_node_id)
100100

101101
def add_strong_link(self, from_node_id, from_socket, to_node_id):
102-
self.add_node(from_node_id)
103-
if to_node_id not in self.blocking[from_node_id]:
104-
self.blocking[from_node_id][to_node_id] = {}
105-
self.blockCount[to_node_id] += 1
106-
self.blocking[from_node_id][to_node_id][from_socket] = True
107-
108-
def add_node(self, unique_id, include_lazy=False, subgraph_nodes=None):
109-
if unique_id in self.pendingNodes:
110-
return
111-
self.pendingNodes[unique_id] = True
112-
self.blockCount[unique_id] = 0
113-
self.blocking[unique_id] = {}
114-
115-
inputs = self.dynprompt.get_node(unique_id)["inputs"]
116-
for input_name in inputs:
117-
value = inputs[input_name]
118-
if is_link(value):
119-
from_node_id, from_socket = value
120-
if subgraph_nodes is not None and from_node_id not in subgraph_nodes:
121-
continue
122-
input_type, input_category, input_info = self.get_input_info(unique_id, input_name)
123-
is_lazy = input_info is not None and "lazy" in input_info and input_info["lazy"]
124-
if include_lazy or not is_lazy:
125-
self.add_strong_link(from_node_id, from_socket, unique_id)
102+
if not self.is_cached(from_node_id):
103+
self.add_node(from_node_id)
104+
if to_node_id not in self.blocking[from_node_id]:
105+
self.blocking[from_node_id][to_node_id] = {}
106+
self.blockCount[to_node_id] += 1
107+
self.blocking[from_node_id][to_node_id][from_socket] = True
108+
109+
def add_node(self, node_unique_id, include_lazy=False, subgraph_nodes=None):
110+
node_ids = [node_unique_id]
111+
links = []
112+
113+
while len(node_ids) > 0:
114+
unique_id = node_ids.pop()
115+
if unique_id in self.pendingNodes:
116+
continue
117+
118+
self.pendingNodes[unique_id] = True
119+
self.blockCount[unique_id] = 0
120+
self.blocking[unique_id] = {}
121+
122+
inputs = self.dynprompt.get_node(unique_id)["inputs"]
123+
for input_name in inputs:
124+
value = inputs[input_name]
125+
if is_link(value):
126+
from_node_id, from_socket = value
127+
if subgraph_nodes is not None and from_node_id not in subgraph_nodes:
128+
continue
129+
input_type, input_category, input_info = self.get_input_info(unique_id, input_name)
130+
is_lazy = input_info is not None and "lazy" in input_info and input_info["lazy"]
131+
if (include_lazy or not is_lazy) and not self.is_cached(from_node_id):
132+
node_ids.append(from_node_id)
133+
links.append((from_node_id, from_socket, unique_id))
134+
135+
for link in links:
136+
self.add_strong_link(*link)
137+
138+
def is_cached(self, node_id):
139+
return False
126140

127141
def get_ready_nodes(self):
128142
return [node_id for node_id in self.pendingNodes if self.blockCount[node_id] == 0]
@@ -146,11 +160,8 @@ def __init__(self, dynprompt, output_cache):
146160
self.output_cache = output_cache
147161
self.staged_node_id = None
148162

149-
def add_strong_link(self, from_node_id, from_socket, to_node_id):
150-
if self.output_cache.get(from_node_id) is not None:
151-
# Nothing to do
152-
return
153-
super().add_strong_link(from_node_id, from_socket, to_node_id)
163+
def is_cached(self, node_id):
164+
return self.output_cache.get(node_id) is not None
154165

155166
def stage_node_execution(self):
156167
assert self.staged_node_id is None

0 commit comments

Comments
 (0)