<!-- Bothost docs | HTML: https://bothost.ru/docs/bot-memory-timeout-rate-limits | Markdown: https://bothost.ru/docs/bot-memory-timeout-rate-limits.md | Index: https://bothost.ru/llms.txt -->

# Память, timeout и лимиты API: бот зависает, падает или получает 429

Бот на Bothost то отвечает, то замолкает, контейнер перезапускается без traceback или Telegram возвращает `Too Many Requests`. Это три разные ситуации: лимит памяти тарифа, таймаут конкретного вызова и лимит Bot API или Discord.

> **Для людей и ИИ.** Каноническая страница: https://bothost.ru/docs/bot-memory-timeout-rate-limits · Markdown: https://bothost.ru/docs/bot-memory-timeout-rate-limits.md · Индекс: https://bothost.ru/llms.txt
> Отвечает на запросы: Python bot memory leak, bot timeout, API rate limits, 429 Too Many Requests, retry after, RetryAfter, TimeoutError, OOM, Killed, exited with code 137.
> Если в логе `Conflict` или `Unauthorized`, откройте [бот не отвечает](bot-not-responding). Если `getWebhookInfo` показывает 404 или SSL, откройте [ошибки webhook](telegram-webhook-errors).

---

## Лимиты контейнера на Bothost

Контейнер бота ограничен тарифом. При превышении памяти процесс завершается, политика перезапуска поднимает его снова. Снаружи это простой и статус `restarting`.

| Тариф | Память контейнера |
|---|---|
| Бесплатный | 256 МБ |
| Базовый | 1 ГБ |
| Pro | 2 ГБ |

Эти цифры относятся к контейнеру бота. Рядом в том же лимите оказываются интерпретатор, загруженные библиотеки и ваши данные в оперативной памяти. Файл SQLite на диске в `/app/data` в этот лимит не входит, пока вы не прочитали его целиком в список.

---

## Python bot memory leak

### Как выглядит

В логах работы нет обычного traceback. Процесс обрывается, иногда последняя строка `Killed`. Контейнер сам поднимается и через минуты или часы падает снова. Пока он жив, бот отвечает всё медленнее. После рестарта память низкая и снова растёт на том же потоке сообщений.

Код выхода такого завершения у Docker — 137: процесс получил SIGKILL из-за лимита памяти, а не из-за исключения в Python.

### Что обычно раздувает процесс

Интерпретатор сам по себе на типичном aiogram-боте в 256 МБ помещается. Растёт то, что код копит между апдейтами:

- словарь или список «всех пользователей / всех сообщений» без удаления старых записей;
- сессии и состояния, которые не истекают;
- байты файлов и картинок, оставленные в списке после отправки;
- новый HTTP-клиент на каждый апдейт (`aiohttp.ClientSession()`, `httpx.AsyncClient()`), который не закрывается;
- загрузка большой таблицы или всей базы SQLite в память на старте.

Разовый тяжёлый запрос (одна большая картинка) может один раз упереться в лимит. Утечка видна иначе: потребление растёт, даже когда сообщений мало и они одинаковые, и сбрасывается только рестартом.

### Что сделать

1. Найдите структуру, которая живёт всё время процесса, и ограничьте её: максимальный размер, удаление по времени, запись на диск в `/app/data` вместо списка в RAM. Про сохранение файла: [SQLite после рестарта](sqlite-data-lost).
2. Создайте один `ClientSession` на всё приложение и закрывайте его при остановке. Внутри хендлера открывайте сессию через `async with`, если она нужна только на один запрос.
3. Не читайте файл целиком, если можно отдать путь или кусок. Картинку отправили в Telegram — удалите байты из переменной.
4. Если бот стабильно упирается в 256 МБ на обычной работе (модель, pandas, несколько браузерных вкладок), тарифа бесплатного лимита не хватает по объёму задачи. Базовый даёт 1 ГБ, Pro даёт 2 ГБ. Утечку это не заменяет: на большем лимите тот же список дорастёт позже.

Пока в логе есть Python traceback (`ModuleNotFoundError`, `KeyError`), это падение кода, а не память: [локально работает, на сервере падает](works-locally-fails-on-server).

---

## bot timeout

Слово «timeout» в логе относится к разным ожиданиям. Лечится по-разному.

### Long polling

`getUpdates` специально висит и ждёт новые сообщения. В aiogram таймаут этого ожидания задаётся параметром polling и в логе выглядит как обычная работа, а не как сбой. Контейнер `running`, ошибка не пишется, бот отвечает на сообщения. Это состояние менять не нужно.

Если бот молчит, а в логе при этом `Conflict` или пусто на ваши сообщения, причина в сессии токена: [бот не отвечает](bot-not-responding).

### Webhook не дождался ответа

Telegram шлёт POST и ждёт HTTP `200`. Пока хендлер качает файл, зовёт нейросеть и только потом отвечает, доставка считается неуспешной, тот же `update_id` приходит снова, пользователь видит двойной ответ или задержку. В `getWebhookInfo` растёт `pending_update_count`.

Ответьте `200` в начале обработчика, дальнейшую работу сделайте после отправки ответа. Разбор 404 и SSL: [webhook Telegram](telegram-webhook-errors).

`504 Gateway Timeout` в браузере на домене бота чаще значит, что процесс не слушает `PORT` на `0.0.0.0` или контейнер перезапускается. Это сеть до приложения, а не лимит Telegram.

### Таймаут чужого API

```text
TimeoutError
asyncio.TimeoutError
httpx.TimeoutException
requests.exceptions.ReadTimeout
```

Контейнер остаётся `running`. Падает один вызов внутри хендлера: OpenAI, платёжка, ваш сервер. Пока вызов висит без собственного лимита времени, очередь бота стоит, и людям кажется, что бот завис.

Задайте таймаут клиенту HTTP (разумный предел на один запрос, например 15–30 секунд) и обработайте исключение: напишите пользователю, что сервис не ответил, и не держите апдейт бесконечно.

Если таймаут только у зарубежных нейросетей (DeepSeek, Gemini, OpenAI, Claude) и текст ошибки про соединение или регион, Bothost исходящие запросы не режет. Часть нод определяется как российские, и API провайдера отклоняет вызов. В профиле Bothost включите «Зарубежный IP для API и нейросетей» и задеплойте бота заново: уже запущенные контейнеры сами на другую ноду не переезжают. Тот же разбор: [справочник ошибок](common-errors).

---

## API rate limits

### Telegram: 429 Too Many Requests

```text
Too Many Requests: retry after 5
aiogram.exceptions.TelegramRetryAfter
```

`error_code` в ответе Bot API равен `429`, в теле есть `parameters.retry_after` — число секунд до следующей попытки.

Ориентиры Bot API, из-за которых рассылка с Bothost упирается в лимит:

- около одного сообщения в секунду в один и тот же чат;
- около 30 сообщений в секунду на бота в разные чаты;
- в группе отдельный, более жёсткий предел на чат.

Цикл `for user in users: await bot.send_message(...)` без паузы выбирает лимит за секунды. Повтор сразу после `429` продлевает ожидание. Прочитайте `retry_after` и подождите это число секунд, затем отправьте следующее сообщение. Для рассылки держите паузу между чатами и не запускайте вторую такую рассылку параллельно тем же токеном: лимит общий на бота, локальный процесс и контейнер на Bothost делят его.

`429` не лечится рестартом контейнера и сменой порта. Пока код шлёт быстрее лимита, ошибка вернётся.

### Discord

HTTP-методы Discord тоже отвечают `429` и полем `retry_after`. Его нужно выдержать до повтора.

Отдельно шлюз. Частые повторные входы (Identify) закрывают соединение с кодом `4008` Rate limited, бот в списке участников остаётся offline. Один процесс, пауза перед повторным `login`, без цикла «упал — сразу стартовать снова». Два клиента с одним токеном дают мигающий offline: [Discord bot offline](bot-not-responding).

### Чужой API

Лимит OpenAI и других сервисов приходит их собственным `429`. Это не лимит контейнера Bothost. В ответе провайдера есть, когда повторить запрос. Имеет смысл очередь в одном процессе и повтор с паузой из ответа, а не новый параллельный запрос на каждый апдейт пользователя.

---

## Как не перепутать три случая

| В логе | Контейнер | Что делать |
|---|---|---|
| `Killed`, код 137, рестарты без traceback | `restarting` | Уменьшить то, что копится в памяти, или тариф с большим лимитом |
| `TimeoutError` на URL нейросети или HTTP | `running` | Таймаут и обработка ошибки в хендлере; для нейросетей при блоке по региону — зарубежный IP и новый деплой |
| `retry after`, `429` | `running` | Пауза на `retry_after`, реже отправлять |
| `Conflict`, `Unauthorized` | `running` | [Один токен и одна сессия](bot-not-responding) |

---

## См. также

- [Бот не отвечает](bot-not-responding)
- [Webhook Telegram](telegram-webhook-errors)
- [SQLite и данные после рестарта](sqlite-data-lost)
- [Справочник ошибок при деплое](common-errors)

**Неясно, память это или исключение?** Пришлите в поддержку кусок лога вокруг перезапуска и тариф: [@bothostru](https://t.me/bothostru).
