На одному проекті інтернет-магазину виникали помилка після завершення оформлення замовлення. В момент надсилання email повідомлення адміністратору магазину про нове замовлення, відбулась проблема з'єднання із SMTP-сервером, в наслідок чого користувач бачив у браузері помилку
Теоретично такого не мало б відбутися, оскільки за змовчанням у ActiveJob використовується ansync адаптер і виклик методу deliver_later мав би виконатися у фоновому режимі
1 2 3 4 5 6 7 |
def send_admins_notification order SpreeMailer.order(order).deliver_later respond_to do |format| format.html { } format.js { } end end |
Але ActiveJob виконувався синхроно, було б добре розібратися чому саме так.
Для вирішення даної проблеми, використаємо gem sidekiq який дозволяє rails породжувати нові процеси, які будуть працювати у фоновому режимі. В основі гема задіяна модель акторів. Його інсталяція досить проста – додати гем в Gemfile:
1 |
gem 'sidekiq' |
Вказуємо сервер черги у config/application.rb:
1 |
config.active_job.queue_adapter = :sidekiq |
Інсталюємо Redis сервер
1 |
sudo apt-get install redis-server |
Оскільки отримання email'а є важливим, задаю 100 спроб у разі невдачі
1 2 3 |
class SpreeMailer < ApplicationMailer include Sidekiq::Worker sidekiq_options retry: 100 |
В development середовищі запускається досить просто:
1 |
bundle exec sidekiq |
Перевірка показала асинхронну роботу
Для деплоя добавляємо у Gemfile gem:
1 |
gem 'capistrano-sidekiq' , group: :development |
Добавляємо в Capfile
1 2 |
require 'capistrano/sidekiq' require 'capistrano/sidekiq/monit' |
Як бачимо у нас буде інтегація з monit, який буде запускати sidekiq у разі його падіння, тому на продакшені інсталюємо його
1 2 |
sudo apt-get update sudo apt-get install monit |
В /etc/monit/monitrc дозволяємо http для localhost'у
1 2 3 4 |
set httpd port 2812 and use address localhost allow localhost |
Та перезапускаємо
1 |
/etc/init.d/monit restart |
Action Mailer використовує чергу mailers, задаємо її для sidekiq у config/deploy.rb
1 |
set :sidekiq_queue, 'mailers' |
Далі деплоємо проект