Телеграм-бот на NodeJS. Автоматическая рассылка.
Tags: telegram, node
Published: 2021-04-04 15:46:12

В этой заметке напишу о том, как я научил бота делать автоматическую еженедельную рассылку. Задача перед ботом такая: Каждую пятницу он бодро должен собрать некий материал, поднимающий настроение и сделать рассылку всем своим подписчикам.
Поэтому задачу можно разделить на три больших блока:
1. Один раз в неделю собрать информацию
2. Собрать всех подписчиков
3. Разослать этим подписчикам информацию.

С первым пунктом на первый взгляд проблем нет: Делаем запрос к некоему сборщику (который никак не связан с ботом), он должен вернуть массив или объект записей для новой рассылки. Проблема в другом: когда и как запускать этот сборщик.
Можно решать задачу "в лоб" - поставить setInterval или setTimeout и вызывать некую веб-службу, может даже обращаться к api-методу. Но здесь есть очевидный минус: При обновлении скриптов или перезапуска сервера или как в случае с некими популярными хостингами, использующими [serverless computing](https://ru.wikipedia.org/wiki/%D0%91%D0%B5%D1%81%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F) наше приложение после бездействия выключится и таймеры с интервалами исчезнут.
Поэтому первый пункт я советую делать не на уровне NodeJS, а на уровне сервера и помогут нам в этом знания настройки cron'a. Если не знаете, как настраивать, то спросите примеры у [гуру](https://crontab.guru/) или на каком-нибудь [другом ресурсе](https://crontab-generator.org/).
Если Ваш бот развёрнут на AWS, то можно написать к примеру такую конфигурацию в файле serverless.yml :
```yml
  # Каждый день в шесть утра запустить рассылку
  sendMail:
    handler: handler.sendMail
    events:
      - http:
          path: sendMail
          method: post
          cors: true
      # Запускать эту функцию каждый день в 6 утра (время местное у сервера)
      - schedule: cron(0 6 * * ? *)
```
Здесь говорится о том, что у нас уже есть POST-метод sendMail на нашем сервере и мы хотим его запускать каждый день в шесть утра.
У меня бот развёрнут на heroku и там нет этих возможностей, зато справка heroku говорит, что можно воспользоваться [GitHub Actions](https://docs.github.com/en/actions). В проекте на гитхабе создал каталог _.github/workflows_ , в нём файл _manualPOST.yml_
```yml
name: Cron for friday mailing
on:
  schedule:
    - cron: "0 6 * * 5"
jobs:
  cron:
    runs-on: ubuntu-latest
    steps:
      - name: Call friday sheduler
        run: curl -X POST https://telegram-bot.herokuapp.com/api/sendMail
```
Здесь говорится, что каждую пятницу, в шесть утра, будет вызываться https://telegram-bot.herokuapp.com/api/sendMail , который отвечает за рассылку.
*Мой бот находится не по адресу telegram-bot.herokuapp.com , этот адрес я привёл для примера.*
Сейчас текст sendMail приводить не буду, позже, возможно в комментах, дам ссылку на гитхаб. В написании этой функции нужно учитывать особенности serverless functions и помнить, что срок их жизни весьма недолгий. Поэтому у меня там запускаются несколько задач в промисах: сбор подписчиков и сбор материала. Затем, когда Promise.all вернёт мне результаты, запускаю другую службу- рассылки адресатам данных. Таким образом сохраняются требования системы о том, что службы сами по себе работают недолго.

Второй и третий шаги рассылки можно позже подсмотреть в гитхабовских проектах.