session-07: чанковая загрузка, worker'ы, одно DB-соединение
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
# Сессия #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` как узкое место.
|
||||||
Reference in New Issue
Block a user