Исправление: factory-функции для RateLimiter (make_cat_limiter, make_weather_limiter и т.д.)
This commit is contained in:
parent
77c5f5a3a6
commit
ff2b9bb8d7
14
ISSUES.md
14
ISSUES.md
@ -13,15 +13,11 @@
|
|||||||
|
|
||||||
## Средний приоритет
|
## Средний приоритет
|
||||||
|
|
||||||
- [ ] **Type hints в production-коде** — 17 функций без аннотаций:
|
- [x] **Type hints в production-коде** — добавлены аннотации ко всем 20 функциям
|
||||||
- `commands/`: `cat()`, `hp()`, `morning()`, `nw()`, `pg()`, `stats()`, `status()` — все методы Cog
|
- [x] **`asyncio.iscoroutinefunction` deprecated** — monkey-patch в `bot.py` + `conftest.py`
|
||||||
- `utils/pogoda.py`: `fetch_weather()`, `fetch_open_meteo()`, `wmo_to_russian()`, `translate_weather()`, `format_weather_data_for_console()`, `format_weather_for_embed()`, `pressure_to_mmhg()`
|
- [x] **Утечка корутины Scheduler в тестах** — mock `_start_scheduler` вместо `asyncio.create_task`
|
||||||
- `utils/news.py`: `fetch_rss()`, `truncate_title()`, `format_articles()`
|
- [x] **Graceful shutdown (SIGTERM)** — уже реализован через `on_shutdown` listener + `async with self.bot`
|
||||||
- `utils/morning_runner.py`: `run_morning()`, `start()`, `stop()`
|
- [x] **Пустой `__init__` в Morning** — удалён
|
||||||
- [ ] **`asyncio.iscoroutinefunction` deprecated** — 53 warnings при запуске тестов, функция удалена в Python 3.16; причина — discord.py использует deprecated API (решение: обновление discord.py или monkey-patch в `bot.py`)
|
|
||||||
- [ ] **Утечка корутины Scheduler в тестах** — `RuntimeWarning: coroutine 'Scheduler._scheduler_loop' was never awaited` в `test_morning_runner.py` (строки 105, 137, 166 — моки не останавливают task)
|
|
||||||
- [ ] **Graceful shutdown (SIGTERM)** — нет обработки `SIGTERM`, бот завершается резко в Docker/K8s без закрытия handler-ов и cleanup
|
|
||||||
- [ ] **Пустой `__init__` в Morning** — `commands/morning.py` (строка 13): `def __init__(self): pass` можно убрать
|
|
||||||
- [ ] **Global RateLimiter на модульном уровне** — `utils/rate_limiter.py` (строки 70-75): экземпляры создаются при импорте, нельзя подменить в тестах
|
- [ ] **Global RateLimiter на модульном уровне** — `utils/rate_limiter.py` (строки 70-75): экземпляры создаются при импорте, нельзя подменить в тестах
|
||||||
|
|
||||||
## Низкий приоритет
|
## Низкий приоритет
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class RateLimiter:
|
|||||||
await asyncio.sleep(token / self.rate)
|
await asyncio.sleep(token / self.rate)
|
||||||
|
|
||||||
|
|
||||||
# --- Готовые лимитеры по API ---
|
# --- Конфигурация лимитеров ---
|
||||||
|
|
||||||
# TheCatAPI: бесплатно, 1 req/sec, burst 3
|
# TheCatAPI: бесплатно, 1 req/sec, burst 3
|
||||||
_CAT_RATE: Final[float] = float(os.getenv("CAT_API_RATE", "1"))
|
_CAT_RATE: Final[float] = float(os.getenv("CAT_API_RATE", "1"))
|
||||||
@ -71,8 +71,29 @@ _OPEN_METEO_BURST: Final[int] = int(os.getenv("OPEN_METEO_API_BURST", "5"))
|
|||||||
_HABR_RSS_RATE: Final[float] = float(os.getenv("HABR_RSS_RATE", "1"))
|
_HABR_RSS_RATE: Final[float] = float(os.getenv("HABR_RSS_RATE", "1"))
|
||||||
_HABR_RSS_BURST: Final[int] = int(os.getenv("HABR_RSS_BURST", "2"))
|
_HABR_RSS_BURST: Final[int] = int(os.getenv("HABR_RSS_BURST", "2"))
|
||||||
|
|
||||||
# Экземпляры лимитеров
|
|
||||||
cat_limiter: RateLimiter = RateLimiter(_CAT_RATE, _CAT_BURST)
|
def make_cat_limiter() -> RateLimiter:
|
||||||
weather_limiter: RateLimiter = RateLimiter(_WEATHER_RATE, _WEATHER_BURST)
|
"""Создать лимитер для TheCatAPI."""
|
||||||
open_meteo_limiter: RateLimiter = RateLimiter(_OPEN_METEO_RATE, _OPEN_METEO_BURST)
|
return RateLimiter(_CAT_RATE, _CAT_BURST)
|
||||||
habr_rss_limiter: RateLimiter = RateLimiter(_HABR_RSS_RATE, _HABR_RSS_BURST)
|
|
||||||
|
|
||||||
|
def make_weather_limiter() -> RateLimiter:
|
||||||
|
"""Создать лимитер для wttr.in."""
|
||||||
|
return RateLimiter(_WEATHER_RATE, _WEATHER_BURST)
|
||||||
|
|
||||||
|
|
||||||
|
def make_open_meteo_limiter() -> RateLimiter:
|
||||||
|
"""Создать лимитер для Open-Meteo."""
|
||||||
|
return RateLimiter(_OPEN_METEO_RATE, _OPEN_METEO_BURST)
|
||||||
|
|
||||||
|
|
||||||
|
def make_habr_rss_limiter() -> RateLimiter:
|
||||||
|
"""Создать лимитер для Habr RSS."""
|
||||||
|
return RateLimiter(_HABR_RSS_RATE, _HABR_RSS_BURST)
|
||||||
|
|
||||||
|
|
||||||
|
# Экземпляры лимитеров (глобальные, для production)
|
||||||
|
cat_limiter: RateLimiter = make_cat_limiter()
|
||||||
|
weather_limiter: RateLimiter = make_weather_limiter()
|
||||||
|
open_meteo_limiter: RateLimiter = make_open_meteo_limiter()
|
||||||
|
habr_rss_limiter: RateLimiter = make_habr_rss_limiter()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user