Привет, читатели, это третья часть обучающих постов о написании Slack App с использованием чистого Ruby (на самом деле не полностью чистого, как оказалось). 

Если вы не знакомы со списком частей, то вот он (со ссылками): 

  1. Написание приложения локально через Sinatra и ngrok.

  2. Добавление чартов или как делать рендер фронта на сервере

  3. Тусовка приложения с таким гостем как Heroku (Мы здесь).

Положение дел таково, что сейчас бот висит на локальном сервере, запускаю вручную. Ребята из моего workspace могут пользоваться функциями бота, когда он включен, с этим нет проблем.

Проблема или недостаток проваляется в том, чтобы бот был доступен 24/7. Как можно пользоваться чем-либо, если оно имеет неоднозначную доступность. Например, ты выходишь утром на маршрутку и не знаешь наверняка будет она или нет. Тогда, вероятно, ты выберешь иной транспорт для передвижения; что-то более надежное.

Максимально переложив ответственность за онлайн своего приложения, ты сможешь сфокусироваться на других задачах, думать больше о новых фичах и новых приложениях. Ведь попробуй просто представить себе, как ты с утречка начинаешь поднимать 20 ботов на своём бедном Lenovo в надежде, что сегодня ни свет, ни интернет не выключится? Представил? А теперь представь если 20 ботов висят на сервере и ты с утра заходишь, смотришь какой у них статус с помощью удобного дашборда. Так и 21е приложение не за горами будет :)

Понимаю, всё звучит так классно, но ты возразишь, а деньги на сервер зачем выбрасывать? Тебе кажется, что твой бот только тебе и интересен, зачем же тратиться. А если я скажу что есть сервис, бесплатный, качественный, функциональный, который в начале кажется сложным, но как всё сложное, его нужно лишь понять и станет простым и отличным помощником.

Выглядит как промо за 50$, но на самом деле я был поражен лишь тем фактом, что если зайти на цены, то там есть раздел Hobby. Это на моей памяти первый случай, когда сервис есть в бесплатном виде, чтобы поддерживать начинания разработчиков, и потом, когда идея окажется работоспособной, тут же можно понемногу увеличивать возможности своего сервиса. Только за это уже можно читать дальше, разве нет?

Шаг 1 : Создание приложения в Heroku

Заходим по адресу. Регистрируемся. Нажимаем New -> Create new app (Рисунок 1).

Рисунок 1 : Heroku Dashboard
Рисунок 1 : Heroku Dashboard

Вводим название своего приложения (особо не напрягайся как оно будет называется, это просто идентификатор среди других твоих приложений в этом сервисе).

На следующей вкладке нам интересен блок Deployment methods (Рисунок 2), выбираем Heroku Git.

Рисунок 2 : Deployment methods
Рисунок 2 : Deployment methods

После выбора, внизу загрузиться инструкция к соответствующему методу выгрузки нашего приложения (Рисунок 3):

Рисунок 3 : Выгрузка через Heroku Git
Рисунок 3 : Выгрузка через Heroku Git

Собственно, сейчас выполним эти команды.

Шаг 2 : Выгрузка приложения в Heroku

Открываем терминал и переходим по пути к нашему проекту, который собираемся выгружать. В моём случае, я использую RubyMine, так что терминал в IDE уже открыт по адресу проекта.

Собственно, выполняем команды сверху -> вниз.

  • heroku login -> у тебя откроется окно в браузере, после авторизации в консоле появится сообщение об этом.

  • Если у тебя ещё не создан git репозиторий в корне проекта - то создай его, у меня он уже есть, так что я пропущу команды по его созданию

  • Добавляем ссылку на heroku-git-репозиторий heroku git:remote -a habr-one-love

  • Добавляем все файлы, делаем коммит и отправляем (push) на этот репозиторий.

Push может занять некоторое время, ведь теперь, для твоего приложения, heroku создал GitHub action, и на каждый push в ветку master будет делать build и run твоего приложения. Чтобы не сидеть и не смотреть в экран, ожидая окончания push - перейдем к знакомству с командами heroku.

Шаг 3 : Основы, которые необходимы для работы с нашим приложением

  1. Для отправки любых изминений на heroku нужно делать push через git. По-другому лучше не будет, это самый удобный из доступных способов. Тестируем на локалке, пушим - видим на дев сервере.

  2. Команды, которые могут быть полезными чаще других :

    • heroku logs --tail - отобразит лог событий с твоим приложением в терминале (консоли).
      Эти события можно посмотреть через Heroku Dashboard на сайте. Для этого - переходим по ссылке к списку приложений и выбираем своё приложение. Нажимаем More->View logs (Рисунок 4).

      Рисунок 4 : Внутри приложения Heroku
      Рисунок 4 : Внутри приложения Heroku
    • heroku local - для запуска приложения локально, используя список команд указаных в Procfile (создадим ниже).
      Опционально можно указать ещё какой именно процесс вы хотите запустить, по-умолчанию это web.

  3. Procfile - это файл-список команд, которые будут выполнены, при старте твоего приложения.

  4. `Dyno` - процессы, которые описаны в Procfile.

  5. `Adds-on` - дополнительное ПО, например - PostgreSQL устанавливается по-умолчанию.

  6. `Buildpacks` - скрипты, которые будут выполняться во время этапа билда приложения, то есть, каждый раз при push, но перед Procfile. Для нас интересно два buildpack - ruby и chrome headless. Так как по-умолчанию ни ruby, ни браузера на сервере нет.

Шаг 4 : Настраиваем Procfile

Добавляем файл в корень проекта, называем его, угадайте как .... Procfile. Записываем туда одну команду :

web rackup config.ru -p ${PORT:-5000}

Этой командой мы запустим наше приложение.

Шаг 5 : Добавляем ENV

heroku config

Эта команда покажет какие сейчас есть переменные окружения для приложения. Нам нужно добавить сюда переменные, которые сейчас находятся в файле `env`. Для этого использовать такую команду :

heroku config:set ключ=значение

Например :

heroku config:set SLACK_CLIENT_ID=123456789000.1123555869121

По такому же процессу добавляем все переменные окружения :

  • SLACK_CLIENT_ID

  • SLACK_API_SECRET

  • SLACK_VERIFICATION_TOKEN

  • SLACK_REDIRECT_URI

Для получения SLACK_REDIRECT_URI нам нужно узнать адресс приложения. Чтобы узнать его, заходим в Dashboard (Рисунок 4) и нажимаем Open App. В открывшейся вкладке копируем адрес, это и есть адресс приложения. Добавляем /finish_auth
и вот он наш redirect uri.

После заполнения всех ключей, можем удалить `env.rb` (так же удалить require этого файла в коде), теперь наши sensetive данные хранятся безопастно!

Шаг 5 : Обновляем Database данные

Теперь у нас БД будет не локальная, а хранится на Amazon AWS через Heroku. Поменяем данные для доступа в эту БД. Переходим в файл `Database.rb` в функцию init.

Как найти значения новой базы данных ?

  1. Переходим в Dashboard Heroku;

  2. Блок Adds-on;

  3. Выбираем Heroku Postgres;

  4. Нажимаем на:

  5. Откроется Adds-on (Рисунок 5);

    Рисунок 5 : Информация о Adds-on
    Рисунок 5 : Информация о Adds-on
  6. Переходим на вкладку Settings;

  7. Нажимаем View Credentials.

У меня, пока писал пост, появилась идея записать эти данные в Heroku Config, чтобы не хранить в коде доступы.

Заменим в фунции init все параметры на :

  def init
    @db = PG.connect(
        host: ENV['HU_POSTGRES_HOST'],
        dbname: ENV['HU_POSTGRES_DBNAME'],
        user: ENV['HU_USER_USER_ENV'],
        password: ENV['HU_POSTGRES_PASS']
    )
  end

И добавим, по-аналогии с переменными для Slack API, их - испольуя доступы в базу с Heroku.

Шаг 6 : Проверяем деплой и подключаем Slack

Делаем Push изменений на heroku. Смотрим лог, наблюдаем картину как на Рисунке 6. Если всё так, то значит ты, как и я, сделал всё правильно!

Рисунок 6. Качественный лог
Рисунок 6. Качественный лог

Поскльку адрес бота с localhost поменялся, то нужно зайти в настройки приложения в Slack API и там поменять адрес везде, где только можно. Для удобства, выпишу список потенциальных мест :

Напоминаю, адрес вашего приложения можно получить с помощью Heroku Dashboard!

  • Slash Commands

  • OAuth & Permissions > Redirect URLs

  • Interactivity & Shortcuts > Interactivity

  • Event Subscriptions

Переустанавливаем приложение, чтобы создалась таблица с доступами в новой БД.

Также, я переписал модуль базы данных для своего приложения, что именно поменялось, можно найти по этим коммитам : главный, фикс, фикс.

Теперь снова делаем коммит + пуш в Heroku.

Заходим в слэк и прописываем команду, которую мы создавали ранее :

/who_am_i
Рисунок 7. Ответ который мы заслужили!
Рисунок 7. Ответ который мы заслужили!

Если твой результат частично совпал с результатом на Рисунке 7 - поздравляю! Ты успешно разместил своё приложение на Heroku!

Шаг 7 : Технические нюансы моего приложения

В прошлом уроке я рассматривал как рендерить фронт на сервере, но делал это на локальной машине, где уже есть бинарные файлы для браузера. Что же касаемо реального сервера ? Там их нет по определению, но можно ведь и добавить :)

Я расскажу как это делать с помощью Heroku Buildpacks.

  1. Заходим в панель управления приложением Heroku.

  2. Выбераем вкладку Settings.

  3. Там ищем блок Buildpacks (Рисунок 8)

    Рисунок 8. Buidpacks в меню Settings
    Рисунок 8. Buidpacks в меню Settings
  4. Клацаем на Add buildpack.

  5. Вписываем URL : https://buildpack-registry.s3.amazonaws.com/buildpacks/heroku/google-chrome.tgz

Всё, теперь, при следующем билде, у нас загрузится новый buildpack, в котором установиться ядро google-chrome.

Теперь нужно немного подправить сам код по рендеру графика, чтобы он нашел файл этого браузера, в файле commands.rb :

 browser = Ferrum::Browser.new(
        :browser_path => "/app/.apt/usr/bin/google-chrome"
    )

в этом же файле поменяем GET запрос на скрин графа, с этого:

get '/graph_image.png' do
    send_file 'Components/Graph/result.png'
  end

на такой:

  get %r{/graph_image/(?<ts>\w+)} do
    send_file "/app/#{params[:ts]}_graph.png"
  end

Идея в том, чтобы каждый скрин подписывать timestamp-ом, когда он создан, а не перезаписывать один и тот же файл. К тому же, изменился путь к файлу, ведь в Heroku нельзя сохранять файл так, как он сохранялся ранее. Поменяем процесс сохранению скриншота к такому виду :

    graph_ts = Time.now.to_i
    browser.screenshot(path: "/app/#{graph_ts}_graph.png")

Так же поменяем сам шаблон :

{
  "type": "modal",
  "title": {
    "type": "plain_text",
    "text": "Граф"
  },
  "blocks": [
    {
      "type": "image",
      "image_url": "http://<%= host %>/graph_image/<%= graph_ts %>",
      "alt_text": "Сер Граф"
    }
  ]
}

Эти изменения описаны в комитах 1,2 и 3.

Коммитим и пушим на Heroku! Отныне build приложения будет занимать больше времени из-за нового buildpack.

Теперь можно идти в Slack workspace и писать /graph.

Если всё сделали правильно, то и ответ получим тот, который ожидали !

Результаты

После успешного прохождения всех этапов, вы, как и я должны получить :

  • Выгруженую в Heroku приложуху которая умеет общаться с Slack API, рендерить html и просто быть в онлайне 24/7.

  • Переменные окружения теперь находятся в более безопастном месте.

  • Модуль базы данных был переписан в класс и теперь может создавать базы данных основываясь на динамических функциях (звучит как что-то особенное, но я не знаю как ещё назвать это, кто смотрел коммиты тот поймёт).

  • Функционал получения графиков обновлен.

Можно резюмировать успешное прохождения цикла из 3х статей по разработке Slack Ruby бота на Sinatra, которое успешно работает на Heroku и имеет функционал по работе с Google Chrome Headless, Slack Modals и Slack Slash Commands. Кроме того - умеет добавлять и поддерживать несколько пользоватей.

С текущего момента, вы сами уже будете иметь необходимые навыки для дальнейшего развития этого приложения, но, если у Вас есть интерес к моим статьям и этой теме, я могу и дальше описывать интересные технологии и решения, которые мне встретятся в будущем. Сейчас, к слову, есть материал для написания таких статьей :

  • Рефакторинг реального приложения на Ruby on Rails, так как Sinatra уже создает больше неудобств, чем удобств по работе с ним.

  • Добавление и настройка Home Page для Slack App.

  • Интеграция Slack App с Jira для авто-трекинга времени по задачам.

Ссылка на Git репозиторий, кому нравиться - ставьте звезды, я старался и это лучший способ меня поддержать!

Комментарии (0)