feat(perf): implement HTTP connection pooling with httpx.AsyncClient singleton and Keep-Alive

- get_http_client: singleton AsyncClient with limits(max_keepalive=10, max_connections=20, keepalive_expiry=60s)
- close_http_client: clean socket pool teardown in FastAPI lifespan shutdown
- refactor dictionary fetchers to reuse pooled client and avoid 5x TLS handshakes per word lookup
- add test_http_connection_pooling (22/22 pytest passed)
This commit is contained in:
2026-10-06 11:34:31 +03:00
parent c4a6edee37
commit 438dfdb055
4 changed files with 211 additions and 132 deletions
+19 -5
View File
@@ -175,13 +175,27 @@
---
### 8. 🔌 Пул соединений HTTP (`httpx.AsyncClient` с Keep-Alive)
- [ ] В [`app/dictionary.py`](file:///home/ai-projects/services/study.qpid.pro/app/dictionary.py) создать синглтон-клиент `get_http_client()` с пулом соединений:
### 7.1. 🖼️ Извлечение и отображение схем, топологий и диаграмм из PDF / EPUB (Planned)
- [ ] **Извлечение бинарных изображений на диск**:
- При парсинге PDF/EPUB извлекать графические объекты (`page.images` / архивы изображений) на файловую систему в изолированную директорию книги: `data/books/{book_id}/images/{img_name}`.
- Избегать раздувания базы данных SQLite: база хранит только текст и метаданные, бинарная графика хранится на диске.
- [ ] **Кэширующий медиа-эндпоинт**:
- Создать эндпоинт `GET /api/books/{book_id}/images/{image_name}` с заголовками кэширования (`Cache-Control: public, max-age=31536000, immutable`).
- [ ] **Встраивание в текст читалки**:
- Привязывать иллюстрации к соответствующей странице/главе через Markdown-теги: `![Схема топологии](/api/books/{book_id}/images/{img_name})`.
- Интерактивный просмотр и зум схем по клику в читалке.
---
### 8. 🔌 Пул соединений HTTP (`httpx.AsyncClient` с Keep-Alive) (Completed)
- [x] В [`app/dictionary.py`](file:///home/ai-projects/services/study.qpid.pro/app/dictionary.py) создать синглтон-клиент `get_http_client()` с пулом соединений:
```python
limits = httpx.Limits(max_keepalive_connections=10, max_connections=20)
limits = httpx.Limits(max_keepalive_connections=10, max_connections=20, keepalive_expiry=60.0)
```
- [ ] Заменить вызовы `async with httpx.AsyncClient()` в парсерах на переиспользуемый клиент.
- [ ] Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив пинг внешних запросов на 300–600 мс.
- [x] Заменить вызовы `async with httpx.AsyncClient()` в парсерах на переиспользуемый клиент.
- [x] Устранить 5 повторных TCP/TLS хэндшейков на каждое слово, сократив задержку внешних запросов на 300–600 мс.
- [x] Добавить вызов `close_http_client()` в `lifespan` FastAPI при остановке приложения для чистого закрытия открытых сокетов.
- [x] Добавить юнит-тесты `test_http_connection_pooling` в `tests/test_api.py` (22/22 passed).
---