Мотивація
Мій Rails-додаток використовував Resque для фонових задач, але я вирішив замінити його на Sidekiq, тому що:
- Sidekiq може ефективніше використовувати серверні ресурси завдяки багатопоточності.
- Веб-інтерфейс Sidekiq має менше залежностей, ніж Resque.
- Я вважаю, що Sidekiq краще підтримується і має більш активну підтримку.
Кроки міграції
1. Налаштування Sidekiq
Поки Resque працював у продакшн-режимі, я додав налаштування Sidekiq і спробував окремо запустити його в продакшн-режимі.
Додайте sidekiq
у Gemfile
.
gem 'sidekiq'
Додайте маршрути для веб-інтерфейсу Sidekiq в routes.rb
require "resque_web"
require 'sidekiq/web'
Rails.application.routes.draw do
mount ResqueWeb::Engine => "/resque_web"
mount Sidekiq::Web => '/sidekiq'
# ...
end
Створіть config/initializers/sidekiq.rb
(увага: використовуйте інший Redis, ніж для Resque, якщо це можливо)
require 'sidekiq'
Sidekiq::Web.use Rack::Auth::Basic do |username, password|
# Захист від атак за часом:
# - Див. https://codahale.com/a-lesson-in-timing-attacks/
# - Див. https://thisdata.com/blog/timing-attacks-against-string-comparison/
# - Використовуйте & (не використовуйте &&), щоб уникнути короткого замикання.
# - Використовуйте digests, щоб уникнути витоку інформації про довжину (див. також ActiveSupport::SecurityUtils.variable_size_secure_compare)
ActiveSupport::SecurityUtils.secure_compare(::Digest::SHA256.hexdigest(username), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_USERNAME"])) &
ActiveSupport::SecurityUtils.secure_compare(::Digest::SHA256.hexdigest(password), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_PASSWORD"]))
end
# https://github.com/redis-rb/redis-client#configuration
redis_client_config = { url: ENV['SIDEKIQ_REDIS_URL'] }
if Rails.env.production?
redis_client_config.merge!(
ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
)
end
Sidekiq.configure_server do |config|
config.redis = redis_client_config
end
Sidekiq.configure_client do |config|
config.redis = redis_client_config
end
Якщо ви використовуєте rspec
, додайте rspec-sidekiq
у Gemfile.
group :test do
gem 'rspec-sidekiq'
end
Додайте наступну конфігурацію до spec/rails_helper.rb
або окремого файлу, наприклад, spec/support/sidekiq.rb
.
RSpec::Sidekiq.configure do |config|
# Очищає всі черги задач перед кожним прикладом
config.clear_all_enqueued_jobs = true # за замовчуванням => true
# Чи використовувати кольори терміналу при виведенні повідомлень
config.enable_terminal_colours = true # за замовчуванням => true
# Попередження, коли задачі не додаються до Redis, а до масиву задач
config.warn_when_jobs_not_processed_by_sidekiq = true # за замовчуванням => true
end
Додайте PingJob
для тестування.
class PingJob
include Sidekiq::Job
def perform
Rails.logger.info '-- PingJob виконано'
end
end
Розгорніть ці зміни в продакшн і спробуйте виконати PingJob
з Sidekiq
bundle exec rails c
PingJob.perform_async
Якщо в логах продакшн-сервера з'явиться запис PingJob виконано
, значить все працює. Також перевірте, чи можете ви отримати доступ до веб-інтерфейсу Sidekiq за адресою /sidekiq
за допомогою Basic Auth.
2. Замініть задачі
Після налаштування Sidekiq я почав замінювати всі існуючі задачі Resque на задачі Sidekiq.
В принципі, потрібно змінити три речі:
- Замість спадкування від
ActiveJob::Base
використовуйтеinclude Sidekiq::Job
- Замість
perform_later
використовуйтеperform_async
- Замість будь-яких аргументів ActiveRecord використовуйте глобальні ID.
ex)perform(user)
потрібно замінити наperform(user_id)
Приклад до змін:
class UserCompleteJob < ApplicationJob
def perform(user)
user.complete!
end
end
# user = User.find(user_id)
# UserCompleteJob.perform_later(user)
Приклад після змін:
class UserCompleteJob
include Sidekiq::Job
def perform(user_id)
user = User.find(user_id)
user.complete!
end
end
# UserCompleteJob.perform_async(user_id)
Також потрібно оновити config.active_job.queue_adapter
у application.rb
або в іншому місці з :resque
на :sidekiq
class Application < Rails::Application
# ...
config.active_job.queue_adapter = :sidekiq
# ...
end
Проведіть ретельне тестування перед тим, як відправляти зміни в продакшн.
3. Видалення Resque
Коли всі задачі будуть замінені на Sidekiq і працювати бездоганно, можна приступати до видалення Resque з вашого коду.
Видаліть залежності гемів, конфігураційні файли та маршрути для веб-інтерфейсу тощо.
Ось і все для міграції 🎉
Перекладено з: Rails: Migration from Resque to Sidekiq