Skip to content

Commit 5274b91

Browse files
committed
use ws messages to get start and end times
1 parent 1b67306 commit 5274b91

File tree

4 files changed

+45
-43
lines changed

4 files changed

+45
-43
lines changed

comfy_execution/jobs.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,20 @@ def normalize_history_item(prompt_id, history_item, include_outputs=False):
9090
outputs_count, preview_output = get_outputs_summary(outputs)
9191

9292
execution_error = None
93-
if status == JobStatus.FAILED and status_info:
94-
messages = status_info.get('messages', [])
95-
for entry in messages:
96-
if isinstance(entry, (list, tuple)) and len(entry) >= 2 and entry[0] == 'execution_error':
97-
detail = entry[1]
98-
if isinstance(detail, dict):
99-
execution_error = detail
100-
break
101-
102-
execution_duration = history_item.get('execution_duration')
10393
execution_start_time = None
10494
execution_end_time = None
105-
if execution_duration is not None and create_time is not None:
106-
execution_end_time = create_time + int(execution_duration * 1000)
107-
execution_start_time = create_time
95+
if status_info:
96+
messages = status_info.get('messages', [])
97+
for entry in messages:
98+
if isinstance(entry, (list, tuple)) and len(entry) >= 2:
99+
event_name, event_data = entry[0], entry[1]
100+
if isinstance(event_data, dict):
101+
if event_name == 'execution_start':
102+
execution_start_time = event_data.get('timestamp')
103+
elif event_name in ('execution_success', 'execution_error', 'execution_interrupted'):
104+
execution_end_time = event_data.get('timestamp')
105+
if event_name == 'execution_error':
106+
execution_error = event_data
108107

109108
job = {
110109
'id': prompt_id,

execution.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,8 +1136,7 @@ class ExecutionStatus(NamedTuple):
11361136
messages: List[str]
11371137

11381138
def task_done(self, item_id, history_result,
1139-
status: Optional['PromptQueue.ExecutionStatus'], process_item=None,
1140-
execution_duration: Optional[float] = None):
1139+
status: Optional['PromptQueue.ExecutionStatus'], process_item=None):
11411140
with self.mutex:
11421141
prompt = self.currently_running.pop(item_id)
11431142
if len(self.history) > MAXIMUM_HISTORY_SIZE:
@@ -1154,7 +1153,6 @@ def task_done(self, item_id, history_result,
11541153
"prompt": prompt,
11551154
"outputs": {},
11561155
'status': status_dict,
1157-
'execution_duration': execution_duration,
11581156
}
11591157
self.history[prompt[1]].update(history_result)
11601158
self.server.queue_updated()

main.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def prompt_worker(q, server_instance):
230230
need_gc = True
231231

232232
current_time = time.perf_counter()
233-
execution_duration = current_time - execution_start_time
233+
execution_time = current_time - execution_start_time
234234

235235
remove_sensitive = lambda prompt: prompt[:5] + prompt[6:]
236236
q.task_done(item_id,
@@ -239,17 +239,16 @@ def prompt_worker(q, server_instance):
239239
status_str='success' if e.success else 'error',
240240
completed=e.success,
241241
messages=e.status_messages),
242-
process_item=remove_sensitive,
243-
execution_duration=execution_duration)
242+
process_item=remove_sensitive)
244243
if server_instance.client_id is not None:
245244
server_instance.send_sync("executing", {"node": None, "prompt_id": prompt_id}, server_instance.client_id)
246245

247246
# Log Time in a more readable way after 10 minutes
248-
if execution_duration > 600:
249-
execution_duration_str = time.strftime("%H:%M:%S", time.gmtime(execution_duration))
250-
logging.info(f"Prompt executed in {execution_duration_str}")
247+
if execution_time > 600:
248+
execution_time = time.strftime("%H:%M:%S", time.gmtime(execution_time))
249+
logging.info(f"Prompt executed in {execution_time}")
251250
else:
252-
logging.info("Prompt executed in {:.2f} seconds".format(execution_duration))
251+
logging.info("Prompt executed in {:.2f} seconds".format(execution_time))
253252

254253
flags = q.get_flags()
255254
free_memory = flags.get("free_memory", False)

tests/execution/test_jobs.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class TestNormalizeHistoryItem:
269269
"""Unit tests for normalize_history_item()"""
270270

271271
def test_completed_job(self):
272-
"""Completed history item should have correct status."""
272+
"""Completed history item should have correct status and times from messages."""
273273
history_item = {
274274
'prompt': (
275275
5, # priority
@@ -278,54 +278,61 @@ def test_completed_job(self):
278278
{
279279
'create_time': 1234567890000,
280280
'extra_pnginfo': {'workflow': {'id': 'workflow-xyz'}}
281-
}, # milliseconds
281+
},
282282
['node1'],
283283
),
284-
'status': {'status_str': 'success', 'completed': True, 'messages': []},
284+
'status': {
285+
'status_str': 'success',
286+
'completed': True,
287+
'messages': [
288+
('execution_start', {'prompt_id': 'prompt-456', 'timestamp': 1234567890500}),
289+
('execution_success', {'prompt_id': 'prompt-456', 'timestamp': 1234567893000}),
290+
]
291+
},
285292
'outputs': {},
286-
'execution_duration': 2.5,
287293
}
288294
job = normalize_history_item('prompt-456', history_item)
289295

290296
assert job['id'] == 'prompt-456'
291297
assert job['status'] == 'completed'
292298
assert job['priority'] == 5
293-
assert job['execution_start_time'] == 1234567890000
294-
assert job['execution_end_time'] == 1234567890000 + 2500 # +2.5 seconds in ms
299+
assert job['execution_start_time'] == 1234567890500
300+
assert job['execution_end_time'] == 1234567893000
295301
assert job['workflow_id'] == 'workflow-xyz'
296302

297303
def test_failed_job(self):
298-
"""Failed history item should have failed status and message."""
299-
error_detail = {
300-
'node_id': '5',
301-
'node_type': 'KSampler',
302-
'exception_message': 'CUDA out of memory',
303-
'exception_type': 'RuntimeError',
304-
'traceback': ['Traceback...', 'RuntimeError: CUDA out of memory'],
305-
}
304+
"""Failed history item should have failed status and error from messages."""
306305
history_item = {
307306
'prompt': (
308307
5,
309308
'prompt-789',
310309
{'nodes': {}},
311-
{'create_time': 1234567890},
310+
{'create_time': 1234567890000},
312311
['node1'],
313312
),
314313
'status': {
315314
'status_str': 'error',
316315
'completed': False,
317316
'messages': [
318-
('execution_error', error_detail)
317+
('execution_start', {'prompt_id': 'prompt-789', 'timestamp': 1234567890500}),
318+
('execution_error', {
319+
'prompt_id': 'prompt-789',
320+
'node_id': '5',
321+
'node_type': 'KSampler',
322+
'exception_message': 'CUDA out of memory',
323+
'exception_type': 'RuntimeError',
324+
'traceback': ['Traceback...', 'RuntimeError: CUDA out of memory'],
325+
'timestamp': 1234567891000,
326+
})
319327
]
320328
},
321329
'outputs': {},
322-
'execution_duration': 1.0,
323330
}
324331

325-
# List view - includes execution_error
326332
job = normalize_history_item('prompt-789', history_item)
327333
assert job['status'] == 'failed'
328-
assert job['execution_error'] == error_detail
334+
assert job['execution_start_time'] == 1234567890500
335+
assert job['execution_end_time'] == 1234567891000
329336
assert job['execution_error']['node_id'] == '5'
330337
assert job['execution_error']['node_type'] == 'KSampler'
331338
assert job['execution_error']['exception_message'] == 'CUDA out of memory'
@@ -342,7 +349,6 @@ def test_include_outputs(self):
342349
),
343350
'status': {'status_str': 'success', 'completed': True, 'messages': []},
344351
'outputs': {'node1': {'images': [{'filename': 'test.png'}]}},
345-
'execution_duration': 2.5,
346352
}
347353
job = normalize_history_item('prompt-123', history_item, include_outputs=True)
348354

0 commit comments

Comments
 (0)