# Сессия #7 — чанковая загрузка, worker'ы, одно соединение _Дата: 2026-06-17_ _Версия: v1.15 → v1.18_ --- ## Проблема Загрузка PDF 153 KB падала с «✗ Сеть»: - v1.14: прямая загрузка (один POST) → Ingress режет `client_max_body_size` - v1.15-16: чанки 50KB в памяти `_chunk_store = {}` → worker'ы разные, чанки теряются - v1.17: чанки в PostgreSQL (таблица `chunks`) → всё равно «Сеть» - v1.18: ОДНО DB-соединение на сборку → ? ## Хронология ### v1.14: прямая загрузка `POST /` с файлом 153 KB → Ingress (nginx) обрывает → `XHR onerror` → «Сеть» ### v1.15: чанки 50KB в памяти `POST /chunk` × 3. `_chunk_store = {}` в памяти модуля. **Ошибка:** dict живёт в одном worker'е. Gunicorn с >1 worker → чанки на разных процессах → второй не видит первый → обрыв. ### v1.16: try/except + проверка doc_id Добавлена обработка ошибок при сборке. **Откачено** (не решило проблему worker'ов). ### v1.17: чанки в БД Таблица `chunks(upload_id, chunk_index, chunk_data, ...)`. `ON CONFLICT DO NOTHING`. **Всё равно «Сеть»** — worker'ы больше не проблема, но осталась другая. ### v1.18: одно DB-соединение (текущая) **Диагноз:** `_chunk_upload` при сборке делал до 7 отдельных `db.execute`/`db.query` — каждое = новый `psycopg2.connect`. На managed-платформе это медленно → таймаут Ingress → обрыв. **Исправление:** - `_save_file_to_db(filename, file_bytes, mime, contract_id, conn=None)` — принимает соединение - `_chunk_upload` открывает ОДНО соединение на всю сборку: - SELECT chunks - INSERT contracts (если нужно) - INSERT documents - SELECT id документа - INSERT supplements - DELETE chunks - Все 6 запросов в одной транзакции, одно подключение. --- ## Архитектура чанков (текущая) ``` Клиент: file.slice(0,50KB) → XHR POST /chunk file.slice(50KB,100KB) → XHR POST /chunk file.slice(100KB,150KB) → XHR POST /chunk Сервер /chunk: 1. INSERT INTO chunks (...) ON CONFLICT DO NOTHING ← 1 conn 2. SELECT COUNT(*) FROM chunks ← 1 conn 3. Если received == total_chunks: ОДНО соединение: SELECT chunk_data ORDER BY chunk_index SELECT metadata INSERT INTO contracts (если нет cid) COMMIT → _save_file_to_db(conn=...) INSERT INTO documents SELECT id INSERT INTO supplements COMMIT DELETE FROM chunks ОТВЕТ {"contract_id": "..."} ``` ## Выученные уроки 1. **`_chunk_store` в памяти не работает с несколькими worker'ами** — нужна общая БД. 2. **Много отдельных `db.execute` = много `psycopg2.connect`** — на managed-платформе медленно. 3. **Всегда одно соединение для зависимых операций** — сборка + сохранение должны быть атомарны. 4. **Анализ агентом помог** — указал на `_save_file_to_db` как узкое место.