Rails фоновые задачи с Sidekiq
Допусти нам нужно по требованию выполнить импорт данных из CSV и отобразить результаты. При стандартном подходе в контроллере создадим метод и выполним обработку файла.
class HomeController < ApplicationController
require 'csv'
def upload
csv_path = File.join Rails.root, 'db', 'data.csv' CSV.foreach(csv_pathm headers: true) do |item|
Element.create(name: item[0], value: item[1])
end
flash[:notice] = 'All elements created!' redirect_to elements_path
end
def destroy_all
Element.destroy_all
end
end
При таком подходе, если данных будет достаточно много, пользователь получит блокировку браузера на время выполнения и это может длиться достаточно долго. Конечно можно использовать ajax, но сейчас разговор не о нём. На некоторых проектах мы вообще можем получить ошибку Request Time-out
.
Теперь решим эту задачу с использованием Sidekiq. Мы не будем использовать основной процесс приложения для обработки, а передадим задачу в фоновому процессу Sidekiq.
Создадим worker
# app/workers/upload_worker.rb
class UploadWorker
include Sidekiq::Worker
sidekiq_options retry: false
require 'csv'
def perform(csv_path)
CSV.foreach(csv_path, headers: true) do |item|
Element.create(name: item[0], value: item[1])
end
end
end
class DestroyWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform
Element.destroy_all
end
end
Важно отметить опцию retry: false
- это важно, иначе sidekiq будет повторять работу при возникновении ошибки, что в данном случае совсем не нужно.
Теперь мы сможем перекинуть работу на Sidekiq
# app/controllers/home_controller.rb
class HomeController < ApplicationController
def upload
csv_path = File.join Rails.root, 'db', 'data.csv'
UploadWorker.perform_async(csv_path)
flash[:notice] = 'Element getting added to app'
redirect_to elements_path
end
def destroy_all
DestroyWorker.perform_async
flash[:notice] = 'Elements getting removed from app'
redirect_to elements_path
end
end