diff --git a/site/app.py b/site/app.py index 4547ec6..13f2865 100644 --- a/site/app.py +++ b/site/app.py @@ -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): diff --git a/site/schema.py b/site/schema.py index 401c202..6d4f91d 100644 --- a/site/schema.py +++ b/site/schema.py @@ -116,6 +116,17 @@ CREATE TABLE IF NOT EXISTS chunks ( ); """ +# ── Таблица debug_log ───────────────────────────────────────── + +DDL_DEBUG_LOG = """ +CREATE TABLE IF NOT EXISTS debug_log ( + id SERIAL PRIMARY KEY, + step TEXT NOT NULL, + detail TEXT, + created_at TIMESTAMPTZ DEFAULT now() +); +""" + # ── Список всех DDL ──────────────────────────────────────────── ALL_DDL = [ @@ -125,6 +136,7 @@ ALL_DDL = [ ("spec_rows", DDL_SPEC_ROWS), ("spec_history", DDL_SPEC_HISTORY), ("chunks", DDL_CHUNKS), + ("debug_log", DDL_DEBUG_LOG), ] diff --git a/site/templates/upload.html b/site/templates/upload.html index 3155703..97beb2b 100644 --- a/site/templates/upload.html +++ b/site/templates/upload.html @@ -59,7 +59,7 @@