v1.1.50: scenario_definitions DB+CRUD, seed, runner from DB, 409 lock, UI definitions, drop config.yaml scenarios

This commit is contained in:
2026-07-30 15:06:05 +04:00
parent 67f6390509
commit 983b387708
8 changed files with 418 additions and 161 deletions
+60
View File
@@ -17,6 +17,7 @@
"""
import os
import json
from db.pool import get_conn, put_conn
SCHEMA_SQL = """
@@ -80,9 +81,65 @@ CREATE TABLE IF NOT EXISTS scenario_runs (
CREATE INDEX IF NOT EXISTS idx_scenario_runs_client_stand
ON scenario_runs (client_id, stand, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_scenario_runs_status
ON scenario_runs (client_id, stand, status);
ALTER TABLE scenario_runs ADD COLUMN IF NOT EXISTS definition_id INTEGER;
ALTER TABLE scenario_runs ADD COLUMN IF NOT EXISTS definition_version INTEGER;
-- Таблица определений сценариев — редактируются без редеплоя
CREATE TABLE IF NOT EXISTS scenario_definitions (
id SERIAL PRIMARY KEY,
client_id VARCHAR(64) NOT NULL,
stand VARCHAR(16) NOT NULL,
name VARCHAR(200) NOT NULL,
steps JSONB NOT NULL DEFAULT '[]',
version INTEGER NOT NULL DEFAULT 1,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_by VARCHAR(128)
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_scenario_defs_unique
ON scenario_definitions (client_id, stand, LOWER(name));
CREATE INDEX IF NOT EXISTS idx_scenario_defs_active
ON scenario_definitions (client_id, stand, is_active);
"""
def _seed_scenarios():
"""Импорт дефолтных сценариев из scenario_seed.yaml при первом старте."""
try:
import yaml, os
path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "scenario_seed.yaml")
if not os.path.exists(path):
return
with open(path) as f:
data = yaml.safe_load(f) or {}
seed_list = data.get("scenarios", [])
if not seed_list:
return
conn = get_conn()
if not conn:
return
cur = conn.cursor()
for s in seed_list:
cur.execute("""
INSERT INTO scenario_definitions (client_id, stand, name, steps)
VALUES (%s, %s, %s, %s)
ON CONFLICT (client_id, stand, LOWER(name)) DO NOTHING
""", (s.get("client_id", ""), s.get("stand", ""), s["name"], json.dumps(s.get("steps", []))))
conn.commit()
cur.close()
put_conn(conn)
print("[DB] Seed scenarios OK", flush=True)
except Exception as e:
print(f"[DB] Seed scenarios error: {e}", flush=True)
def init_db():
"""Применить схему + миграции — идемпотентно, безопасно для конкурентного вызова."""
if not os.getenv("DB_USER"):
@@ -107,3 +164,6 @@ def init_db():
conn.rollback()
finally:
put_conn(conn)
# Seed сценариев — только при первом старте (INSERT ON CONFLICT DO NOTHING)
_seed_scenarios()