Files
contracts/History/session-07-chunks.md
T

3.7 KiB
Raw Permalink Blame History

Сессия #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 как узкое место.