Міграція з Resque на Sidekiq у Rails

pic

Мотивація

Мій 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