Причина аварии 18.09.2026 (разобрана замерами по логам и нагрузкой):
MAX доставляет один и тот же update повторно, каждый повтор запускал новый поток
runserver, а поток держал своё соединение к MySQL на всё время запроса — отсюда
117 одновременных соединений от одного процесса и 1040 Too many connections у
общего сервера БД. Залп запускался тем, что бот не мог ответить: user_query из
callback'а с числовым data уходил в Yandex как content-число, Yandex отвечал
400 'failed to parse request JSON', сообщение оставалось в истории сессии и ломало
все последующие вызовы этой сессии.
- max_bot/max_api.py: таймаут (3.05, 15) на все 12 вызовов MAX API и обёртка
_max_request — таймаут даёт success=False, а не исключение (иначе вебхук отвечает
500 и провоцирует повторную доставку).
- ai_agent/api_yandex_ai.py: таймаут 20 с и max_retries=0; приведение user_query
к строке; откат неудачной попытки из истории; окно истории 20 сообщений;
лимит 500 сессий в памяти процесса.
- ai_agent/api_common.py: user_query приводится к строке на входе во все AI-агенты.
- max_bot/views.py: дедупликация вебхука по идентификатору update (TTL 300 с,
cache.add) и семафор на 12 одновременных обработок — лишние получают быстрый 200.
Проверено: юнит active, авторелоад, 0 новых ERROR за 3 часа, счётчик 1040 не вырос,
пик соединений процесса упал со 117 до 2, два живых числовых запроса из прода
получили нормальные ответы вместо ошибки.