Стадия 5 — SQLite: батчинг записей вместо connect+write на каждый запрос #5
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Цель
Убрать SQLite из горячего пути
/media: сейчас каждый кэш-хит = поток + новый connect + UPDATE (с busy_timeout до 5с), что душит общий threadpool и стриминг.Полный план: plans/2026-07-05-stability-fix-plan.md
Контекст (что чиним)
/media(api_server.py:963-973): fire-and-forgetasyncio.create_task(_update_access(...))→to_thread→ connect → UPDATE — на каждый запрос картинки.Задачи
_access_updates: dict[(channel, post_id, fid), float]— кэш-хит просто пишет в словарь (на лупе, дёшево и атомарно для asyncio), никакого to_threadexecutemany UPDATE; под supervision из стадии 1 (п. 1.4)asyncio.create_task(_update_access(...))целикомupsert_media_file_ids_bulk_syncсexecutemanyв file_io.pyaddedв БД обновился; flush при shutdown; ключи с числовым каналом (-100...)Где не наебаться
str(...)— рассинхрон str/int тихо ломает UPDATE (строка не находится), timestamp перестаёт обновляться, и живые файлы начнут выпадать из кэша по 20-дневному TTL при живом трафике. Тест именно на числовой канал обязателен.executemanyснимать снапшот и очищать атомарно (взять dict, заменить на пустой), чтобы не потерять обновления, пришедшие во время flush.DoD
На кэш-хит
/media— ноль обращений к SQLite в горячем пути (кроме read-кэша MIME); фоновая запись раз в минуту; тесты зелёные.Зависимости: стадия 1 (supervision), стадия 4 (п. 4.2 — bulk upsert; можно сделать и здесь, если стадия 4 ещё не начата).