I have a lengthy task that needs to run in the background in my Rails 4.2.6 app. Unfortunately, the job is not being sent to the background using Active Job. I've generated a job:
class PhotoProcessorJob < ActiveJob::Base
queue_as :default
def perform(*args)
::Photo.process_photos
end
end
which calls a method on my Photo class (stored in config/initializers):
class Photo
require 'zxing'
require 'csv'
@tablePath = Dir.glob("#{Rails.root.to_s}/tmp/photo_processing/*.csv")[0]
@output = "#{Rails.root.to_s}/tmp/photo_data.csv"
def self.getStudentInfo(id)
CSV.foreach(@tablePath, headers: true) do |row|
if row["Student ID"] == id
return row
else
next
end
end
end
def self.writeInfoToFile(data, file)
first_name = data["First Name"]
last_name = data["Last Name"]
student_id = data["Student ID"]
grade = data["Grade"]
email = data["Email"]
photo = file.to_s
CSV.open(@output, "a+") do |csv|
csv << [first_name, last_name, student_id, grade, email, photo]
end
end
def self.process_photos
extensions = %w(.jpg .jpeg .png .gif .tif)
studentInfo = nil
newfile = false
if File.exist?(@output)
outfile = CSV.new(File.read(@output))
if outfile.count == 0
newfile = true
end
else
newfile = true
end
if newfile
CSV.open(@output, "wb") do |csv|
csv << ["First Name", "Last Name", "Student ID", "Grade", "Email", "Photo"]
end
end
Dir.glob("#{Rails.root.to_s}/tmp/photo_processing/*").each do |file|
if file.match(/#{extensions.join("|")}/)
id = ZXing.decode File.new(file)
unless id.nil?
studentInfo = getStudentInfo(id)
else
writeInfoToFile(studentInfo, file) unless studentInfo.nil?
end
end
end
end
end
and called from a controller:
class ProcessingController < ApplicationController
def finish
PhotoProcessorJob.perform_later
end
end
I'm trying to use the Active Job Inline backend and so do not have any queue libraries installed. The problem is that the "finish" view is delayed while the process_photos
method runs rather than it being sent to the background and the view being displayed immediately. This results in a 502 error within Nginx caused by upstream prematurely closed connection
presumably because the process_photos
task is taking too long to complete.
Have I done something wrong with my Active Job setup?
To quote the docs:
Rails by default comes with an "immediate runner" queuing implementation. That means that each job that has been enqueued will run immediately.
What that means is that by default, active job will run in the main thread, not in "the background". This is a common gotcha. Basically active job is just a common API across multiple queueing backends.
TL;DR You have to set up a queueing backend like Sidekiq.
Otherwise, your setup looks great, textbook even.