Перезапуск телеграмм-бота в случае ошибки
При использовании телеграмм-бота на сервере, работающим под linux перезапустить упавший скрипт Python, в случае использования bot.polling , можно при помощи systemd или supervisor .
Разберем случай с менеджером системных и служб systemd .
Systemd представляет собой программный комплекс, который содержит набор системных компонентов для операционных систем Linux. Его основная цель — унифицировать конфигурацию и поведение служб в дистрибутивах Linux. Основным компонентом systemd является «менеджер систем и служб» — система инициализации, используемая для загрузки пользовательского пространства и управления пользовательскими процессами.
Проще говоря, системный менеджер systemd запустит любой скрипт (в том числе и скрипт Python телеграмм-бота) при старте системы, и будет перезапускать его в случае падения.
Установим системный менеджер systemd , если отсутствует:
$ apt-get install systemd
Создадим файл bot.service в директории /etc/systemd/system с таким содержанием:
$ sudo touch /etc/systemd/system/bot.service
Теперь откроем его
$ sudo nano /etc/systemd/system/bot.service
и вставим следующее содержимое:
[Unit] Description=Telegram bot %name% After=syslog.target After=network.target [Service] Type=simple User=root # замените на свой путь к каталогу, где находится `bot.py` WorkingDirectory=/usr/local/bin/bot # или другой путь # замените на свой путь к телеграмм-боту `bot.py` ExecStart=/usr/bin/python3 /usr/local/bin/bot/bot.py RestartSec=10 Restart=always [Install] WantedBy=multi-user.target
в консоли выполним:
# перечитываем конфигурацию # (обнаружит файл `bot.service`) $ sudo systemctl daemon-reload # подключаем демон `bot.service` $ sudo systemctl enable bot # запускаем демон `bot.service` $ sudo systemctl start bot # смотрим статус демона `bot.service` $ sudo systemctl status bot
Теперь перезапустить/остановить телеграмм-бота можно системными командами Linux:
# перезапуск $ sudo systemctl restart bot # остановка $ sudo systemctl stop bot # запуск после остановки $ sudo systemctl start bot
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Переход на асинхронный python-telegram-bot версии 20.x
- Чистый интерфейс Python для Telegram Bot API
- Команды и оповещения @BotFather в Telegram
- Обработка сообщений модулем python-telegram-bot
- Фильтры сообщений модуля python-telegram-bot
- Хранение временных данных модулем python-telegram-bot
- Настройки по умолчанию модуля python-telegram-bot
- Планировщик сообщений модуля python-telegram-bot
- Форматирование и отправка сообщений в python-telegram-bot
- Работа с файлами/media, модуль python-telegram-bot
- Меню из кнопок, модуль python-telegram-bot
- Объект CallbackContext модуля python-telegram-bot
- Подключения Telegram-бота через webhook
- Обработка исключений модуля python-telegram-bot
- Создание Inline-бота, модуль python-telegram-bot
- Работа с опросами в модуле python-telegram-bot
- Создание разговоров ConversationHandler в python-telegram-bot
- Перезапуск телеграмм-бота в случае ошибки
- Декоратор-обработчик сообщений в python-telegram-bot
- Авторизация на сайте через Telegram Passport
- Ведение публикаций в Telegram-канале с python-telegram-bot
- UTF коды emoji/эмодзи для отправки в Telegram из Python
Глава 6 Повышаем стабильность работы бота
К этому моменту вы знаете уже достаточно для того, что бы решить значительную часть своих задач по ботостроению. Простой бот будет работать достаточно стабильно, но всё равно иногда сервера API Telegram могут давать сбой. Даже если в вашем коде нет ошибок, и пользователи используют его правильно, иногда он может падать.
В этой главе мы поговорим о том, как повысить работоспособность бота за счёт отлавливания и обработки ошибок пуллинга.
6.1 Конструкция tryCatch()
Повысить работоспособность вашего бота поможет конструкция tryCatch() . Данная конструкция имеет следующий синтаксис:
tryCatch(expr = ~ Тут код который будет выполняться ~ >, error = function(err) ~ код который будет выполняться в случае возникновения ошибки в блоке expr ~ >, finally = ~ Код который будет выполняться в любом случае, не зависимо от того закончилось выражение expr ошибкой или нет ~ >)
6.2 Логика работы конструкции tryCatch()
Из описанного синтаксиса понятно, что вам необходимо завернуть выражение в фигурные скобки в аргументе expr . Это выражение будет выполняться либо до тех пор, пока не встретится ошибка, либо если ошибки нет, оно будет выполнено полностью.
Если в выражении переданном в expr встречается ошибка, то конструкция tryCath() запустит анонимную функцию, которую вы передали в блоке error .
В любом случае, не зависимо от того, встретилась в выражении expr ошибка или нет, в завершении выполнения будет выполнен код, переданный в аргумент finally .
Если вы хотите более подробно узнать про конструкцию tryCatch() посмотрите этот видео урок.
6.3 Используем tryCatch() внутри бота
По большому счёту вы можете использовать tryCatch() внутри каждой функции вашего бота. Но можно убить всех зайцев одним выстрелом.
В разработке ботов слабым местом является пуллинг, т.е. метод updater$start_polling() . Пуллинг — это бесконечный цикл, именно он выполняется всё время работы бота, и даёт сбой если пользователь неправильно использовал бота, или API Telegram не отправил вам ответ. Соответственно если завернуть пуллинг в tryCatch() , и перезапускать вашего бота в бота в блоке finally то при любой ошибке он будет самостоятельно перезапускаться.
Перед перезапуском бота не забывайте очистить его апдейты, что бы избавиться от ошибки, которая вызвала падение бота.
Выглядеть такой пуллинг будет следующим образом:
tryCatch( # запускаем пуллинг expr = updater$start_polling(), # действия при ошибке пуллинга error = function(err) # бот для оповещения bot Bot(token = bot_token("Токен вашего бота")) # чат для оповещения chat_id "Идентификатор чата в который необходимо отправить сообщение" # сообщение msg str_glue("*Бот упал*: Ошибка (__).") bot$sendMessage(chat_id = chat_id, text = msg, parse_mode = 'Markdown') # очищаем полученный апдейт бота, который вызвал ошибку updater$bot$clean_updates() # информация о том, что бот будет перезапущен bot$sendMessage(chat_id = chat_id, text = str_glue('*Перезапускаю бота* в '), parse_mode = 'Markdown') >, # действия которые будут выполненны в любом случае finally = # останавливаем пулинг updater$stop_polling() # перезапускаем скрипт бота source('C:\\telegram_bot\\my_bot.R') > )
В приведённом выше коде вам необходимо подставить токен созданного вами бота, и указать ID чата, в который бот будет отправлять уведомление о падении пуллинга.
В блок expr мы завернули процесс пуллинга, таким образом он постоянно контролируется конструкцией tryCatch .
Далее в блок error мы передали безымянную функцию, которая принимает всего один аргумент err , т.е. саму ошибку. Сообщение об ошибке мы получаем через err$message , и отправляем в указанный чат. С помощью updater$bot$clean_updates() мы очищаем очередь апдейтов бота, т.к. последний апдейт вызвал ошибку и падение нашего бота.
В блоке finally мы останавливаем пуллинг, и командой source(‘C:\\telegram_bot\\my_bot.R’) занова запускаем скрипт с ботом.
Такая схема позволяет боту очищаться и подниматься при любой ошибке пуллинга.
Очищать апдейты бота с помощью комманды updater$bot$clean_updates() можно так же и при запуске бота, указав эту команду сразу, после инициализации объекта бота.
Как перезапустить бота кодом, при нажатии inline кнопки(pytelegrambotapi)?
Когда я запускаю бота, с первого раза всё работает стабильно, но когда я нажимаю сбросить, и хочу начать по новой (начать вводить имя), то бот работает по предыдущему запросу, и думает что я ввёл фамилию. Соответственно сначала бот пишет «Введите имя», а потом он думает что я ввожу фамилию, и выдаёт результат «Вас зовут» + имя и фамилия введённая пользователем, затем такую ошибку:
2021-10-31 21:53:34,798 (__init__.py:663 MainThread) ERROR - TeleBot: "A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request : message to delete not found"
Как можно при нажатии inline кнопки сбросить работу программы, перезапустить бота и начать сначала? Чтобы при каждом нажатии на inline кнопку, скрипт будто закрыли и открыли заново. Не знаю как сделать это кодом, чтобы бот работал без остановки 24/7.
Отслеживать
задан 31 окт 2021 в 19:23
user464804 user464804
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Можно повторно вызывать функцию send_welcome прямо из inline_handler , которая ловит нажатие кнопки сброса.
А в самой функции send_welcome сбрасывать все зарегистрированные обработчики с помощью вызова bot.clear_step_handler(message) .
Тогда если send_welcome вызвана первый раз, никаких обработчиков еще не установлено и ничего не произойдет, а если повторно — они будут сброшены, как и требуется.
Вот пример рабочего кода:
@bot.message_handler(commands=["start"]) def send_welcome(message): global DELETEuserName1 bot.clear_step_handler(message) userName = bot.send_message(message.chat.id, "Здравствуйте, введите имя") DELETEuserName1 = userName.message_id bot.register_next_step_handler(userName, userSurNameFUNC) def userSurNameFUNC(message): global userName, DELETEuserSurName, DELETEuserSurName1 userName = message.text markup = types.InlineKeyboardMarkup() resetDataKey = types.InlineKeyboardButton("Сбросить", callback_data="resetData") markup.add(resetDataKey) userSurName = bot.send_message(message.chat.id, "Теперь введите фамилию", reply_markup=markup) DELETEuserSurName = userSurName.chat.id DELETEuserSurName1 = userSurName.message_id bot.delete_message(message.chat.id, message.message_id) bot.delete_message(message.chat.id, DELETEuserName1) bot.register_next_step_handler(userSurName, endProgrammFUNC) def endProgrammFUNC(message): global userSurName, DELETEendProgramm, DELETEendProgramm1 userSurName = message.text endProgramm = bot.send_message(message.chat.id, "Вас зовут " + userName + " " + userSurName) DELETEendProgramm = endProgramm.chat.id DELETEendProgramm1 = endProgramm.message_id bot.delete_message(message.chat.id, message.message_id) bot.delete_message(DELETEuserSurName, DELETEuserSurName1) @bot.callback_query_handler(func=lambda call: True) def inline_handler(call): if call.data == "resetData": bot.delete_message(call.message.chat.id, call.message.message_id) send_welcome(call.message) bot.infinity_polling()
Как перезапустить бота в телеграмме
Боты на тестовом тарифе ограничены числом пользователей. Тестовый тариф работает только у пяти тестировщиков.
Назначьте себя и коллег тестировщиками, чтобы бот отвечал вам, либо оплатите подписку.
Узнать подробнее о тарифах и сравнить их вы можете на странице Тарифные планы.
В логике бота есть ошибки
В Telegram
- Попробуйте перезапустить бота через команду /start и повторить исполнение ошибки.
- Внимательно проверьте причину ошибки: возможно, вы зашли в тупик (пустой экран, нет перехода на другой экран) или не исполнился компонент экрана из-за некорректного исполнения (некорректные данные, незаполненные данные).
Если бот не перезапускается через /start:
- Проверьте настройки токена.
- Нажмите «Сохранить» в конструкторе. Если бот не «отвис», попробуйте ещё раз отправить команду /start.
- Если бот всё ещё не «отвис», дайте боту @Botfather команду /revoke, получите новый токен и измените токен в Настройках.
В Viber, ВКонтакте и Одноклассниках
- Добавьте событие Шаблон, исполняющее Стартовый экран. Отправьте боту команду.
- Если бот перезапустился, проверьте причину ошибки: возможно, вы зашли в тупик (пустой экран, нет перехода на другой экран) или не исполнился компонент экрана из-за некорректного исполнения (некорректные данные).
Если бот не перезапускается:
- Проверьте настройки подключения платформы.
- Нажмите «Сохранить» в конструкторе. Если бот не «отвис», попробуйте ещё раз отправить команду из события Шаблон.
Во всех платформах сразу
Если бот перестал работать во всех платформах, но при этом не отправлял никаких ошибок, попробуйте нажать на кнопку «Сохранить» в конструкторе.
Проверьте почту на наличие уведомлений: возможно, бот был заблокирован из-за превышения лимита запросов (это бывает, когда бот зациклился) или за нарушения Пользовательского соглашения.
Проверьте, чтобы бот был открыт только в одной вкладке браузера.
Если бот не начал работать после вышеупомянутых действий, напишите в чат поддержки или на sup@botmother.com. Обязательно в письме укажите почту, на которую зарегистрирован бот, и прикрепите скриншоты диалога в Telegram.