Стадия 3 — отдача файлов через FileResponse, удаление BaseHTTPMiddleware, расширение executor #3
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?
Цель
Заменить самодельный стриминг (ручной парсинг Range +
asyncio.to_threadна каждые 64KB) на встроенныйFileResponseStarlette; убрать оверхедBaseHTTPMiddleware; расширить дефолтный threadpool.Полный план: plans/2026-07-05-stability-fix-plan.md
Контекст (что чиним)
prepare_file_response(api_server.py:203-335): свой парсер Range + генератор, где каждый 64KB-чанк — отдельныйto_threadс open/seek/read/close. Отдача 500MB видео = ~8000 прыжков в threadpool, конкурирующих с SQLite/magic/pickle/os.walk за 5-6 потоков дефолтного executor в контейнере → стриминг замирает.FileResponseиз коробки.RequestLoggingMiddlewareнаBaseHTTPMiddleware(api_server.py:54-64) — каждый чанк каждого стрима проходит через anyio memory stream ради debug-лога.Задачи
bytes=0-499,bytes=-500,bytes=500-, start за EOF → 416, мусорный заголовокprepare_file_responseнаFileResponse(path, media_type=..., filename=..., content_disposition_type="inline", headers={"Cache-Control": "public, max-age=86400, immutable"}, background=...)file_chunk_generator, ручные заголовки; оставить пре-чек существования (404) и MIME-логику (magic + SQLite-кэш)RequestLoggingMiddleware; при необходимости — чистый ASGI-middleware на ~10 строк или access-log uvicornloop.set_default_executor(ThreadPoolExecutor(max_workers=32, thread_name_prefix="io"))Где не наебаться
FileResponseпроверяет файл на этапе отправки (ошибка → 500) — пре-чек на 404 оставить обязательно.Content-Dispositionсfilename*=UTF-8''...FileResponse формирует сам — руками не собирать, иначе задвоится.Cache-Control: immutable(не конфликтуют, но проверить в тестах, что 304 работает разумно).DoD
Range-тесты зелёные; отдача большого файла не порождает поток-на-чанк; поведение эндпоинта эквивалентно (кроме осознанных RFC-допущений).
Зависимости: лучше после стадии 2 (меньше конфликтов в download-путях), но технически независима.