В посте я поделюсь своим опытом разработки телеграм-бота для большого количества пользователей: разберу свои ошибки и шаги для их решения.
Одной из моих рабочих задач как программиста была автоматизация проведения викторины. Конечно, уже существуют специализированные бесплатные приложения, заточенные под эти задачи, но нужно было такое, в котором не было бы ничего лишнего, оно было всегда под рукой и такое привычное, чтобы не нужно было с ним разбираться. Выбор пал на телеграм бота и для того, чтобы он справлялся с большей нагрузкой. Было принято решение использовать асинхронную библиотеку aiogram.
Начнём с создания эхо бота на aiogram, тут нет ничего сложного, возьмём пример из документации:
Однако преимущество aiogram над python-telegram-bot и pyTelegramBotAPI в том, что он асинхронный, а значит может обрабатывать несколько запросов почти единовременно. Стандартная база данных sqlite отлично подходит для несложных проектов и уже входит в стандартную библиотеку питона, поэтому для начала я решил использовать её.
Отправка уведомлений в телеграм с помощью Github Actions
Через несколько часов работы приложение было написано, и мы с коллегами решили протестировать на себе его работоспособность. Бот запускался с использование технологии long polling, и запускался на локальном компьютере. Для небольшого количества человек этого вполне достаточно: 3-4 человека в секунду бот выдерживает без особых проблем.
Но, к сожалению или к счастью, во время проведения викторины боту посыпалось бОльшее количество запросов, на которое мы не рассчитывали, в связи с чем посыпались ошибки — необрабатываемые ошибки, связанные с одновременным постоянным запросом новых сообщений у сервера и обработкой уже полученных.
Решением этой проблемы стал переход на вебхуки. Для обеспечения бесперебойной работы разместим его на удалённом сервере. Отличным решением для этого является heroku: здесь можно управлять запуском приложения как с компьютера, так и с мобильного приложения, отслеживать логи и, что является наиболее важным для нас, настраивать вебхуки.
Алгоритм, для реализации эхо бота в данном случае занимает больше времени, но он достаточно прост:
2) Создаём новое приложение на странице Personal
Выбираем имя нашего приложения (у меня это «aiogram-echo-bot-webhook» — запомним его, оно нам ещё понадобится!), меняем сервер на Europe и нажимаем кнопку «create app».
Отлично, мы подготовили контейнер для нашего приложения! Передать туда код самого приложения можно несколькими способами, например через Heroku CLI или через GitHub. Разберём деплой через гитхаб, так как при любой возможности лучше использовать контроль версий
Перед деплоем на Heroku хорошо бы переписать наше приложение на вебхуки:
Что здесь происходит?
TOKEN, HEROKU_APP_NAME – мы считываем из переменных окружения, которые скоро добавим в наш проект.
WEBHOOK_HOST – доменное имя нашего приложения
WEBHOOK_PATH – часть пути, на который мы будем принимать запросы. Его следует придумать таким, чтобы не было возможности его угадать, во избежание фальсификации запросов. В нашем случае используется токен бота, так как его, также, следует держать в секрете.
WEBHOOK_URL – полный url адрес, на который будут принимать запросы.
WEBAPP_HOST – хост нашего приложения, оставляем локальный.
WEBAPP_PORT – порт, на котором работает наше приложение, так же считывается с переменных окружения, которое предоставляет Heroku.. Его мы не заполняем.
Асинхронная функция on_startup устанавливает вебхук для нашего телеграм бота, на который будут отсылаться уведомления о получении новых сообщений. И on_shutdown, наоборот, удаляет этот вебхук при выключении.
Далее мы переключаем вывод логов только на вывод только чисто информативной информации. И запускаем наш диспетчер, при этом при запуске опускаются все сообщения, которые были получены в то время, когда бот не работал, что указано в параметре «skip_updates».
Почти всё готово, но чтобы дать инструкции Heroku, как именно развернуть наше приложение, нужно создать файл «Procfile» и вставить туда следующий код:
web: python main.py
Здесь: web – значит, что наше приложение будет web приложением, а то, что идёт после «:» это строка, которую необходимо выполнить в первую очередь. Запустить наш файл main.py с помощью питона.
И ещё один файл, который необходим для запуска, это requirements.txt, в котором мы указываем все зависимости нашего проекта. Его создаём, выполнив команду pip freeze > requirements.txt .
Также можно указать, какую конкретную версию питона использовать: для этого создадим файл «runtime.txt» и впишем туда версию питона по шаблону «python-3.9.7»
Теперь подготовим переменные среды на Heroku: для этого переходим на вкладку «Settings» и жмём кнопку «Reveal Config Vars»
Здесь добавляем два поля:
BOT_TOKEN – токен, полученный у BotFather
HEROKU_APP_NAME – имя приложения созданного на heroku, которое мы с вами запоминали.
Отлично! Перейдём обратно к деплою: создадим репозиторий на гитхаб и зальём туда все файлы. На странице с нашим приложением в Heroku переходим во вкладку «Deploy». Кликаем на вкладку «Github». После того, как вошли в свой аккаунт гитхаб заполняем имя репозитория. Помним, что репозиторий должен быть не пустым!
Кликаем на кнопку «connect».
Для того, чтобы наше приложение обновлялось каждый раз, как мы заливаем новые изменения в ветку «master», можем нажать кнопку «Enable Automatic Deploys»
В первый раз, всё-таки придётся деплоить самим, для этого нажимаем кнопку ниже:
И дожидаемся окончания деплоя. При положительном результате, вывод будет, примерно таким:
Также можно посмотреть логи вверху окна кнопка «More»->«View logs»:
Переходим в наш бот и отправляем ему пару сообщений, если бот отвечает, значит всё в порядке, если нет, то переходим в логи и смотрим, в чём может быть ошибка.
На этом можно было бы остановиться, эхо-бот готов, но в реальном проекте нам понадобится сохранять различные данные из приложения. Для этого нужна база данных, как и в прошлый раз мы можем воспользоваться стандартной sqlite, но так как мы используем асинхронную библиотеку, то и запросы в бд должны быть асинхронными. Поэтому устанавливаем библиотеку databases для sqlite: pip install databases[sqlite] .
Разобьём код по модулям и подключимся к базе данных: создаём файл config.py и выносим туда все переменные (WEBHOOK_HOST, WEBHOOK_PATH и т.д.).
И ещё один модуль «db.py», в котором пишем следующий код:
from databases import Database database = Database(‘sqlite:///bot.db’) # где bot.db – путь к файлу базы данных
CREATE TABLE messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, telegram_id INTEGER NOT NULL, text text NOT NULL );
И дополняем модуль main.py:
Здесь мы после получения сообщения сохраняем его в базу данных, и затем просто возвращаем все сообщения, полученные от этого пользователя.
Не забываем обновить requirements.txt
Пушим всё на гитхаб, процесс сборки можно посмотреть на вкладке «Activity»
Проверяем в боте: отправляем пару сообщений, бот возвращает нам список сохранённых в базу.
Казалось бы, всё хорошо, но вдруг произошла непредвиденная ошибка и приложение необходимо перезапустить: зайдём на вкладку «Resources»
Нажимаем на карандаш, жмём переключатель, для выключения приложения и подтверждаем «confirm».
Вновь включаем таким же способом и пробуем отправить боту сообщения:
Ужас, мы потеряли все данные! Но почему, ведь они хранятся в базе данных? Это происходит потому, что деплой происходит в изолированных контейнерах и при каждом новом запуске создаётся новый контейнер, а как мы помним исходный файл с бд у нас был пустым.
В нашем случае данные нужны будут и после выключения, поэтому нам нужна изолированная от приложения база данных. К счастью на Heroku, помимо множества приложений, можно бесплатно развернуть и базу данных, например postgres.
Переходим в «elements»
Выбираем «Heroku Postgres»
Выбираем бесплатный план и вводим имя приложения, для которого подключаем бд, для того чтобы потом мы могли считывать строку подключения с переменных среды:
Переходим в переменные среды нашего приложения и видим, что там появился ключ «DATABASE_URL», который мы и будем использовать для подключения.
Для подключения к бд postgresql, установим пакет databases[postgresql]: pip install databases[postgresql] . Создаём исходные таблицы, но синтаксис создания таблицы немного поменяется:
CREATE TABLE messages ( id SERIAL PRIMARY KEY, telegram_id INTEGER NOT NULL, text text NOT NULL );
Также следует немного изменить метод «read» следующим образом:
async def read(user_id): results = await database.fetch_all(‘SELECT text ‘ ‘FROM messages ‘ ‘WHERE telegram_id = :telegram_id ‘, values=) return [next(result.values()) for result in results]
Вновь обновляем requirements.txt и пушим на гит.
Дожидаемся окончания деплоя, если приложение не запущено, то запускаем его и отправляем проверочные сообщения боту:
Получаем сообщения, всё отлично! Как и в прошлый раз возникает непредвиденная ситуация, из-за которой приходится перезапускать приложение. Перезапускаем, отправляем ещё одно сообщение и …
Видим, что все данные сохранились в бд!
Вот всё и готово! А дальше всё зависит только от ваших предпочтений: для чего и под какие задачи разработать функционал бота, но вы можете быть уверенны, что его производительность будет на высоте, а данные надёжно сохранены.
Исходный код приложения размещён в репозитории: ссылка.
Источник: newtechaudit.ru
Создаем телеграм бота с помощью serverless на nodejs
Бесплатный хостинг Telegram-бота на Google Cloud Platform
При написание телеграмм ботов столкнулся с вопросом, как быстро и бесплатно сделать так, чтобы бот работал постоянно. Варианты с Heroku и Pythonanywhere имеют слишком маленькие лимиты, если у вас более одного бота. Поэтому я решил воспользоваться GCP. Платформа предоставляет бесплатно 300$ на год + огромные скидки при использование этих средств(до 94%).
Как захостить вашего бота?
Шаг 1. Регистрация на GCP
Переходим на сайт GCP и нажимаем Get started for free.
Вводим свои данные и карточку. Деньги с карточки не будут списываться, если вы сами не активируете платную подписку.
Шаг 2. Создаём виртуальную машину
После регистрации вы окажетесь на главной странице сервиса. Вам необходимо выбрать в разделе Ресурсов вкладку Compute Engine.
Необходимо создать новый экземпляр.
Если вы не будете развертывать БД на виртуальной машине, то можете взять g1-small, иначе советую n1-standart.
Необходимо будет выбрать также ОС. Я выбрал Debian GNU/Linux 9 (stretch).
Всё, ВМ создана. Обычные её развертывание занимает от 1 до 5 минут.
Шаг 3. Настройка виртуальной машины
Вы можете подключиться по SSH со своего ПК или же взаимодействовать через платформу.
Для этого нажмите на SSH.
У вас откроется терминал Linux в новом окне.
Теперь перейдем к настройке. Сначала вводим команду:
sudo apt-get update
для обновления информации об новейших версиях пакетов.
sudo apt-get install python3-setuptools sudo apt-get install python3-pip
Сам Python устанавливать не нужно, он уже есть.
Теперь необходимо установить все необходимые библиотеки. Есть небольшой нюанс, все библиотеки необходимо устанавливать дважды:
pip3 install ‘name_of_package’
для использования через коману python3, и
sudo pip3 install ‘name_of_package’
для systemd. Данная утилита поможет вам запустить бота и перезапускать его, если он упадёт.
Самый простой способ запускать бота через python3, но он будет выключаться, если вы будете отключаться. Можно использовать screen, но бот не будет сам перезапускаться. Также можно использовать crontab с проверкой порта, но мне кажется этот вариант сложнее, чем systemd.
Шаг 4. Заливаем бота на сервер
Есть два способа залить вашего бота. Если вы не дружите с Git, вы можете просто заархивировать бота в .tar и залить его на сервер:
После этого разархивируем его командой:
tar -xvf yourfile.tar
Теперь ваш бот хранится в папке с названием архива.
Второй способ через Git. Я думаю, не стоит объяснять как это сделать людям, которые умеют его использовать.
После установки его командой:
sudo apt install git
Вы можете клонировать его себе на ВМ.
После этого переходим к настройке systemd. Для этого переходим в его директорию:
cd /etc/systemd/system
И создаём файл bot.service:
sudo nano bot.service
Вписываем в открывшиеся окно следующее:
[Unit] Description=Telegram bot ‘Имя бота’ After=syslog.target After=network.target [Service] Type=simple User=root WorkingDirectory=/home/название вашего юзера/название папки в которой лежит бот ExecStart=/usr/bin/python3 /home/название вашего юзера/название папки в которой лежит бот/bot.py RestartSec=10 Restart=always [Install] WantedBy=multi-user.target
Закройте и соханите файл. Закрывается с помощью команды Ctrl+X.
После этого введите команды по очереди:
sudo systemctl daemon-reload sudo systemctl enable bot sudo systemctl start bot sudo systemctl status bot
Если всё будет хорошо, вы увидите примерно следующее:
Всё, теперь ваш бот работает самостоятельно. Надеюсь моя статья поможет вам захостить вашего бота.
P.S.
1.Проверьте вашего бота на ошибки
Запустите вашего бота и проверьте его работу прежде, чем запускать его через systemd. Для этого перейдите в папку с ботом и запустите через python.
cd python3 bot.py
2.Добавьте в файлы с py-скриптами кодировку
#!/usr/bin/env python # -*- coding: utf-8 -*-
Вставить в начале файла.
3.Ошибки в systemd
Если вы проверяли бота на ошибки и он нормально работал, но он не хочет запускаться в systemd, то вы можете посмотреть логи и понять в чём ошибка просмотрев файл:
sudo nano /var/log/syslog
Вы можете скачать этот файл и просмотреть на своём компьютере через Notepad++.
4.Апдейт бота
Если вы хотите дописать или залить новую версию бота, то введите команду:
sudo systemctl stop bot
Провидите все необходимые манипуляции. А потом введите следующие команды, чтобы он опять заработал:
sudo systemctl daemon-reload sudo systemctl start bot sudo systemctl status bot