# Стадии выполнения операции (stages) Как через API и код Autotest определить, на каком этапе исполнения находится команда (операция). ## Связь с реальным кодом | Компонент | Файл | Роль | |-----------|------|------| | Запуск операции | `app-autotest/site/operations/executor.py` → `execute_operation()` | Создаёт операцию и возвращает `op_uid` | | Поллинг (async / sync) | `app-autotest/site/operations/poll.py` → `poll_until_done()` | Периодически спрашивает статус и отдаёт `stages` | | Фоновый поллинг + кэш | `app-autotest/site/routes/api_test.py` → `_finish_op()`, `_op_results` | Ждёт `dtFinish`, кладёт `stages` в кэш | | Отдача в UI | `app-autotest/site/routes/api_test.py` → `api_test_status()` | `GET /api/test/status/` → `stages` | | Вывод этапов (ручной режим) | `app-autotest/site/static/js/operations.js` → `showStages()` | Поллинг каждые 2 сек + отрисовка | | Вывод этапов (история) | `app-autotest/site/static/js/history.js` → `renderStages()` | Раскрытие строки истории по клику | ## Эндпоинты ### 1. Запуск операции (получаем `opUid`) ``` POST /api/test ``` `execute_operation()` проходит этапы запуска: 1. **CREATE**: `POST /instances` → `instanceUid` 2. CREATE + NON-CREATE: `POST /instanceOperations` → `opUid` 3. Параметры: `send_params_terraform(...)` 4. `POST /instanceOperations/{opUid}/run` → запуск Возвращает `{ok, error, failed_step, instance_uid, op_uid, display_name}`. При `ok=False` смотри `failed_step`: `instances` / `instanceOperations` / `params` / `run`. ### 2. Поллинг статуса (определяем этап) ``` GET /api/test/status/ ``` Ответ — dict, ключи: - `status` — `"RUNNING"` / `"OK"` / `"FAIL"` - `done` — bool, завершена ли операция - `stages` — список этапов - `isInProgress`, `isSuccessful`, `duration`, `errorLog`, `displayName` Сервер сам дергает Nubes API: ``` GET /instanceOperations/{opUid}?fields=dtFinish,isSuccessful,errorLog,isInProgress,duration,stages ``` ### 3. Фоновый поллинг (для сценариев/сохранения) `poll_until_done()` поллит тот же эндпоинт и возвращает: ```python {status, is_successful, error_log, stages, duration, svc} ``` где `status ∈ {"OK", "FAIL", "TIMEOUT"}`. ## Как определить текущий этап Поле `stages` — массив объектов-стадий. Каждая стадия: | Поле | Тип | Описание | |------|-----|---------| | `instanceOperationStageUid` | UUID | UID стадии | | `stage` | string | Название (напр. `"1. Валидация"`) | | `isSuccessful` | bool/null | `true`/`false`/`null` (ещё не завершена) | | `dtStart` | datetime | Начало этапа | | `dtFinish` | datetime/null | Окончание (`null` — ещё идёт) | | `duration` | float | Секунды (пересчитывается, пока идёт) | | `stageMsg` | JSON-string/null | Детальные логи этапа | **Правило определения текущего этапа:** - `dtFinish == null` (или `isSuccessful == null`) → этап **сейчас выполняется** — это текущий этап команды. - `dtFinish != null` → этап завершён (`isSuccessful == true` → ✅, `false` → ❌). - Идёшь по массиву по порядку: до первого `dtFinish == null` — уже прошли, первый с `null` — текущий, дальше — ещё не начались. **Завершение операции:** смотри `done` / `isInProgress`. Когда `done == true` — `status` принимает `OK`/`FAIL`. При `FAIL` текст ошибки в `errorLog` / `error_log`. ## Пример ответа ```json { "status": "RUNNING", "done": false, "stages": [ { "stage": "1. Валидация", "isSuccessful": true, "dtFinish": "2026-07-24T15:22:01.804+0300", "duration": 4.4 }, { "stage": "2. Основной процесс", "isSuccessful": null, "dtFinish": null, "duration": 14.1 }, { "stage": "3. Проверки", "isSuccessful": null, "dtFinish": null } ] } ``` Здесь: этап 1 завершён ✅, этап 2 — **текущий** (идёт), этап 3 — ещё не начался. ## Вывод этапов в UI ### Ручной режим (`operations.js` → `showStages()`) - Поллинг: `setInterval` каждые **2 секунды** → `GET /api/test/status/{opUid}` - `showStages(sd.stages)` рендерит этапы в последний `.stages-box`: - иконка: `✅` (завершён успешно) / `❌` (завершён с ошибкой) / `⏳` (идёт) - название `stage` + длительность `duration` - `stopPoll()` после завершения; при 5 ошибках подряд поллинга → `TIMEOUT` ### История (`history.js` → `renderStages()`) - `GET /api/history` → записи, у каждой поле `stages` - по клику на строку раскрываются этапы (`stages` сохранены в БД `runs`, колонка `stages JSONB`) ## Примечание `stageMsg` содержит **JSON-строку** с массивом `[[заголовок, текст], ...]` — можно распарсить и показать детальные логи этапа.