In my Rails 4 app, I have an ActiveRecord model with an AASM column. When I use a failing method with delayed_job_active_record, it swallows the error and throws something else to do with AASM.
class MyModel < ActiveRecord::Base
include AASM
aasm do
# aasm setup here
end
def self.joberror
1/0 #bad code here
end
end
MyModel.joberror
fails predictably with a ZeroDivisionError
. However, when I run this method from inside delayed_job_active_record (MyModel.delay.joberror
), the correct error is swallowed, and this is thrown instead:
wrong number of arguments (2 for 0)
/Users/myhome/myproject/.gems/gems/aasm-4.0.5/lib/aasm/persistence/base.rb:67:in `block (2 levels) in state_with_scope'
That points to code in the aasm gem, despite this method not involving aasm at all, nor even an actual instance of MyModel
. However, if I comment out the aasm code it goes back to the correct ZeroDivision error.
I've read that delayed_job does some serialization of the method you want it to perform but I don't understand the consequences of that enough to know why it would cause this or how to fix it.
This delayed_job code was the problem. When delayed_job encounters an error it looks for something on the object that it can call, in this case anything named "error":
# lib/delayed/backend/base.rb: 96
rescue => e
hook :error, e
raise e
# lib/delayed/backend/base.rb: 111
def hook(name, *args)
if payload_object.respond_to?(name) # <--- my object has an unrelated method "error"
method = payload_object.method(name)
method.arity == 0 ? method.call : method.call(self, *args)
end
rescue DeserializationError
end
In my case I had an aasm state named error
. So whenever an error occurred, delayed_job rescued and then tried to call this error state as a method, which failed. This obviously only occurred when the code being called threw an error, and only when it was run via delayed_job.