ActiveJob: Accessible instance variables between callbacks

2.7k views Asked by At

I have the following snippet within my job:

before_enqueue do |job|
  # do something
  @car = create_car
end


before_perform do |job|
  # do something
  @car.update(type: 'broken')
end

but when the job is performed @car is a nil. Is it possible to pass somehow the instance variable from one callback to the second one? Even only ID would be fine. Cheers.

2

There are 2 answers

1
Aegix On

You would need to make this an instance variable off of job and access that way:

class Car < ActiveJob::Base
  attr_accessor :car
end

then

before_enqueue do |job|
  # do something
  job.car = create_car
end

before_perform do |job|
  # do something
  job.car.update(type: 'broken')
end
0
Jacquen On

Similar to what you're trying to do, I wanted to know which user enqueued a job without passing the user id to each job in perform. It doesn't look like ActiveJob lets you serialize new instance variables, so I just made use of the arguments variable:

class ApplicationJob < ActiveJob::Base
  before_enqueue do |job|
    # Get user_id from somewhere first
    job.arguments = [user_id, *job.arguments]
  end

  around_perform do |job, block|
    user_id = job.arguments.shift
    # Store user_id somewhere
    block.call
    # Ensure user_id is no longer stored
    # (why I'm using around_perform instead of before_perform)
  end
end

However, that causes problems if you use perform_now and not just perform_later, since any job performed "now" does not pass through before_enqueue. So here's an improved approach to allow perform_now:

class ApplicationJob < ActiveJob::Base
  before_enqueue do |job|
    job.arguments = ['_LATER_', user_id, *job.arguments]
  end

  around_perform do |job, block|
    if job.arguments[0] == '_LATER_'
      _, user_id = job.arguments.shift(2)
      store_somewhere(user_id) { block.call }
    else
      block.call
    end
  end
end