debug_log: таблица + логи на каждом шаге _chunk_upload, v1.19

This commit is contained in:
2026-06-17 17:49:33 +04:00
parent ba5933b715
commit dfb9a4218b
3 changed files with 43 additions and 9 deletions
+30 -8
View File
@@ -17,6 +17,15 @@ from api import api_bp
load_dotenv()
import time as _time
def _log(step, detail=""):
"""Писать отладочный лог в таблицу debug_log."""
try:
db.execute("INSERT INTO debug_log (step, detail) VALUES (%s,%s)", (step, str(detail)[:500]))
except:
pass # не мешать основному потоку
def _save_file_to_db(filename, file_bytes, mime, contract_id, conn=None):
"""Сохранить файл в БД. Если conn передан — использовать его, иначе свои подключения."""
@@ -136,35 +145,42 @@ class ContractsApp:
chunk_data = chunk_file.read()
mime = mimeutil.guess_mime(filename) or "application/octet-stream"
_log("chunk_start", f"{filename} idx={chunk_index}/{total_chunks} size={len(chunk_data)} cid={cid}")
# Сохранить чанк в БД (ON CONFLICT — идемпотентно)
db.execute(
rc, err = db.execute(
"INSERT INTO chunks (upload_id, chunk_index, chunk_data, filename, mime, total_chunks, cid) "
"VALUES (%s,%s,%s,%s,%s,%s,%s) ON CONFLICT (upload_id, chunk_index) DO NOTHING",
(upload_id, chunk_index, chunk_data, filename, mime, total_chunks, cid),
)
_log("chunk_insert", f"idx={chunk_index} rc={rc} err={err}")
# Сколько уже получено
count_res, _ = db.query(
count_res, cerr = db.query(
"SELECT COUNT(*) FROM chunks WHERE upload_id=%s", (upload_id,)
)
received = count_res["rows"][0][0] if count_res else 0
_log("chunk_count", f"received={received}/{total_chunks} err={cerr}")
if received == total_chunks:
_log("assembly_start", f"{filename} {total_chunks} chunks, {sum(len(c) if c else 0 for c in [chunk_data])}b this chunk")
try:
# ОДНО соединение на всю сборку + сохранение
conn, err = db.connect()
_log("assembly_connect", f"err={err}")
if err:
return jsonify({"error": f"БД: {err}"}), 500
cur = conn.cursor()
# Собрать все чанки по порядку
cur.execute(
"SELECT chunk_data FROM chunks WHERE upload_id=%s ORDER BY chunk_index",
(upload_id,),
)
file_bytes = b"".join(r[0] for r in cur.fetchall())
all_chunks = cur.fetchall()
_log("assembly_select", f"{len(all_chunks)} rows")
file_bytes = b"".join(r[0] for r in all_chunks)
_log("assembly_joined", f"{len(file_bytes)} bytes")
# Метаданные
cur.execute(
"SELECT filename, mime, cid FROM chunks WHERE upload_id=%s LIMIT 1",
(upload_id,),
@@ -173,8 +189,8 @@ class ContractsApp:
fname = meta[0] if meta else filename
fmime = meta[1] if meta else mime
fcid = meta[2] if meta else cid
_log("assembly_meta", f"fname={fname} mime={fmime} cid={fcid}")
# Контракт если нет
if fcid:
contract_id = fcid
else:
@@ -183,11 +199,13 @@ class ContractsApp:
("б" + __import__("datetime").datetime.now().strftime("%Y%m%d-%H%M"), ""),
)
contract_id = cur.fetchone()[0]
_log("assembly_contract", f"new cid={contract_id}")
conn.commit()
_log("assembly_commit", "ok")
# Сохранить файл через то же соединение
doc_id = _save_file_to_db(fname, file_bytes, fmime, str(contract_id), conn=conn)
_log("save_file", f"doc_id={doc_id}")
if not doc_id:
conn.rollback()
cur.close()
@@ -196,7 +214,9 @@ class ContractsApp:
cur.close()
conn.close()
_log("assembly_done", f"cid={contract_id}")
except Exception as e:
_log("assembly_error", str(e))
try: conn.rollback()
except: pass
try: cur.close()
@@ -206,9 +226,11 @@ class ContractsApp:
return jsonify({"error": f"Сборка: {e}"}), 500
finally:
db.execute("DELETE FROM chunks WHERE upload_id=%s", (upload_id,))
_log("chunks_cleanup", f"upload_id={upload_id}")
return jsonify({"contract_id": str(contract_id)})
_log("chunk_ok", f"idx={chunk_index} received={received}/{total_chunks}")
return jsonify({"chunk": chunk_index, "received": received, "total": total_chunks})
def _show_contract(self, cid):