diff --git a/site/app.py b/site/app.py index 62c245a..9ab2e6d 100644 --- a/site/app.py +++ b/site/app.py @@ -32,7 +32,7 @@ from routes.api_scenario_defs import bp_defs as api_scenario_defs_bp # Версия — показывается в топбаре UI. Меняется при КАЖДОМ изменении кода. # Нужна для фильтрации истории (пользователь видит только записи своей версии). -VERSION = "1.2.36" +VERSION = "1.2.37" # Flask-приложение с Jinja2-шаблонами из папки templates/ app = Flask(__name__, template_folder="templates", static_folder="static") diff --git a/site/db/init_db.py b/site/db/init_db.py index 339c92c..f8e82b9 100644 --- a/site/db/init_db.py +++ b/site/db/init_db.py @@ -84,6 +84,12 @@ ALTER TABLE runs ADD COLUMN IF NOT EXISTS app_version VARCHAR(16); ALTER TABLE runs ADD COLUMN IF NOT EXISTS scenario_run_id INTEGER; ALTER TABLE runs ADD COLUMN IF NOT EXISTS step_number INTEGER; ALTER TABLE runs ADD COLUMN IF NOT EXISTS instance_meta JSONB; + +-- Уникальный индекс на op_uid (частичный — только не-NULL). +-- Нужен для UPSERT: сценарий вызывает save_run дважды (RUNNING → OK), +-- второй вызов обновляет существующую строку вместо INSERT дубликата. +CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_op_uid + ON runs (op_uid) WHERE op_uid IS NOT NULL; """ # ── DDL для scenario_runs (запуски сценариев) ── diff --git a/site/db/save_run.py b/site/db/save_run.py index 5bbe2bb..a350d2c 100644 --- a/site/db/save_run.py +++ b/site/db/save_run.py @@ -57,6 +57,13 @@ def save_run(client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id, status, duration_sec, error_log, params, stages, app_version, scenario_run_id, step_number, instance_meta) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + ON CONFLICT (op_uid) WHERE op_uid IS NOT NULL DO UPDATE SET + status = EXCLUDED.status, + duration_sec = EXCLUDED.duration_sec, + error_log = EXCLUDED.error_log, + stages = EXCLUDED.stages, + svc_name = EXCLUDED.svc_name, + instance_meta = EXCLUDED.instance_meta """, ( client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id, op_uid, instance_uid, display_name, status, duration_sec,