7

I'm using DelayedJob and I'd like to update my Rails 4.2 app to use ActiveJob. The problem is that I have a bunch of custom jobs that look like this:

AssetDeleteJob = Struct.new(:user_id, :params) do
  def perform
    # code
  end
  # more methods n' stuff
end

Then in a controller somewhere the job is enqueued with this syntax:

@asset_delete_job = AssetDeleteJob.new(current_admin_user.id, params)
Delayed::Job.enqueue @asset_delete_job

I'd like to find the equivalent for ActiveJob. The above is basically straight from the DJ docs. Using it to enqueue a single call is as simple as calling the job's perform method, just like with DJ. But mine are more complex and require DJ's Struct syntax and the arguments passed to it.

Here's what I've tried so far:

class AssetDeleteJob < ActiveJob::Base
  queue_as :default

  def initialize(user_id, params)
    @user_id  = user_id
    @params   = params
  end

  def perform
  #code
  end

  # more methods n' stuff

end

job = AssetDeleteJob.new(1, {ids: [1,2,3]})

Unfortunately, the instantiated object has no #perform_later method as I would expect. It does have #enqueue, but I get an odd error:

Could not log "enqueue.active_job" event. NoMethodError: undefined method `any?' for nil:NilClass

...followed by a stack trace in an array, ending in

NoMethodError: undefined method `map' for nil:NilClass

An odd couple of errors, but I might not be supposed to be accessing #enqueue directly. The above seems like it's pretty on the nose as far as what ActiveJob is looking for. What am I missing?

zach
  • 73
  • 1
  • 4

2 Answers2

7

I can see two problems. First, you've defined the initialize method in your custom job class, thereby overwriting the initialize method in the ActiveJob class. This is what's causing the exception to be thrown. I'm not sure if you can fiddle about with instantiation of active jobs. Second, you're trying to call the class method perform_later on an instance of that class, which ruby won't allow.

It's simple to fix, just add the arguments to the perform method in your custom class instead:

class AssetDeleteJob < ActiveJob::Base
  #code

  def perform(user_id, params)
    #do a thing
  end

  #more code
end

and then queue the job by calling something like:

AssetDeleteJob.perform_later(1, {ids: [1,2,3]})
Joe Douglas
  • 136
  • 4
  • This is correct. If you do want to modify `initialize` with the ability to override some defaults, you can call `super()` as the last command in your custom initialize. I did this recently to allow one off calls (with custom parameters) and scheduled defaults. – spyle May 29 '20 at 17:46
0
# in jobs/asset_delete_job.rb
class AssetDeleteJob < ActiveJob::Base 
  queue_as :default
  def perform(user_id, params)
    AssetService.new(user_id, params).delete # for example
  end
end

# somewhere in your controllers/assets_controller.rb 
  AssetDeleteJob.perform_later(1, {ids: [1,2,3]})