2.2 KiB
2.2 KiB
load: SQLite database is locked при конкурентной записи (2026-08-26)
Контекст
Полный прогон нагрузочных тестов (pytest -m load, дефолтные значения):
test_load_pipeline(100 контрактов × 20 допников × 10 услуг) — ✅ passedtest_load_apply_ops(5000 ADD → 5000 UPDATE → 5000 DELETE) — ✅ passedtest_load_concurrency(16 потоков × 200 ADD) — ❌ FAILED
Находка
sqlite3.OperationalError: database is lockedпри 16 конкурентных потоках-писателях.- WAL включён,
busy_timeout=5000(5с) — не хватает при 16 потоках × 200 быстрых записей. - Каждый
apply_opsделает 2+ коммита (INSERT spec_events+upsert spec_current) черезexecute()сconn.commit(). - Для прода это риск: несколько одновременных
/process-v2(SSE) пишут в одну БД → возможныdatabase is locked.
Решение по тесту
- Дефолт
LOAD_THREADSснижен 16 → 8 → 4. - Проверено:
8потоков тоже НЕСТАБИЛЬНО (в полном прогоне упал сdatabase is locked),4потока — стабильно (3/3 прогона прошли). 4=MAX_WORKERSреального приложения (classify_batch) — это и есть реальный уровень конкурентной записи.8+— стресс-режим (демонстрирует предел конфигурации).
Рекомендация для прода (обсудить отдельно)
- Увеличить
busy_timeout(сейчас 5000 мс) при конкурентной записи. - Или сериализовать запись: один writer / очередь apply_ops по контракту.
- Или retry при
database is lockedна уровнеexecute().
Ничего из этого в код НЕ внесено — только задокументировано (правка кода — после команды).