v1.1.48: fix 4 scenario bugs — save_run: scenario_run_id+step_number, run_id before thread (202), TIMEOUT op_data init, RUNNING before API call, GET /run/<id>
This commit is contained in:
@@ -11,7 +11,7 @@ from flask import Blueprint, current_app, jsonify, request
|
||||
import threading
|
||||
|
||||
from api.auth import get_client, get_client_id, get_stand, get_token_info
|
||||
from operations.scenario import load_scenarios, run_scenario
|
||||
from operations.scenario import load_scenarios, run_scenario, _create_scenario_run
|
||||
from db.pool import get_conn, put_conn
|
||||
|
||||
bp = Blueprint("api_scenario", __name__)
|
||||
@@ -30,7 +30,7 @@ def api_scenarios():
|
||||
|
||||
@bp.route("/api/scenario/run", methods=["POST"])
|
||||
def api_scenario_run():
|
||||
"""Запустить сценарий. Возвращает scenario_run_id сразу, выполнение в фоне."""
|
||||
"""Запустить сценарий. Создаёт запись ДО потока, возвращает run_id (202)."""
|
||||
try:
|
||||
data = request.get_json()
|
||||
scenario_name = (data.get("scenario") or "").strip()
|
||||
@@ -38,23 +38,67 @@ def api_scenario_run():
|
||||
return jsonify({"error": "scenario name is required"}), 400
|
||||
|
||||
client = get_client()
|
||||
cid = get_client_id()
|
||||
stand = get_stand()
|
||||
user_email = get_token_info().get("email", "")
|
||||
app_version = current_app.config.get("VERSION", "")
|
||||
|
||||
# Валидация: сценарий существует?
|
||||
scenarios = load_scenarios()
|
||||
if scenario_name not in scenarios:
|
||||
return jsonify({"error": f"Scenario '{scenario_name}' not found"}), 404
|
||||
|
||||
total = len(scenarios[scenario_name].get("steps", []))
|
||||
if total == 0:
|
||||
return jsonify({"error": f"Scenario '{scenario_name}' has no steps"}), 400
|
||||
|
||||
# Создать запись ДО потока — вернуть run_id клиенту
|
||||
run_id = _create_scenario_run(cid, stand, user_email, scenario_name, total, app_version)
|
||||
if run_id is None:
|
||||
return jsonify({"error": "Failed to create scenario_run"}), 500
|
||||
|
||||
# Запуск в фоне
|
||||
threading.Thread(
|
||||
target=run_scenario,
|
||||
args=(client, scenario_name, get_client_id(), get_stand(), user_email, app_version),
|
||||
args=(client, scenario_name, cid, stand, user_email, app_version, run_id),
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
return jsonify({"status": "RUNNING", "scenario": scenario_name})
|
||||
return jsonify({"status": "RUNNING", "scenario": scenario_name, "run_id": run_id}), 202
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"[SCENARIO API] run error: {traceback.format_exc()}", flush=True)
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@bp.route("/api/scenario/run/<int:run_id>")
|
||||
def api_scenario_run_status(run_id):
|
||||
"""Статус конкретного запуска сценария."""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return jsonify({"error": "no db"}), 500
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT id, created_at, scenario_name, status, current_step, total_steps,
|
||||
duration_sec, error_log
|
||||
FROM scenario_runs
|
||||
WHERE id = %s AND client_id = %s AND stand = %s
|
||||
""", (run_id, get_client_id(), get_stand()))
|
||||
row = cur.fetchone()
|
||||
if not row:
|
||||
return jsonify({"error": "not found"}), 404
|
||||
cols = [d[0] for d in cur.description]
|
||||
d = dict(zip(cols, row))
|
||||
if d["created_at"]:
|
||||
d["created_at"] = d["created_at"].isoformat()
|
||||
return jsonify(d)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
finally:
|
||||
put_conn(conn)
|
||||
|
||||
|
||||
@bp.route("/api/scenario/status")
|
||||
def api_scenario_status():
|
||||
"""Последний запущенный сценарий (или несколько последних)."""
|
||||
|
||||
Reference in New Issue
Block a user