Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resque-Scheduler not working with ActiveJob in Rails 4.2

Has anyone been able to get scheduled jobs to work in Rails 4.2?

I am using resque, and I am attempting to use resque-scheduler to schedule jobs. I have a schedule that get loaded and the scheduler runs, and even looks like it is running the jobs but it doesn't do anything.

resque-scheduler: [INFO] 2014-09-16T01:54:25-07:00: Starting
resque-scheduler: [INFO] 2014-09-16T01:54:25-07:00: Loading Schedule
resque-scheduler: [INFO] 2014-09-16T01:54:25-07:00: Scheduling friends 
resque-scheduler: [INFO] 2014-09-16T01:54:25-07:00: Schedules Loaded
resque-scheduler: [INFO] 2014-09-16T01:54:55-07:00: queueing FriendsJob (friends)

I can enqueue jobs like this and they get processed.

TestJob.enqueue(params[:id])

and I get this output in the worker log

got: (Job{default} | ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper | ["TestJob", "98732ce5-17f7-4da3-9a03-a5d2f8f74e84", "8"])
** [01:24:01 2014-09-16] 54841: resque-1.25.2: Processing default since 1410855841  [ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper]
** [01:24:01 2014-09-16] 54841: Running before_fork hooks with [(Job{default} | ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper | ["TestJob", "98732ce5-17f7-4da3-9a03-a5d2f8f74e84", "8"])]
** [01:24:01 2014-09-16] 54841: resque-1.25.2: Forked 54882 at 1410855841
** [01:24:01 2014-09-16] 54882: Running after_fork hooks with [(Job{default} | ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper | ["TestJob", "98732ce5-17f7-4da3-9a03-a5d2f8f74e84", "8"])]
Hello World!!
** [01:24:01 2014-09-16] 54882: done: (Job{default} | ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper | ["TestJob", "98732ce5-17f7-4da3-9a03-a5d2f8f74e84", "8"])

But when I try to schedule a job, it looks like the are getting enqueue but they well not doing anything.

Here is the schedule.yml

friends:
  every: "30s"
  queue: "friends"
  class: "FriendsJob"
  args: 8
  description: "Friends jobs scheduler"

Here is the output from the scheduled job.

** [01:23:36 2014-09-16] 54841: got: (Job{friends} | FriendsJob | [8])
** [01:23:36 2014-09-16] 54841: resque-1.25.2: Processing friends since 1410855816 [FriendsJob]
** [01:23:36 2014-09-16] 54841: Running before_fork hooks with [(Job{friends} | FriendsJob | [8])]
** [01:23:36 2014-09-16] 54841: resque-1.25.2: Forked 54880 at 1410855816
** [01:23:36 2014-09-16] 54880: Running after_fork hooks with [(Job{friends} | FriendsJob | [8])]
** [01:23:36 2014-09-16] 54880: done: (Job{friends} | FriendsJob | [8])

After reading this http://dev.mikamai.com/post/96343027199/rails-4-2-new-gems-active-job-and-global-id I am suspecting it has something to do with ActiveJob and GlobalId.

Take a look at the difference enqueued

** [01:24:01 2014-09-16] 54841: Running before_fork hooks with [(Job{default} | ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper | ["TestJob", "98732ce5-17f7-4da3-9a03-a5d2f8f74e84", "8"])]

vs scheduled

** [01:23:36 2014-09-16] 54841: Running before_fork hooks with [(Job{friends} | FriendsJob | [8])]

The jobs themselves were generated via

 rails g job <JobName>

They look like this:

class TestJob < ActiveJob::Base
  queue_as :default
  def perform(friend_id)
    friend = Friend.find(friend_id)
    name = friend.name.swapcase
    puts "Hello World!!"
  end
end


class FriendsJob < ActiveJob::Base
  queue_as :friends
  def perform(friend_id)
    friend = Friend.find(friend_id)
    name = friend.name.swapcase
    puts "Hello World!!"
  end
end

Any help with this will be greatly appreciated and thanks in advance.

********* UPDATE *********

I've removed the action_job railtie and I am using Resque and Resque-Scheduler only, and scheduled jobs are working now. So this does seems to be related to ActionJob/GlobalId. I've open an issue in the rails project. Hopefully, they will fix it soon.

****** SECOND UPDATE ********* I got an update on this. Cristianbica who works in the ActiveJob codebase said this. "We haven't thought at recurring jobs so far and we don't support this as none of the adapters support this without an external gem. However this is a very nice feature but I don't think we can make it in time for 4.2. Also I'm not sure it will suitable to be included in rails"

like image 204
luis.madrigal Avatar asked Sep 16 '14 09:09

luis.madrigal


3 Answers

https://github.com/JustinAiken/active_scheduler is a gem that wraps the one into the other

like image 123
Justin Aiken Avatar answered Nov 16 '22 13:11

Justin Aiken


UPDATE: 4/4/16 - Whilst the below answer is still correct with the current version of Rails, I now use the active_scheduler gem created by Justin as mentioned in the answer above: https://stackoverflow.com/a/29155372/1299792

ORIGINAL ANSWER: Avoid using ActiveJob if you need to schedule recurring jobs.

From the issue that Luis raised

As we are not currently supporting recurring jobs with ActiveJob we're going to close this. If it's possible to support recurring jobs I'm seeing this as a separate gem or in rails 5. Feature requests and talks around them are usually talked in the mailing list (https://groups.google.com/forum/#!forum/rubyonrails-core). As a solution to your problem @luismadrigal I suggest you use the resque-scheduler way to do recurring job.

https://github.com/rails/rails/issues/16933#issuecomment-58945932

There was talk about creating a gem in the mailing list but I can't find any further information on it.

like image 42
Marklar Avatar answered Nov 16 '22 14:11

Marklar


It seems that ActiveJob in Rails 4.2 is not supported by resque-scheduler. Therefore, jobs are not scheduled correctly, that explains the difference in the log when a job is enqueued using ActiveJob API and resque-scheduler.

To fix this, we should find a way to schedule job within ActiveJob wrapper:

ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper

Resque-scheduler provides the way to support extensions that are not supported by default. To do this, we should extend custom job class to support the #scheduled method. This way we can enqueue job manually using ActiveJob API.

The easiest way is to write general code method in the base job, and then extend all jobs from it:

# custom base job
class Job < ActiveJob::Base

    # method called by resque-scheduler to enqueue job in a queue
    def self.scheduled(queue, klass, *args)

        # create the job instance and pass the arguments
        job = self.job_or_instantiate(*args)

        # set correct queue
        job.queue_name = queue

        # enqueue job using ActiveJob API
        job.enqueue
    end
end

Reque-scheduler will call this method to schedule every single job extended from Job class. This way jobs are going to be enqueued within the ActiveJob wrapper. Result will be same as calling MyJob.perform_later(*args).

like image 2
XeNoN Avatar answered Nov 16 '22 13:11

XeNoN