Skip to content

Commit 775ce83

Browse files
committed
use ws messages to get start and end times
1 parent c33c6c8 commit 775ce83

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
@@ -1130,8 +1130,7 @@ class ExecutionStatus(NamedTuple):
11301130
messages: List[str]
11311131

11321132
def task_done(self, item_id, history_result,
1133-
status: Optional['PromptQueue.ExecutionStatus'], process_item=None,
1134-
execution_duration: Optional[float] = None):
1133+
status: Optional['PromptQueue.ExecutionStatus'], process_item=None):
11351134
with self.mutex:
11361135
prompt = self.currently_running.pop(item_id)
11371136
if len(self.history) > MAXIMUM_HISTORY_SIZE:
@@ -1148,7 +1147,6 @@ def task_done(self, item_id, history_result,
11481147
"prompt": prompt,
11491148
"outputs": {},
11501149
'status': status_dict,
1151-
'execution_duration': execution_duration,
11521150
}
11531151
self.history[prompt[1]].update(history_result)
11541152
self.server.queue_updated()

main.py

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

205205
current_time = time.perf_counter()
206-
execution_duration = current_time - execution_start_time
206+
execution_time = current_time - execution_start_time
207207

208208
remove_sensitive = lambda prompt: prompt[:5] + prompt[6:]
209209
q.task_done(item_id,
@@ -212,17 +212,16 @@ def prompt_worker(q, server_instance):
212212
status_str='success' if e.success else 'error',
213213
completed=e.success,
214214
messages=e.status_messages),
215-
process_item=remove_sensitive,
216-
execution_duration=execution_duration)
215+
process_item=remove_sensitive)
217216
if server_instance.client_id is not None:
218217
server_instance.send_sync("executing", {"node": None, "prompt_id": prompt_id}, server_instance.client_id)
219218

220219
# Log Time in a more readable way after 10 minutes
221-
if execution_duration > 600:
222-
execution_duration_str = time.strftime("%H:%M:%S", time.gmtime(execution_duration))
223-
logging.info(f"Prompt executed in {execution_duration_str}")
220+
if execution_time > 600:
221+
execution_time = time.strftime("%H:%M:%S", time.gmtime(execution_time))
222+
logging.info(f"Prompt executed in {execution_time}")
224223
else:
225-
logging.info("Prompt executed in {:.2f} seconds".format(execution_duration))
224+
logging.info("Prompt executed in {:.2f} seconds".format(execution_time))
226225

227226
flags = q.get_flags()
228227
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)