Сервис-витрина каталога цитат: принимает полный снимок каталога и отдаёт цитаты читателям по одной. Всё состояние — в памяти одного процесса, внешних БД, кэшей и брокеров нет.
Что внутри
- Снимок читается потоком — тело до 110 МБ разбирается по чанкам и строкам
через
orjson, целиком в память не поднимается. Битая запись пропускается со счётчикомdropped, битый конверт — 400. - Packed-буфер вместо объектов — тела записей лежат в одном
bytearrayс length-prefix, индексid → offset, набор всех id отдельно. Поэтому витрина помнит id даже после вытеснения тела, а LRU по байтам работает предохранителем, а не штатным путём. - Circuit breaker на каталог — 5 подряд транспортных сбоев открывают цепь
с backoff и jitter, half-open пускает одну пробу. А вот 503 breaker не
открывает: это ответ каталога, а не обрыв связи, — уважается
Retry-After. - Честные счётчики —
X-Source: LOCAL | CATALOGна каждом ответе, а/statsпоказывает, сколько отдано из памяти, сколько дочитано из каталога и сколько тел вытеснено. 404 из каталога не кешируется, DELETE ставит tombstone до следующего снимка. - Укладывается в 256 МБ RAM — пик на снимке в 340 000 записей (114 МБ) около 220 МБ при лимите 0.5 CPU и одном воркере uvicorn.
Стек
Python 3.13, FastAPI, uvicorn, orjson, httpx и uvloop. Всё приложение — чуть
меньше 18 КБ кода в четырёх модулях; сборка через pip, multi-stage образ,
запуск под non-root.
Проверка
scripts/contract_test.py прогоняет контракт целиком против заглушки
каталога: импорт, LOCAL/CATALOG, границы полей, tombstone’ы и форму /stats.