How to run a resque job in the console? - ruby-on-rails

I am trying to call a job in the console but always get errors.
Followed the following documentation:
http://tutorials.jumpstartlab.com/topics/performance/background_jobs.html
https://www.youtube.com/watch?v=UrE47tCrZXc
https://guides.rubyonrails.org/active_job_basics.html
https://github.com/resque/resque
How can I run an ActiveJob in Rails console for debugging?
Created the following file:
(lib/jobs/archive_survey_jobs.rb)
module Jobs
class ArchiveSurveysJob < ActiveJob::Base
#queue = :setup
def perform(survey_type)
if SurveyTypes.all_classes.map(&:to_s).include?(survey_type)
surveys = Survey.where(something: 'stuff')\
.where.not(something: 'stuff',
something: 'stuff')
surveys.each do |survey|
do_something
end
end
end
end
end
I understand that I can do something like Resque.enqueue(ArchiveSurveysJob, 'string_here')
How can I call this in the console? If I try:
Jobs::ArchiveSurveysJob.create(survey_type: 'string_here'),
when I check the Resque Statuses it resulted in an error: `The task failed because of an error:
undefined local variable or method `args' for #
If I try this:
Jobs::ArchiveSurveysJob.perform(`string_here`)
Or:
Jobs::ArchiveSurveysJob.perform_now('string_here')
I get:
ArgumentError: wrong number of arguments (given 0, expected 1..2)
Please let me know if I am missing some documentation or if I am doing something wrong.

In your example, perform is an instance method. youre calling the class level perform which might not have any arguments. I dont know about your version of resque specifically, however you can enqueue jobs from the console like this in at least one version: Resque.enqueue(Jobs::ArchiveSurveysJob)
ps, make sure your resque workers are running.
In dev environments I typically have resque running in line:
# config/initializers/resque.rb
Resque.inline = true if Rails.env.dev? || Rails.env.test?

How I managed to do this was by creating a Rake task and calling the Job there.

Related

Error "undefined method `to_datetime'" in sidekiq

Start sidekiq with the command
bundle exec sidekiq -e production -P /path/to/pid/file/tmp/pids/sidekiq.pid -L /path/to/log/file/shared/log/sidekiq.log --daemon
In the log error
2017-06-29T06:59:44.776Z 16181 TID-1jr7pg ERROR: CRON JOB: undefined method `to_datetime' for #<EtOrbi::EoTime:0x0000000a933848>
2017-06-29T06:59:44.776Z 16181 TID-1jr7pg ERROR: CRON JOB: /home/user/.rvm/gems/ruby-2.0.0-p247#script-admin/gems/activesupport-3.2.13/lib/active_support/core_ext/date_time/calculations.rb:141:in `<=>'
error while executing the method /home/user/.rvm/gems/ruby-2.0.0-p247#script-admin/gems/activesupport-3.2.13/lib/active_support/core_ext/date_time/calculations.rb:141:in <=>:
def <=> (other)
super other.kind_of?(Infinity) ? other : other.to_datetime
end
What can be done with the problem?
UPD: Updated version rails to 3.2.22.5 and there is a new error
ERROR: CRON JOB: comparison of Time with EtOrbi::EoTime failed
ERROR: CRON JOB: /home/user/.rvm/gems/ruby-2.0.0-p247#script-admin/gems/sidekiq-cron-0.3.1/lib/sidekiq/cron/job.rb:434:in `<'
in this place
def not_enqueued_after?(time)
#last_enqueue_time.nil? || #last_enqueue_time < last_time(time)
end
Your issue arises not from sidekiq but from Rails 3.2.13. #<=> does not handle undefined method to_datetime. It was fixed in future versions of Rails. For example, in the Rails 3.2.22.5:
def <=>(other)
if other.kind_of?(Infinity)
super
elsif other.respond_to? :to_datetime
super other.to_datetime
else
nil
end
end
Therefore, the simplest way to solve your issue is to update your Rails version. If it is not an options paste your code or rewrite #<=>.
to_datetime is a method from rails' activesupport library and your sidekiq worker is not using this.
try adding require 'active_support/core_ext' to your sidekiq initializer config config/initializers/sidekiq.rb and restart sidekiq

Why is my rake task running twice in my test?

I have a rake task test that I setup following the only examples I could find online.
It looks like this:
require 'test_helper'
require 'minitest/mock'
require 'rake'
class TestScrapeWelcome < ActiveSupport::TestCase
def setup
Rake.application.init
Rake.application.load_rakefile
#task = Rake::Task['scrape:scrape']
#task.reenable
end
def teardown
Rake::Task.clear
end
test "scraping text and sending to elasticsearch" do
mocked_client = Minitest::Mock.new
get_fixtures.each_with_index do |arg,i|
mocked_client.expect :index, :return_value, [index: "test", type: 'welcome', id: i, body: arg]
end
Elasticsearch::Model.stub :client, mocked_client do
#task.invoke
end
assert mocked_client.verify
end
private
def get_fixtures
(0..11).map { |i|
File.read("test/fixtures/scrape/index_#{i}.json")
}
end
end
But after the task runs once it starts running again without me doing anything (puts prints before and after #task.invoke show that the task is only run the once).
Turns out that rake is already required and initialized when the test runs so all of the following lines need to be removed or the task gets defined twice and runs twice even if you only invoke it once.
require 'minitest/mock'
require 'rake'
...
Rake.application.init
Rake.application.load_rakefile
Updated answer for rails 5.1 (using minitest):
I found I needed the following to load tasks once and only once:
MyAppName::Application.load_tasks if Rake::Task.tasks.empty?
Alternatively add MyAppName::Application.load_tasks to your test_helper, if you don't mind tasks being loaded even when running individual tests that don't need them.
(Replace MyAppName with your application name)
I've tried #iheggie answer but it worked in a way that indeed tests were run once but any other task was breaking with Don't know how to build task '<task_name_like_db_migrate>'.
I'm on Rails 3.2 still. It turned out that there were couple tasks loaded beforehand so the Rake::Task.tasks.empty? was never true and all other useful tasks were not loaded. I've fiddled with it and this version of it works for me right now:
Rake::Task.clear if Rails.env.test?
MyAppName::Application.load_tasks
Hope this helps anyone.
A solution that works for testing the tasks of a Gem that has been made a Railtie so it can add tasks to the Rails app:
Don't define the Railtie in test mode when you're also defining a Rails::Application class in spec_helper.rb (which allows your tests to call Rails.application.load_tasks). Otherwise the Rake file will be loaded once as a Railtie and once as an Engine:
class Railtie < Rails::Railtie
rake_tasks do
load 'tasks/mygem.rake'
end
end unless Rails.env.test? # Without this condition tasks under test are run twice
Another solution would be to put a condition in the Rake file to skip the task definitions if the file has already been loaded.

NameError: uninitialized constant MyJob ActiveJob and Sidekiq

I have a problem with sidekiq/activejob integration. I have a controller that calls a perform_later method from a MyJob class. This works with the perform method, but when I change to perfom_later, the job is scheduled in my development log. However, when I see the sidekiq dashboard, at the retries section, I can see NameError: uninitialized constant (look below image)
These are my files:
# app/jobs/crime_job.rb
class CrimeJob < ActiveJob::Base
queue_as :default
def perform(crime)
puts "Perform #{crime}"
end
def self.job_name(crime)
"RadarCrime:#{crime.id}"
end
end
Crime Controller
# app/controllers/crime_controller.rb
def show
# [...]
CrimeJob.perform_later(#crime)
end
Sidekiq initializer
# config/initializers/active_job.rb
Rails.application.config.active_job.queue_adapter = :sidekiq
Well, I also open an issue in Sidekiq repository, and the solution is easier than I've think.
Just restart the sidekiq process and it's works fine.
Issue link: https://github.com/mperham/sidekiq/issues/2207

Resque error- wrong number of arguments(0 for 1)

I am using rescue to handle all the heavy lifting background tasks,
In my library/parsers/file.rb I have
Resque.enqueue(Hello)
This will redirect app/workers/file.rb where I have
class Hello
def self.perform(page)
.......
.......
end
rescue Exception => e
log "error: #{e}"
end
end
my lib/tasks/resque.rake file is
require "resque/tasks"
task "resque:setup" => :environment
I am able to queue the jobs buts when i try to execute the job using
rake resque:work QUEUE=*
it is throwing an error by saying
argument error
wrong number of arguments (0 for 1)
what am I doing wrong in this?
pjumble is exactly right, you're not passing the page.
Resque.enqueue(Hello, page_id)
enqueue takes the Job followed by the args which go into the perform action. If you had:
class Hello
def self.perform(page_number, page_foo, page_bar)
...
end
end
Then you would do this:
Resque.enqueue(Hello, page_number, page_foo, page_bar)

testing using Resque with Rspec examples?

I am processing my background jobs using Resque.
My model looks like this
class SomeClass
...
repo = Repo.find(params[:repo_id])
Resque.enqueue(ReopCleaner, repo.id)
...
end
class RepoCleaner
#queue = :repo_cleaner
def self.perform(repo_id)
puts "this must get printed in console"
repo = Repo.find(repo_id)
# some more action here
end
end
Now to test in synchronously i have added
Resque.inline = Rails.env.test?
in my config/initializers/resque.rb file
This was supposed to call #perform method inline without queuing it into Redis and without any Resque callbacks as Rails.env.test? returns true in test environment.
But
"this must get printed in console"
is never printed while testing. and my tests are also failing.
Is there any configurations that i have missed.
Currently i am using
resque (1.17.1)
resque_spec (0.7.0)
resque_unit (0.4.0)
I personally test my workers different. I use RSpec and for example in my user model I test something like this:
it "enqueue FooWorker#create_user" do
mock(Resque).enqueue(FooWorker, :create_user, user.id)
user.create_on_foo
end
Then I have a file called spec/workers/foo_worker_spec.rb with following content:
require 'spec_helper'
describe FooWorker do
describe "#perform" do
it "redirects to passed action" do
...
FooWorker.perform
...
end
end
end
Then your model/controller tests run faster and you don't have the dependency between model/controller and your worker in your tests. You also don't have to mock so much things in specs which don't have to do with the worker.
But if you wan't to do it like you mentioned, it worked for me some times ago. I put Resque.inline = true into my test environment config.
It looks like the question about logging never got answered. I ran into something similar to this and it was from not setting up the Resque logger. You can do something as simple as:
Resque.logger = Rails.logger
Or you can setup a separate log file by adding this to your /lib/tasks/resque.rake. When you run your worker it will write to /log/resque.log
Resque.before_fork = Proc.new {
ActiveRecord::Base.establish_connection
# Open the new separate log file
logfile = File.open(File.join(Rails.root, 'log', 'resque.log'), 'a')
# Activate file synchronization
logfile.sync = true
# Create a new buffered logger
Resque.logger = ActiveSupport::Logger.new(logfile)
Resque.logger.level = Logger::INFO
Resque.logger.info "Resque Logger Initialized!"
}
Mocking like daniel-spangenberg mentioned above ought to write to STDOUT unless your methods are in the "private" section of your class. That's tripped me up a couple times when writing rspec tests. ActionMailer requires it's own log setup too. I guess I've been expecting more convention than configuration. :)

Resources