diff options
Diffstat (limited to 'activejob/lib')
-rw-r--r-- | activejob/lib/active_job/arguments.rb | 2 | ||||
-rw-r--r-- | activejob/lib/active_job/exceptions.rb | 37 | ||||
-rw-r--r-- | activejob/lib/active_job/logging.rb | 2 | ||||
-rw-r--r-- | activejob/lib/active_job/queue_adapters/backburner_adapter.rb | 4 | ||||
-rw-r--r-- | activejob/lib/active_job/railtie.rb | 4 | ||||
-rw-r--r-- | activejob/lib/active_job/test_helper.rb | 71 |
6 files changed, 84 insertions, 36 deletions
diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index ba7f9456f9..b344c44aef 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -34,7 +34,7 @@ module ActiveJob arguments.map { |argument| serialize_argument(argument) } end - # Deserializes a set of arguments. Instrinsic types that can safely be + # Deserializes a set of arguments. Intrinsic types that can safely be # deserialized without mutation are returned as-is. Arrays/Hashes are # deserialized element by element. All other types are deserialized using # GlobalID. diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb index d8384c81b6..bc9e168971 100644 --- a/activejob/lib/active_job/exceptions.rb +++ b/activejob/lib/active_job/exceptions.rb @@ -46,24 +46,15 @@ module ActiveJob # end def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil) rescue_from(*exceptions) do |error| - payload = { - job: self, - adapter: self.class.queue_adapter, - error: error, - wait: wait - } - if executions < attempts - ActiveSupport::Notifications.instrument("enqueue_retry.active_job", payload) do - retry_job wait: determine_delay(wait), queue: queue, priority: priority - end + retry_job wait: determine_delay(wait), queue: queue, priority: priority, error: error else if block_given? - ActiveSupport::Notifications.instrument("retry_stopped.active_job", payload) do + instrument :retry_stopped, error: error do yield self, error end else - ActiveSupport::Notifications.instrument("retry_stopped.active_job", payload) + instrument :retry_stopped, error: error raise error end end @@ -90,16 +81,8 @@ module ActiveJob # end def discard_on(*exceptions) rescue_from(*exceptions) do |error| - payload = { - job: self, - adapter: self.class.queue_adapter, - error: error - } - - ActiveSupport::Notifications.instrument("discard.active_job", payload) do - if block_given? - yield self, error - end + instrument :discard, error: error do + yield self, error if block_given? end end end @@ -127,7 +110,9 @@ module ActiveJob # end # end def retry_job(options = {}) - enqueue options + instrument :enqueue_retry, options.slice(:error, :wait) do + enqueue options + end end private @@ -148,5 +133,11 @@ module ActiveJob raise "Couldn't determine a delay based on #{seconds_or_duration_or_algorithm.inspect}" end end + + def instrument(name, error: nil, wait: nil, &block) + payload = { job: self, adapter: self.class.queue_adapter, error: error, wait: wait } + + ActiveSupport::Notifications.instrument("#{name}.active_job", payload, &block) + end end end diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb index 96a3e6bf48..0abee4ed98 100644 --- a/activejob/lib/active_job/logging.rb +++ b/activejob/lib/active_job/logging.rb @@ -94,7 +94,7 @@ module ActiveJob wait = event.payload[:wait] error do - "Retrying #{job.class} in #{wait} seconds, due to a #{ex.class}. The original exception was #{ex.cause.inspect}." + "Retrying #{job.class} in #{wait.inspect} seconds, due to a #{ex&.class.inspect}. The original exception was #{ex&.cause.inspect}." end end diff --git a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb index 0ba93c6e0b..7dc49310ac 100644 --- a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb @@ -16,12 +16,12 @@ module ActiveJob # Rails.application.config.active_job.queue_adapter = :backburner class BackburnerAdapter def enqueue(job) #:nodoc: - Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name + Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority) end def enqueue_at(job, timestamp) #:nodoc: delay = timestamp - Time.current.to_f - Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name, delay: delay + Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority, delay: delay) end class JobWrapper #:nodoc: diff --git a/activejob/lib/active_job/railtie.rb b/activejob/lib/active_job/railtie.rb index d0294854d3..ecc0908d5f 100644 --- a/activejob/lib/active_job/railtie.rb +++ b/activejob/lib/active_job/railtie.rb @@ -30,6 +30,10 @@ module ActiveJob send(k, v) if respond_to? k end end + + ActiveSupport.on_load(:action_dispatch_integration_test) do + include ActiveJob::TestHelper + end end initializer "active_job.set_reloader_hook" do |app| diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index bb9e3e6ca4..e7a9b16277 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -331,6 +331,22 @@ module ActiveJob # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) # end # + # + # The +args+ argument also accepts a proc which will get passed the actual + # job's arguments. Your proc needs to returns a boolean value determining if + # the job's arguments matches your expectation. This is useful to check only + # for a subset of arguments. + # + # def test_assert_enqueued_with + # expected_args = ->(job_args) do + # assert job_args.first.key?(:foo) + # end + # + # MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test') + # assert_enqueued_with(job: MyJob, args: expected_args, queue: 'low') + # end + # + # # If a block is passed, that block should cause the job to be # enqueued with the given arguments. # @@ -345,7 +361,7 @@ module ActiveJob # end def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil) expected = { job: job, args: args, at: at, queue: queue }.compact - serialized_args = serialize_args_for_assertion(expected) + expected_args = prepare_args_for_assertion(expected) if block_given? original_enqueued_jobs_count = enqueued_jobs.count @@ -358,7 +374,15 @@ module ActiveJob end matching_job = jobs.find do |enqueued_job| - serialized_args.all? { |key, value| value == enqueued_job[key] } + deserialized_job = deserialize_args_for_assertion(enqueued_job) + + expected_args.all? do |key, value| + if value.respond_to?(:call) + value.call(deserialized_job[key]) + else + value == deserialized_job[key] + end + end end assert matching_job, "No enqueued job found with #{expected}" @@ -381,6 +405,22 @@ module ActiveJob # assert_performed_with(job: MyJob, at: Date.tomorrow.noon) # end # + # The +args+ argument also accepts a proc which will get passed the actual + # job's arguments. Your proc needs to returns a boolean value determining if + # the job's arguments matches your expectation. This is useful to check only + # for a subset of arguments. + # + # def test_assert_performed_with + # expected_args = ->(job_args) do + # assert job_args.first.key?(:foo) + # end + # MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test') + # + # perform_enqueued_jobs + # + # assert_performed_with(job: MyJob, args: expected_args, queue: 'high') + # end + # # If a block is passed, that block performs all of the jobs that were # enqueued throughout the duration of the block and asserts that # the job has been performed with the given arguments in the block. @@ -396,7 +436,7 @@ module ActiveJob # end def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, &block) expected = { job: job, args: args, at: at, queue: queue }.compact - serialized_args = serialize_args_for_assertion(expected) + expected_args = prepare_args_for_assertion(expected) if block_given? original_performed_jobs_count = performed_jobs.count @@ -408,8 +448,16 @@ module ActiveJob jobs = performed_jobs end - matching_job = jobs.find do |performed_job| - serialized_args.all? { |key, value| value == performed_job[key] } + matching_job = jobs.find do |enqueued_job| + deserialized_job = deserialize_args_for_assertion(enqueued_job) + + expected_args.all? do |key, value| + if value.respond_to?(:call) + value.call(deserialized_job[key]) + else + value == deserialized_job[key] + end + end end assert matching_job, "No performed job found with #{expected}" @@ -552,10 +600,15 @@ module ActiveJob end end - def serialize_args_for_assertion(args) - args.dup.tap do |serialized_args| - serialized_args[:args] = ActiveJob::Arguments.serialize(serialized_args[:args]) if serialized_args[:args] - serialized_args[:at] = serialized_args[:at].to_f if serialized_args[:at] + def prepare_args_for_assertion(args) + args.dup.tap do |arguments| + arguments[:at] = arguments[:at].to_f if arguments[:at] + end + end + + def deserialize_args_for_assertion(job) + job.dup.tap do |new_job| + new_job[:args] = ActiveJob::Arguments.deserialize(new_job[:args]) if new_job[:args] end end |