Бот на 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, откройте бот не отвечает. Если getWebhookInfo показывает 404 или SSL, откройте ошибки webhook.

Лимиты контейнера на Bothost

Контейнер бота ограничен тарифом. При превышении памяти процесс завершается, политика перезапуска поднимает его снова. Снаружи это простой и статус restarting.
ТарифПамять контейнера
Бесплатный256 МБ
Базовый1 ГБ
Pro2 ГБ
Эти цифры относятся к контейнеру бота. Рядом в том же лимите оказываются интерпретатор, загруженные библиотеки и ваши данные в оперативной памяти. Файл SQLite на диске в /app/data в этот лимит не входит, пока вы не прочитали его целиком в список.

Python bot memory leak

Как выглядит

В логах работы нет обычного traceback. Процесс обрывается, иногда последняя строка Killed. Контейнер сам поднимается и через минуты или часы падает снова. Пока он жив, бот отвечает всё медленнее. После рестарта память низкая и снова растёт на том же потоке сообщений. Код выхода такого завершения у Docker — 137: процесс получил SIGKILL из-за лимита памяти, а не из-за исключения в Python.

Что обычно раздувает процесс

Интерпретатор сам по себе на типичном aiogram-боте в 256 МБ помещается. Растёт то, что код копит между апдейтами:
  • словарь или список «всех пользователей / всех сообщений» без удаления старых записей;
  • сессии и состояния, которые не истекают;
  • байты файлов и картинок, оставленные в списке после отправки;
  • новый HTTP-клиент на каждый апдейт (aiohttp.ClientSession(), httpx.AsyncClient()), который не закрывается;
  • загрузка большой таблицы или всей базы SQLite в память на старте.
Разовый тяжёлый запрос (одна большая картинка) может один раз упереться в лимит. Утечка видна иначе: потребление растёт, даже когда сообщений мало и они одинаковые, и сбрасывается только рестартом.

Что сделать

    • Найдите структуру, которая живёт всё время процесса, и ограничьте её: максимальный размер, удаление по времени, запись на диск в /app/data вместо списка в RAM. Про сохранение файла: SQLite после рестарта.
    • Создайте один ClientSession на всё приложение и закрывайте его при остановке. Внутри хендлера открывайте сессию через async with, если она нужна только на один запрос.
    • Не читайте файл целиком, если можно отдать путь или кусок. Картинку отправили в Telegram — удалите байты из переменной.
    • Если бот стабильно упирается в 256 МБ на обычной работе (модель, pandas, несколько браузерных вкладок), тарифа бесплатного лимита не хватает по объёму задачи. Базовый даёт 1 ГБ, Pro даёт 2 ГБ. Утечку это не заменяет: на большем лимите тот же список дорастёт позже.
Пока в логе есть Python traceback (ModuleNotFoundError, KeyError), это падение кода, а не память: локально работает, на сервере падает.

bot timeout

Слово «timeout» в логе относится к разным ожиданиям. Лечится по-разному.

Long polling

getUpdates специально висит и ждёт новые сообщения. В aiogram таймаут этого ожидания задаётся параметром polling и в логе выглядит как обычная работа, а не как сбой. Контейнер running, ошибка не пишется, бот отвечает на сообщения. Это состояние менять не нужно. Если бот молчит, а в логе при этом Conflict или пусто на ваши сообщения, причина в сессии токена: бот не отвечает.

Webhook не дождался ответа

Telegram шлёт POST и ждёт HTTP 200. Пока хендлер качает файл, зовёт нейросеть и только потом отвечает, доставка считается неуспешной, тот же update_id приходит снова, пользователь видит двойной ответ или задержку. В getWebhookInfo растёт pending_update_count. Ответьте 200 в начале обработчика, дальнейшую работу сделайте после отправки ответа. Разбор 404 и SSL: webhook Telegram. 504 Gateway Timeout в браузере на домене бота чаще значит, что процесс не слушает PORT на 0.0.0.0 или контейнер перезапускается. Это сеть до приложения, а не лимит Telegram.

Таймаут чужого API

TimeoutError
asyncio.TimeoutError
httpx.TimeoutException
requests.exceptions.ReadTimeout
Контейнер остаётся running. Падает один вызов внутри хендлера: OpenAI, платёжка, ваш сервер. Пока вызов висит без собственного лимита времени, очередь бота стоит, и людям кажется, что бот завис. Задайте таймаут клиенту HTTP (разумный предел на один запрос, например 15–30 секунд) и обработайте исключение: напишите пользователю, что сервис не ответил, и не держите апдейт бесконечно. Если таймаут только у зарубежных нейросетей (DeepSeek, Gemini, OpenAI, Claude) и текст ошибки про соединение или регион, Bothost исходящие запросы не режет. Часть нод определяется как российские, и API провайдера отклоняет вызов. В профиле Bothost включите «Зарубежный IP для API и нейросетей» и задеплойте бота заново: уже запущенные контейнеры сами на другую ноду не переезжают. Тот же разбор: справочник ошибок.

API rate limits

Telegram: 429 Too Many Requests

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.

Чужой API

Лимит OpenAI и других сервисов приходит их собственным 429. Это не лимит контейнера Bothost. В ответе провайдера есть, когда повторить запрос. Имеет смысл очередь в одном процессе и повтор с паузой из ответа, а не новый параллельный запрос на каждый апдейт пользователя.

Как не перепутать три случая

В логеКонтейнерЧто делать
Killed, код 137, рестарты без tracebackrestartingУменьшить то, что копится в памяти, или тариф с большим лимитом
TimeoutError на URL нейросети или HTTPrunningТаймаут и обработка ошибки в хендлере; для нейросетей при блоке по региону — зарубежный IP и новый деплой
retry after, 429runningПауза на retry_after, реже отправлять
Conflict, UnauthorizedrunningОдин токен и одна сессия
---

См. также

Неясно, память это или исключение? Пришлите в поддержку кусок лога вокруг перезапуска и тариф: @bothostru.