fix(tradein/tgbot): ограничение частоты на отправителя в мосте поддержки #2543

Merged
lekss361 merged 1 commit from fix/tradein-audit-tgbot-ratelimit into main 2026-07-26 23:16:58 +00:00
Owner

Проблема

В Telegram-мосте поддержки не было ограничения частоты на отправителя. Воркер long-polling однопоточный и обрабатывает апдейты последовательно, поэтому один клиент, шлющий сообщения потоком, задерживал зеркалирование сообщений всех остальных.

Хуже того, лимит группы Telegram — около 20 сообщений в минуту, и его превышение даёт 429 с ожиданием в десятки секунд, что бьёт по всем клиентам сразу.

Решение

Переиспользован готовый SlidingWindowLimiter из app/core/ratelimit.py — тот же механизм, что применён для веб-чата, но ключом выступает chat_id отправителя.

Поведение при превышении выбрано так, чтобы не создать новый источник флуда: молча проглотить сообщение нельзя (клиент решит, что доставлено), но и отвечать на каждое превышение тоже нельзя. Клиент уведомляется не чаще одного раза за окно.

Test plan

  • Превышение лимита одним клиентом не блокирует доставку сообщений другого
  • Уведомление приходит не чаще одного раза за окно
  • Полный набор тестов зелёный
## Проблема В Telegram-мосте поддержки не было ограничения частоты на отправителя. Воркер long-polling однопоточный и обрабатывает апдейты последовательно, поэтому один клиент, шлющий сообщения потоком, задерживал зеркалирование сообщений всех остальных. Хуже того, лимит группы Telegram — около 20 сообщений в минуту, и его превышение даёт 429 с ожиданием в десятки секунд, что бьёт **по всем клиентам сразу**. ## Решение Переиспользован готовый `SlidingWindowLimiter` из `app/core/ratelimit.py` — тот же механизм, что применён для веб-чата, но ключом выступает `chat_id` отправителя. Поведение при превышении выбрано так, чтобы не создать новый источник флуда: молча проглотить сообщение нельзя (клиент решит, что доставлено), но и отвечать на каждое превышение тоже нельзя. Клиент уведомляется не чаще одного раза за окно. ## Test plan - [x] Превышение лимита одним клиентом не блокирует доставку сообщений другого - [x] Уведомление приходит не чаще одного раза за окно - [x] Полный набор тестов зелёный
lekss361 added 1 commit 2026-07-26 21:44:42 +00:00
fix(tradein/tgbot): per-chat_id rate-limit на входящие сообщения бота
All checks were successful
CI Trade-In / changes (pull_request) Successful in 16s
CI / changes (pull_request) Successful in 16s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m11s
CI / frontend-tests (pull_request) Has been skipped
8e0479c616
Однопоточный long-polling воркер обрабатывал апдейты строго
последовательно, и ничто не мешало одному флудящему клиенту слать
поток сообщений: каждое зеркалировалось (copyMessage) в support-топик,
а групповой Telegram-лимит ~20 msg/min общий на ВСЕХ клиентов сразу —
превышение даёт 429 с ожиданием 30-60с, за которое воркер не может
обработать ни одного апдейта от кого-либо ещё.

Переиспользован app.core.ratelimit.SlidingWindowLimiter (тот же
примитив, что уже применён для веб-чата поддержки, app/api/v1/support.py) —
ключ здесь TELEGRAM chat_id отправителя, лимит заметно ниже группового
Telegram-порога (5 msg/60s). Сообщения сверх бюджета не зеркалируются
(и не пишутся в tg_support_messages — маршрутизировать ответ всё равно
нечего без topic_message_id), клиент получает явное уведомление о
недоставке РОВНО один раз за окно (второй лимитер с limit=1 на то же
окно) — молчать нельзя (клиент решит, что доставлено), но повторные
уведомления на каждое превышение сами стали бы источником флуда.
lekss361 merged commit 036ff84eaa into main 2026-07-26 23:16:58 +00:00
lekss361 deleted branch fix/tradein-audit-tgbot-ratelimit 2026-07-26 23:16:58 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2543
No description provided.