dsp_099 dsp_099 - 4 months ago 15
Ruby Question

Resque tasks always fail - uninitialized job constants?

I've tried using Resque before and was met with unmitigated failure. I'm revisiting it again with the same results...

resque.rake
:

require "resque/tasks"

task "resque:setup" => :environment


test.rb
:

require 'resque'

class FileWorker
@queue = :save_to_file

def self.perform(str)
File.open('./' + Time.now.to_s + '.txt', 'w+') do |f|
f << "test 123"
end
end
end

Resque.enqueue(FileWorker, "12345567".split('').shuffle.join)


Gemfile
:

gem 'resque'
gem 'rake'


It seems like running
test.rb
on its own successfully queues the job:

enter image description here

However, running
rake resque:work QUEUE='*'
in the same folder results in a warning,


WARNING: This way of doing signal handling is now deprecated. Please
see http://hone.heroku.com/resque/2012/08/21/resque-signals.html for
more info.


As well as the task being added to "failed" queue with the following reason:
"exception":"NameError","error":"uninitialized constant FileWorker"


How do I get this to work? Seems like something quite obvious but there's tons of tutorials about Resque spanning many years - some painfully out of date and none explaining how to run workers so they don't fail.

Thanks in advance.

Answer

When you enqueue a task with Resque, what is stored on Redis is just the name of the job class (as a string) along with the arguments (again as strings) in a JSON object.

When a worker then tries to perform the task, it needs to be able to create an instance of the job class. It does this by using const_get and const_missing. This is where the error you are seeing occurs, since the worker does not have the definition of FileWorker available to it.

The error is the same as if you tried to get an unknown constant in irb:

> Object.const_missing "FileWorker"
NameError: uninitialized constant FileWorker

The solution is to make sure the definition of FileWorker is available to your workers. The simplest way to do this would be to just require test.rb from your Rakefile (or resque.rake). In your code this would involve adding another task to the queue, so you might want to move the FileWorker code to its own file where it can be required by both the rake file and the code enqueuing jobs.

test.rb:

require 'resque'
require './file_worker'

Resque.enqueue(FileWorker, "12345567".split('').shuffle.join)

Rakefile (note the :environment task only makes sense if you are using Rails and will give errors otherwise):

require "resque/tasks"
require "./file_worker"

file_worker.rb:

class FileWorker
  @queue = :save_to_file

  def self.perform(str)
    File.open('./' + Time.now.to_s + '.txt', 'w+') do |f|
      f << "test 123"
    end
  end
end

Now the workers will be able to create instances of FileWorker to complete the tasks.


The way to avoid the warning about signals is given in the page linked to in the message. Simply set the environment variable TERM_CHILD when calling rake:

$ rake resque:work QUEUE='*' TERM_CHILD=1
Comments