Skip to content

Commit 54d13ef

Browse files
committed
add update function into experiment finally logic
1 parent a49bf5b commit 54d13ef

2 files changed

Lines changed: 450 additions & 0 deletions

File tree

client/api/endpoints.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,84 @@ async def get_experiment_stats_optimized(experiment_id: str, db) -> Dict:
316316
}
317317

318318

319+
async def check_and_update_group_status(experiment_id: str, db):
320+
"""Проверяет и обновляет статус группы экспериментов после завершения эксперимента.
321+
322+
Находит все группы, содержащие завершившийся эксперимент, и проверяет,
323+
завершились ли все эксперименты в группе. Если да, обновляет статус группы на COMPLETED.
324+
"""
325+
try:
326+
# Находим все группы, содержащие этот эксперимент
327+
# В MongoDB запрос {"experiment_ids": value} находит документы, где value содержится в массиве
328+
groups = await db.groups.find({
329+
"experiment_ids": experiment_id,
330+
"state": ExperimentState.RUNNING # Проверяем только запущенные группы
331+
}).to_list(None)
332+
333+
if not groups:
334+
logger.debug(f"No running groups found for experiment {experiment_id}")
335+
return
336+
337+
logger.info(f"Found {len(groups)} running group(s) containing experiment {experiment_id}")
338+
339+
for group in groups:
340+
group_id = str(group["_id"])
341+
experiment_ids = group.get("experiment_ids", [])
342+
343+
if not experiment_ids:
344+
logger.warning(f"Group {group_id} has no experiment_ids")
345+
continue
346+
347+
logger.debug(f"Checking group {group_id} with {len(experiment_ids)} experiments")
348+
349+
# Проверяем статусы всех экспериментов в группе
350+
all_finished = True
351+
352+
for exp_id in experiment_ids:
353+
try:
354+
if not ObjectId.is_valid(exp_id):
355+
logger.warning(f"Invalid experiment ID format in group {group_id}: {exp_id}")
356+
all_finished = False
357+
break
358+
359+
experiment = await db.experiments.find_one({"_id": ObjectId(exp_id)})
360+
if not experiment:
361+
logger.warning(f"Experiment {exp_id} not found in database for group {group_id}")
362+
all_finished = False
363+
break
364+
365+
exp_state = experiment.get("state")
366+
367+
# Если хотя бы один эксперимент еще выполняется или приостановлен, группа не завершена
368+
if exp_state in [ExperimentState.RUNNING, ExperimentState.PENDING, ExperimentState.PAUSED]:
369+
all_finished = False
370+
logger.debug(f"Group {group_id} not finished: experiment {exp_id} is {exp_state}")
371+
break
372+
373+
except Exception as exp_error:
374+
logger.error(f"Error checking experiment {exp_id} in group {group_id}: {str(exp_error)}")
375+
all_finished = False
376+
break
377+
378+
# Если все эксперименты завершены (completed или failed), обновляем статус группы
379+
if all_finished:
380+
try:
381+
await with_retry(
382+
db.groups.update_one,
383+
{"_id": ObjectId(group_id)},
384+
{"$set": {"state": ExperimentState.COMPLETED, "updated_at": datetime.now()}}
385+
)
386+
logger.info(f"Group {group_id} status updated to COMPLETED - all experiments finished")
387+
except Exception as update_error:
388+
logger.error(f"Failed to update group {group_id} status: {str(update_error)}")
389+
else:
390+
logger.debug(f"Group {group_id} not yet completed - some experiments still running")
391+
392+
except Exception as e:
393+
logger.error(f"Error checking group status for experiment {experiment_id}: {str(e)}", exc_info=True)
394+
# Не прерываем выполнение, если проверка группы не удалась
395+
396+
319397
async def run_experiment(experiment_id: str):
320398
"""Фоновая задача для выполнения эксперимента с динамической нагрузкой."""
321399
if experiment_id in active_experiments:
@@ -325,6 +403,7 @@ async def run_experiment(experiment_id: str):
325403
active_experiments.add(experiment_id)
326404
semaphore = asyncio.Semaphore(MAX_CONCURRENT_TASKS)
327405
save_semaphore = asyncio.Semaphore(1) # Семафор для сохранения результатов
406+
db = None # Инициализируем для доступа в finally блоке
328407

329408
try:
330409
db = await get_database()
@@ -510,6 +589,15 @@ async def run_experiment(experiment_id: str):
510589
except Exception as update_error:
511590
logger.error(f"Failed to update experiment state: {str(update_error)}")
512591
finally:
592+
# Проверяем и обновляем статус группы экспериментов после завершения эксперимента
593+
# Это выполнится независимо от того, как завершился эксперимент (успешно, с ошибкой или отменен)
594+
if db is not None:
595+
try:
596+
await check_and_update_group_status(experiment_id, db)
597+
except Exception as group_check_error:
598+
# Логируем ошибку, но не прерываем выполнение
599+
logger.error(f"Failed to check group status in finally block: {str(group_check_error)}")
600+
513601
active_experiments.remove(experiment_id)
514602

515603

0 commit comments

Comments
 (0)