fix: ручной UPSERT вместо ON CONFLICT — не требует индекса (v1.2.39)
ON CONFLICT требовал уникальный индекс idx_runs_op_uid, который не всегда создавался (мультистейтмент SQL в psycopg2). → save_run падал молча → история пустая. Новый подход: UPDATE по op_uid, если rowcount==0 → INSERT. Не зависит от индексов, работает всегда.
This commit is contained in:
+31
-25
@@ -51,31 +51,37 @@ def save_run(client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id,
|
||||
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO runs (client_id, stand, user_email, svc_id, svc_name,
|
||||
op_name, svc_op_id, op_uid, instance_uid, display_name,
|
||||
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,
|
||||
error_log,
|
||||
# params и stages — JSONB: сериализуем в JSON-строку
|
||||
json.dumps(params) if params else None,
|
||||
json.dumps(stages) if stages else None,
|
||||
app_version,
|
||||
scenario_run_id, step_number,
|
||||
# instance_meta — тоже JSONB
|
||||
json.dumps(instance_meta) if instance_meta else None,
|
||||
))
|
||||
|
||||
# Ручной UPSERT (UPDATE → INSERT если не затронуто строк).
|
||||
# Не используем ON CONFLICT — не требует индекса, надёжнее.
|
||||
# Сценарий вызывает save_run дважды (RUNNING → OK) — второй вызов
|
||||
# обновляет существующую строку вместо создания дубликата.
|
||||
params_json = json.dumps(params) if params else None
|
||||
stages_json = json.dumps(stages) if stages else None
|
||||
meta_json = json.dumps(instance_meta) if instance_meta else None
|
||||
|
||||
if op_uid:
|
||||
cur.execute("""
|
||||
UPDATE runs SET
|
||||
status = %s, duration_sec = %s, error_log = %s,
|
||||
stages = %s, svc_name = %s, instance_meta = %s
|
||||
WHERE op_uid = %s
|
||||
""", (status, duration_sec, error_log, stages_json, svc_name, meta_json, op_uid))
|
||||
|
||||
if not op_uid or cur.rowcount == 0:
|
||||
# Нет op_uid ИЛИ UPDATE не затронул строк → INSERT
|
||||
cur.execute("""
|
||||
INSERT INTO runs (client_id, stand, user_email, svc_id, svc_name,
|
||||
op_name, svc_op_id, op_uid, instance_uid, display_name,
|
||||
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)
|
||||
""", (
|
||||
client_id, stand, user_email, svc_id, svc_name, op_name, svc_op_id,
|
||||
op_uid, instance_uid, display_name, status, duration_sec,
|
||||
error_log, params_json, stages_json, app_version,
|
||||
scenario_run_id, step_number, meta_json,
|
||||
))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
print(f"[DB] save_run OK: {op_name} {status} {duration_sec}s", flush=True)
|
||||
|
||||
Reference in New Issue
Block a user