activejob 7.0.8.1 → 7.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +112 -155
- data/MIT-LICENSE +1 -1
- data/README.md +2 -2
- data/lib/active_job/arguments.rb +14 -25
- data/lib/active_job/base.rb +1 -1
- data/lib/active_job/callbacks.rb +1 -4
- data/lib/active_job/configured_job.rb +4 -0
- data/lib/active_job/core.rb +3 -1
- data/lib/active_job/deprecator.rb +7 -0
- data/lib/active_job/enqueuing.rb +30 -0
- data/lib/active_job/exceptions.rb +30 -0
- data/lib/active_job/execution.rb +5 -1
- data/lib/active_job/gem_version.rb +4 -4
- data/lib/active_job/instrumentation.rb +18 -10
- data/lib/active_job/log_subscriber.rb +77 -7
- data/lib/active_job/queue_adapter.rb +13 -2
- data/lib/active_job/queue_adapters/async_adapter.rb +2 -2
- data/lib/active_job/queue_adapters/backburner_adapter.rb +7 -3
- data/lib/active_job/queue_adapters/delayed_job_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/inline_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/queue_classic_adapter.rb +4 -4
- data/lib/active_job/queue_adapters/resque_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +42 -14
- data/lib/active_job/queue_adapters/sneakers_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +2 -2
- data/lib/active_job/queue_adapters/test_adapter.rb +2 -2
- data/lib/active_job/queue_adapters.rb +8 -7
- data/lib/active_job/queue_priority.rb +18 -1
- data/lib/active_job/railtie.rb +25 -6
- data/lib/active_job/serializers/big_decimal_serializer.rb +22 -0
- data/lib/active_job/serializers/duration_serializer.rb +4 -2
- data/lib/active_job/serializers.rb +7 -3
- data/lib/active_job/test_helper.rb +23 -3
- data/lib/active_job/version.rb +1 -1
- data/lib/active_job.rb +26 -4
- data/lib/rails/generators/job/USAGE +19 -0
- data/lib/rails/generators/job/job_generator.rb +6 -2
- data/lib/rails/generators/job/templates/job.rb.tt +1 -1
- metadata +13 -11
- data/lib/active_job/queue_adapters/que_adapter.rb +0 -61
@@ -1,6 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveJob
|
4
|
+
class << self
|
5
|
+
private
|
6
|
+
def instrument_enqueue_all(queue_adapter, jobs)
|
7
|
+
payload = { adapter: queue_adapter, jobs: jobs }
|
8
|
+
ActiveSupport::Notifications.instrument("enqueue_all.active_job", payload) do
|
9
|
+
result = yield payload
|
10
|
+
payload[:enqueued_count] = result
|
11
|
+
result
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
4
16
|
module Instrumentation # :nodoc:
|
5
17
|
extend ActiveSupport::Concern
|
6
18
|
|
@@ -21,19 +33,15 @@ module ActiveJob
|
|
21
33
|
end
|
22
34
|
|
23
35
|
def instrument(operation, payload = {}, &block)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if defined?(@_halted_callback_hook_called) && @_halted_callback_hook_called
|
28
|
-
event_payload[:aborted] = true
|
29
|
-
@_halted_callback_hook_called = nil
|
30
|
-
end
|
36
|
+
payload[:job] = self
|
37
|
+
payload[:adapter] = queue_adapter
|
31
38
|
|
39
|
+
ActiveSupport::Notifications.instrument("#{operation}.active_job", payload) do
|
40
|
+
value = block.call if block
|
41
|
+
payload[:aborted] = @_halted_callback_hook_called if defined?(@_halted_callback_hook_called)
|
42
|
+
@_halted_callback_hook_called = nil
|
32
43
|
value
|
33
44
|
end
|
34
|
-
|
35
|
-
ActiveSupport::Notifications.instrument \
|
36
|
-
"#{operation}.active_job", payload.merge(adapter: queue_adapter, job: self), &enhanced_block
|
37
45
|
end
|
38
46
|
|
39
47
|
def halted_callback_hook(*)
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/string/filters"
|
4
3
|
require "active_support/log_subscriber"
|
5
4
|
|
6
5
|
module ActiveJob
|
7
6
|
class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
|
7
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
8
|
+
|
8
9
|
def enqueue(event)
|
9
10
|
job = event.payload[:job]
|
10
11
|
ex = event.payload[:exception_object] || job.enqueue_error
|
@@ -23,6 +24,7 @@ module ActiveJob
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
27
|
+
subscribe_log_level :enqueue, :info
|
26
28
|
|
27
29
|
def enqueue_at(event)
|
28
30
|
job = event.payload[:job]
|
@@ -38,10 +40,38 @@ module ActiveJob
|
|
38
40
|
end
|
39
41
|
else
|
40
42
|
info do
|
41
|
-
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)
|
43
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
subscribe_log_level :enqueue_at, :info
|
48
|
+
|
49
|
+
def enqueue_all(event)
|
50
|
+
info do
|
51
|
+
jobs = event.payload[:jobs]
|
52
|
+
adapter = event.payload[:adapter]
|
53
|
+
enqueued_count = event.payload[:enqueued_count]
|
54
|
+
|
55
|
+
if enqueued_count == jobs.size
|
56
|
+
enqueued_jobs_message(adapter, jobs)
|
57
|
+
elsif jobs.any?(&:successfully_enqueued?)
|
58
|
+
enqueued_jobs = jobs.select(&:successfully_enqueued?)
|
59
|
+
|
60
|
+
failed_enqueue_count = jobs.size - enqueued_count
|
61
|
+
if failed_enqueue_count == 0
|
62
|
+
enqueued_jobs_message(adapter, enqueued_jobs)
|
63
|
+
else
|
64
|
+
"#{enqueued_jobs_message(adapter, enqueued_jobs)}. "\
|
65
|
+
"Failed enqueuing #{failed_enqueue_count} #{'job'.pluralize(failed_enqueue_count)}"
|
66
|
+
end
|
67
|
+
else
|
68
|
+
failed_enqueue_count = jobs.size - enqueued_count
|
69
|
+
"Failed enqueuing #{failed_enqueue_count} #{'job'.pluralize(failed_enqueue_count)} "\
|
70
|
+
"to #{ActiveJob.adapter_name(adapter)}"
|
42
71
|
end
|
43
72
|
end
|
44
73
|
end
|
74
|
+
subscribe_log_level :enqueue_all, :info
|
45
75
|
|
46
76
|
def perform_start(event)
|
47
77
|
info do
|
@@ -49,6 +79,7 @@ module ActiveJob
|
|
49
79
|
"Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} enqueued at #{job.enqueued_at}" + args_info(job)
|
50
80
|
end
|
51
81
|
end
|
82
|
+
subscribe_log_level :perform_start, :info
|
52
83
|
|
53
84
|
def perform(event)
|
54
85
|
job = event.payload[:job]
|
@@ -67,6 +98,7 @@ module ActiveJob
|
|
67
98
|
end
|
68
99
|
end
|
69
100
|
end
|
101
|
+
subscribe_log_level :perform, :info
|
70
102
|
|
71
103
|
def enqueue_retry(event)
|
72
104
|
job = event.payload[:job]
|
@@ -75,34 +107,37 @@ module ActiveJob
|
|
75
107
|
|
76
108
|
info do
|
77
109
|
if ex
|
78
|
-
"Retrying #{job.class} in #{wait.to_i} seconds, due to a #{ex.class}."
|
110
|
+
"Retrying #{job.class} (Job ID: #{job.job_id}) after #{job.executions} attempts in #{wait.to_i} seconds, due to a #{ex.class} (#{ex.message})."
|
79
111
|
else
|
80
|
-
"Retrying #{job.class} in #{wait.to_i} seconds."
|
112
|
+
"Retrying #{job.class} (Job ID: #{job.job_id}) after #{job.executions} attempts in #{wait.to_i} seconds."
|
81
113
|
end
|
82
114
|
end
|
83
115
|
end
|
116
|
+
subscribe_log_level :enqueue_retry, :info
|
84
117
|
|
85
118
|
def retry_stopped(event)
|
86
119
|
job = event.payload[:job]
|
87
120
|
ex = event.payload[:error]
|
88
121
|
|
89
122
|
error do
|
90
|
-
"Stopped retrying #{job.class} due to a #{ex.class}, which reoccurred on #{job.executions} attempts."
|
123
|
+
"Stopped retrying #{job.class} (Job ID: #{job.job_id}) due to a #{ex.class} (#{ex.message}), which reoccurred on #{job.executions} attempts."
|
91
124
|
end
|
92
125
|
end
|
126
|
+
subscribe_log_level :enqueue_retry, :error
|
93
127
|
|
94
128
|
def discard(event)
|
95
129
|
job = event.payload[:job]
|
96
130
|
ex = event.payload[:error]
|
97
131
|
|
98
132
|
error do
|
99
|
-
"Discarded #{job.class} due to a #{ex.class}."
|
133
|
+
"Discarded #{job.class} (Job ID: #{job.job_id}) due to a #{ex.class} (#{ex.message})."
|
100
134
|
end
|
101
135
|
end
|
136
|
+
subscribe_log_level :discard, :error
|
102
137
|
|
103
138
|
private
|
104
139
|
def queue_name(event)
|
105
|
-
event.payload[:adapter]
|
140
|
+
ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
|
106
141
|
end
|
107
142
|
|
108
143
|
def args_info(job)
|
@@ -134,6 +169,41 @@ module ActiveJob
|
|
134
169
|
def logger
|
135
170
|
ActiveJob::Base.logger
|
136
171
|
end
|
172
|
+
|
173
|
+
def info(progname = nil, &block)
|
174
|
+
return unless super
|
175
|
+
|
176
|
+
if ActiveJob.verbose_enqueue_logs
|
177
|
+
log_enqueue_source
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def error(progname = nil, &block)
|
182
|
+
return unless super
|
183
|
+
|
184
|
+
if ActiveJob.verbose_enqueue_logs
|
185
|
+
log_enqueue_source
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def log_enqueue_source
|
190
|
+
source = extract_enqueue_source_location(caller)
|
191
|
+
|
192
|
+
if source
|
193
|
+
logger.info("↳ #{source}")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def extract_enqueue_source_location(locations)
|
198
|
+
backtrace_cleaner.clean(locations.lazy).first
|
199
|
+
end
|
200
|
+
|
201
|
+
def enqueued_jobs_message(adapter, enqueued_jobs)
|
202
|
+
enqueued_count = enqueued_jobs.size
|
203
|
+
job_classes_counts = enqueued_jobs.map(&:class).tally.sort_by { |_k, v| -v }
|
204
|
+
"Enqueued #{enqueued_count} #{'job'.pluralize(enqueued_count)} to #{ActiveJob.adapter_name(adapter)}"\
|
205
|
+
" (#{job_classes_counts.map { |klass, count| "#{count} #{klass}" }.join(', ')})"
|
206
|
+
end
|
137
207
|
end
|
138
208
|
end
|
139
209
|
|
@@ -3,7 +3,18 @@
|
|
3
3
|
require "active_support/core_ext/string/inflections"
|
4
4
|
|
5
5
|
module ActiveJob
|
6
|
-
|
6
|
+
class << self
|
7
|
+
def adapter_name(adapter) # :nodoc:
|
8
|
+
return adapter.queue_adapter_name if adapter.respond_to?(:queue_adapter_name)
|
9
|
+
|
10
|
+
adapter_class = adapter.is_a?(Module) ? adapter : adapter.class
|
11
|
+
"#{adapter_class.name.demodulize.delete_suffix('Adapter')}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# = Active Job Queue adapter
|
16
|
+
#
|
17
|
+
# The +ActiveJob::QueueAdapter+ module is used to load the
|
7
18
|
# correct adapter. The default queue adapter is the +:async+ queue.
|
8
19
|
module QueueAdapter # :nodoc:
|
9
20
|
extend ActiveSupport::Concern
|
@@ -41,7 +52,7 @@ module ActiveJob
|
|
41
52
|
assign_adapter(name_or_adapter.to_s, queue_adapter)
|
42
53
|
else
|
43
54
|
if queue_adapter?(name_or_adapter)
|
44
|
-
adapter_name =
|
55
|
+
adapter_name = ActiveJob.adapter_name(name_or_adapter).underscore
|
45
56
|
assign_adapter(adapter_name, name_or_adapter)
|
46
57
|
else
|
47
58
|
raise ArgumentError
|
@@ -7,7 +7,7 @@ require "concurrent/utility/processor_counter"
|
|
7
7
|
|
8
8
|
module ActiveJob
|
9
9
|
module QueueAdapters
|
10
|
-
#
|
10
|
+
# = Active Job Async adapter
|
11
11
|
#
|
12
12
|
# The Async adapter runs jobs with an in-process thread pool.
|
13
13
|
#
|
@@ -95,7 +95,7 @@ module ActiveJob
|
|
95
95
|
|
96
96
|
def enqueue_at(job, timestamp, queue_name:)
|
97
97
|
delay = timestamp - Time.current.to_f
|
98
|
-
if delay > 0
|
98
|
+
if !immediate && delay > 0
|
99
99
|
Concurrent::ScheduledTask.execute(delay, args: [job], executor: executor, &:perform)
|
100
100
|
else
|
101
101
|
enqueue(job, queue_name: queue_name)
|
@@ -4,7 +4,7 @@ require "backburner"
|
|
4
4
|
|
5
5
|
module ActiveJob
|
6
6
|
module QueueAdapters
|
7
|
-
#
|
7
|
+
# = Backburner adapter for Active Job
|
8
8
|
#
|
9
9
|
# Backburner is a beanstalkd-powered job queue that can handle a very
|
10
10
|
# high volume of jobs. You create background jobs and place them on
|
@@ -16,12 +16,16 @@ module ActiveJob
|
|
16
16
|
# Rails.application.config.active_job.queue_adapter = :backburner
|
17
17
|
class BackburnerAdapter
|
18
18
|
def enqueue(job) # :nodoc:
|
19
|
-
Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority)
|
19
|
+
response = Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority)
|
20
|
+
job.provider_job_id = response[:id] if response.is_a?(Hash)
|
21
|
+
response
|
20
22
|
end
|
21
23
|
|
22
24
|
def enqueue_at(job, timestamp) # :nodoc:
|
23
25
|
delay = timestamp - Time.current.to_f
|
24
|
-
Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority, delay: delay)
|
26
|
+
response = Backburner::Worker.enqueue(JobWrapper, [job.serialize], queue: job.queue_name, pri: job.priority, delay: delay)
|
27
|
+
job.provider_job_id = response[:id] if response.is_a?(Hash)
|
28
|
+
response
|
25
29
|
end
|
26
30
|
|
27
31
|
class JobWrapper # :nodoc:
|
@@ -5,7 +5,7 @@ require "active_support/core_ext/string/inflections"
|
|
5
5
|
|
6
6
|
module ActiveJob
|
7
7
|
module QueueAdapters
|
8
|
-
#
|
8
|
+
# = Delayed Job adapter for Active Job
|
9
9
|
#
|
10
10
|
# Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
|
11
11
|
# executing longer tasks in the background. Although DJ can have many
|
@@ -4,7 +4,7 @@ require "queue_classic"
|
|
4
4
|
|
5
5
|
module ActiveJob
|
6
6
|
module QueueAdapters
|
7
|
-
#
|
7
|
+
# = queue_classic adapter for Active Job
|
8
8
|
#
|
9
9
|
# queue_classic provides a simple interface to a PostgreSQL-backed message
|
10
10
|
# queue. queue_classic specializes in concurrent locking and minimizing
|
@@ -37,10 +37,10 @@ module ActiveJob
|
|
37
37
|
qc_job
|
38
38
|
end
|
39
39
|
|
40
|
-
# Builds a
|
40
|
+
# Builds a +QC::Queue+ object to schedule jobs on.
|
41
41
|
#
|
42
|
-
# If you have a custom
|
43
|
-
#
|
42
|
+
# If you have a custom +QC::Queue+ subclass you'll need to subclass
|
43
|
+
# +ActiveJob::QueueAdapters::QueueClassicAdapter+ and override the
|
44
44
|
# <tt>build_queue</tt> method.
|
45
45
|
def build_queue(queue_name)
|
46
46
|
QC::Queue.new(queue_name)
|
@@ -16,7 +16,7 @@ end
|
|
16
16
|
|
17
17
|
module ActiveJob
|
18
18
|
module QueueAdapters
|
19
|
-
#
|
19
|
+
# = Resque adapter for Active Job
|
20
20
|
#
|
21
21
|
# Resque (pronounced like "rescue") is a Redis-backed library for creating
|
22
22
|
# background jobs, placing those jobs on multiple queues, and processing
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
gem "sidekiq", ">= 4.1.0"
|
3
4
|
require "sidekiq"
|
4
5
|
|
5
6
|
module ActiveJob
|
6
7
|
module QueueAdapters
|
7
|
-
#
|
8
|
+
# = Sidekiq adapter for Active Job
|
8
9
|
#
|
9
10
|
# Simple, efficient background processing for Ruby. Sidekiq uses threads to
|
10
11
|
# handle many jobs at the same time in the same process. It does not
|
11
|
-
# require Rails but will integrate tightly with it to make background
|
12
|
+
# require \Rails but will integrate tightly with it to make background
|
12
13
|
# processing dead simple.
|
13
14
|
#
|
14
15
|
# Read more about Sidekiq {here}[http://sidekiq.org].
|
@@ -18,21 +19,48 @@ module ActiveJob
|
|
18
19
|
# Rails.application.config.active_job.queue_adapter = :sidekiq
|
19
20
|
class SidekiqAdapter
|
20
21
|
def enqueue(job) # :nodoc:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
"queue" => job.queue_name,
|
26
|
-
"args" => [ job.serialize ]
|
22
|
+
job.provider_job_id = JobWrapper.set(
|
23
|
+
wrapped: job.class,
|
24
|
+
queue: job.queue_name
|
25
|
+
).perform_async(job.serialize)
|
27
26
|
end
|
28
27
|
|
29
28
|
def enqueue_at(job, timestamp) # :nodoc:
|
30
|
-
job.provider_job_id =
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
job.provider_job_id = JobWrapper.set(
|
30
|
+
wrapped: job.class,
|
31
|
+
queue: job.queue_name,
|
32
|
+
).perform_at(timestamp, job.serialize)
|
33
|
+
end
|
34
|
+
|
35
|
+
def enqueue_all(jobs) # :nodoc:
|
36
|
+
enqueued_count = 0
|
37
|
+
jobs.group_by(&:class).each do |job_class, same_class_jobs|
|
38
|
+
same_class_jobs.group_by(&:queue_name).each do |queue, same_class_and_queue_jobs|
|
39
|
+
immediate_jobs, scheduled_jobs = same_class_and_queue_jobs.partition { |job| job.scheduled_at.nil? }
|
40
|
+
|
41
|
+
if immediate_jobs.any?
|
42
|
+
jids = Sidekiq::Client.push_bulk(
|
43
|
+
"class" => JobWrapper,
|
44
|
+
"wrapped" => job_class,
|
45
|
+
"queue" => queue,
|
46
|
+
"args" => immediate_jobs.map { |job| [job.serialize] },
|
47
|
+
)
|
48
|
+
enqueued_count += jids.compact.size
|
49
|
+
end
|
50
|
+
|
51
|
+
if scheduled_jobs.any?
|
52
|
+
jids = Sidekiq::Client.push_bulk(
|
53
|
+
"class" => JobWrapper,
|
54
|
+
"wrapped" => job_class,
|
55
|
+
"queue" => queue,
|
56
|
+
"args" => scheduled_jobs.map { |job| [job.serialize] },
|
57
|
+
"at" => scheduled_jobs.map { |job| job.scheduled_at }
|
58
|
+
)
|
59
|
+
enqueued_count += jids.compact.size
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
enqueued_count
|
36
64
|
end
|
37
65
|
|
38
66
|
class JobWrapper # :nodoc:
|
@@ -5,7 +5,7 @@ require "monitor"
|
|
5
5
|
|
6
6
|
module ActiveJob
|
7
7
|
module QueueAdapters
|
8
|
-
#
|
8
|
+
# = Sneakers adapter for Active Job
|
9
9
|
#
|
10
10
|
# A high-performance RabbitMQ background processing framework for Ruby.
|
11
11
|
# Sneakers is being used in production for both I/O and CPU intensive
|
@@ -4,13 +4,13 @@ require "sucker_punch"
|
|
4
4
|
|
5
5
|
module ActiveJob
|
6
6
|
module QueueAdapters
|
7
|
-
#
|
7
|
+
# = Sucker Punch adapter for Active Job
|
8
8
|
#
|
9
9
|
# Sucker Punch is a single-process Ruby asynchronous processing library.
|
10
10
|
# This reduces the cost of hosting on a service like Heroku along
|
11
11
|
# with the memory footprint of having to maintain additional jobs if
|
12
12
|
# hosting on a dedicated server. All queues can run within a
|
13
|
-
# single application (e.g. Rails, Sinatra, etc.) process.
|
13
|
+
# single application (e.g. \Rails, Sinatra, etc.) process.
|
14
14
|
#
|
15
15
|
# Read more about Sucker Punch {here}[https://github.com/brandonhilkert/sucker_punch].
|
16
16
|
#
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module ActiveJob
|
4
4
|
module QueueAdapters
|
5
|
-
#
|
5
|
+
# = Test adapter for Active Job
|
6
6
|
#
|
7
7
|
# The test adapter should be used only in testing. Along with
|
8
8
|
# ActiveJob::TestCase and ActiveJob::TestHelper
|
9
|
-
# it makes a great tool to test your Rails application.
|
9
|
+
# it makes a great tool to test your \Rails application.
|
10
10
|
#
|
11
11
|
# To use the test adapter set +queue_adapter+ config to +:test+.
|
12
12
|
#
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveJob
|
4
|
-
#
|
4
|
+
# = Active Job adapters
|
5
5
|
#
|
6
6
|
# Active Job has adapters for the following queuing backends:
|
7
7
|
#
|
@@ -13,10 +13,14 @@ module ActiveJob
|
|
13
13
|
# * {Sidekiq}[https://sidekiq.org]
|
14
14
|
# * {Sneakers}[https://github.com/jondot/sneakers]
|
15
15
|
# * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
|
16
|
-
# * {Active Job Async Job}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html]
|
17
|
-
# * {Active Job Inline}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html]
|
18
16
|
# * Please Note: We are not accepting pull requests for new adapters. See the {README}[link:files/activejob/README_md.html] for more details.
|
19
17
|
#
|
18
|
+
# For testing and development Active Job has three built-in adapters:
|
19
|
+
#
|
20
|
+
# * {Active Job Async}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html]
|
21
|
+
# * {Active Job Inline}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html]
|
22
|
+
# * {Active Job Test}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/TestAdapter.html]
|
23
|
+
#
|
20
24
|
# === Backends Features
|
21
25
|
#
|
22
26
|
# | | Async | Queues | Delayed | Priorities | Timeout | Retries |
|
@@ -31,6 +35,7 @@ module ActiveJob
|
|
31
35
|
# | Sucker Punch | Yes | Yes | Yes | No | No | No |
|
32
36
|
# | Active Job Async | Yes | Yes | Yes | No | No | No |
|
33
37
|
# | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
|
38
|
+
# | Active Job Test | No | Yes | N/A | N/A | N/A | N/A |
|
34
39
|
#
|
35
40
|
# ==== Async
|
36
41
|
#
|
@@ -106,10 +111,6 @@ module ActiveJob
|
|
106
111
|
# N/A: The adapter does not run in a separate process, and therefore doesn't
|
107
112
|
# support retries.
|
108
113
|
#
|
109
|
-
# === Async and Inline Queue Adapters
|
110
|
-
#
|
111
|
-
# Active Job has two built-in queue adapters intended for development and
|
112
|
-
# testing: +:async+ and +:inline+.
|
113
114
|
module QueueAdapters
|
114
115
|
extend ActiveSupport::Autoload
|
115
116
|
|
@@ -18,7 +18,24 @@ module ActiveJob
|
|
18
18
|
# end
|
19
19
|
# end
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# Can be given a block that will evaluate in the context of the job
|
22
|
+
# so that a dynamic priority can be applied:
|
23
|
+
#
|
24
|
+
# class PublishToFeedJob < ApplicationJob
|
25
|
+
# queue_with_priority do
|
26
|
+
# post = self.arguments.first
|
27
|
+
#
|
28
|
+
# if post.paid?
|
29
|
+
# 10
|
30
|
+
# else
|
31
|
+
# 50
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def perform(post)
|
36
|
+
# post.to_feed!
|
37
|
+
# end
|
38
|
+
# end
|
22
39
|
def queue_with_priority(priority = nil, &block)
|
23
40
|
if block_given?
|
24
41
|
self.priority = block
|
data/lib/active_job/railtie.rb
CHANGED
@@ -10,6 +10,10 @@ module ActiveJob
|
|
10
10
|
config.active_job.custom_serializers = []
|
11
11
|
config.active_job.log_query_tags_around_perform = true
|
12
12
|
|
13
|
+
initializer "active_job.deprecator", before: :load_environment_config do |app|
|
14
|
+
app.deprecators[:active_job] = ActiveJob.deprecator
|
15
|
+
end
|
16
|
+
|
13
17
|
initializer "active_job.logger" do
|
14
18
|
ActiveSupport.on_load(:active_job) { self.logger = ::Rails.logger }
|
15
19
|
end
|
@@ -25,6 +29,15 @@ module ActiveJob
|
|
25
29
|
options = app.config.active_job
|
26
30
|
options.queue_adapter ||= :async
|
27
31
|
|
32
|
+
config.after_initialize do
|
33
|
+
options.each do |k, v|
|
34
|
+
k = "#{k}="
|
35
|
+
if ActiveJob.respond_to?(k)
|
36
|
+
ActiveJob.send(k, v)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
28
41
|
ActiveSupport.on_load(:active_job) do
|
29
42
|
# Configs used in other initializers
|
30
43
|
options = options.except(
|
@@ -32,19 +45,19 @@ module ActiveJob
|
|
32
45
|
:custom_serializers
|
33
46
|
)
|
34
47
|
|
35
|
-
options.each do
|
48
|
+
options.each do |k, v|
|
36
49
|
k = "#{k}="
|
37
|
-
|
50
|
+
if ActiveJob.respond_to?(k)
|
51
|
+
ActiveJob.send(k, v)
|
52
|
+
elsif respond_to? k
|
53
|
+
send(k, v)
|
54
|
+
end
|
38
55
|
end
|
39
56
|
end
|
40
57
|
|
41
58
|
ActiveSupport.on_load(:action_dispatch_integration_test) do
|
42
59
|
include ActiveJob::TestHelper
|
43
60
|
end
|
44
|
-
|
45
|
-
ActiveSupport.on_load(:active_record) do
|
46
|
-
self.destroy_association_async_job = ActiveRecord::DestroyAssociationAsyncJob
|
47
|
-
end
|
48
61
|
end
|
49
62
|
|
50
63
|
initializer "active_job.set_reloader_hook" do |app|
|
@@ -70,5 +83,11 @@ module ActiveJob
|
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
86
|
+
|
87
|
+
initializer "active_job.backtrace_cleaner" do
|
88
|
+
ActiveSupport.on_load(:active_job) do
|
89
|
+
LogSubscriber.backtrace_cleaner = ::Rails.backtrace_cleaner
|
90
|
+
end
|
91
|
+
end
|
73
92
|
end
|
74
93
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bigdecimal"
|
4
|
+
|
5
|
+
module ActiveJob
|
6
|
+
module Serializers
|
7
|
+
class BigDecimalSerializer < ObjectSerializer # :nodoc:
|
8
|
+
def serialize(big_decimal)
|
9
|
+
super("value" => big_decimal.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def deserialize(hash)
|
13
|
+
BigDecimal(hash["value"])
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def klass
|
18
|
+
BigDecimal
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,14 +4,16 @@ module ActiveJob
|
|
4
4
|
module Serializers
|
5
5
|
class DurationSerializer < ObjectSerializer # :nodoc:
|
6
6
|
def serialize(duration)
|
7
|
+
# Ideally duration.parts would be wrapped in an array before passing to Arguments.serialize,
|
8
|
+
# but we continue passing the bare hash for backwards compatibility:
|
7
9
|
super("value" => duration.value, "parts" => Arguments.serialize(duration.parts))
|
8
10
|
end
|
9
11
|
|
10
12
|
def deserialize(hash)
|
11
13
|
value = hash["value"]
|
12
14
|
parts = Arguments.deserialize(hash["parts"])
|
13
|
-
|
14
|
-
klass.new(value, parts)
|
15
|
+
# `parts` is originally a hash, but will have been flattened to an array by Arguments.serialize
|
16
|
+
klass.new(value, parts.to_h)
|
15
17
|
end
|
16
18
|
|
17
19
|
private
|
@@ -3,7 +3,9 @@
|
|
3
3
|
require "set"
|
4
4
|
|
5
5
|
module ActiveJob
|
6
|
-
#
|
6
|
+
# = Active Job \Serializers
|
7
|
+
#
|
8
|
+
# The +ActiveJob::Serializers+ module is used to store a list of known serializers
|
7
9
|
# and to add new ones. It also has helpers to serialize/deserialize objects.
|
8
10
|
module Serializers # :nodoc:
|
9
11
|
extend ActiveSupport::Autoload
|
@@ -18,6 +20,7 @@ module ActiveJob
|
|
18
20
|
autoload :TimeSerializer
|
19
21
|
autoload :ModuleSerializer
|
20
22
|
autoload :RangeSerializer
|
23
|
+
autoload :BigDecimalSerializer
|
21
24
|
|
22
25
|
mattr_accessor :_additional_serializers
|
23
26
|
self._additional_serializers = Set.new
|
@@ -25,7 +28,7 @@ module ActiveJob
|
|
25
28
|
class << self
|
26
29
|
# Returns serialized representative of the passed object.
|
27
30
|
# Will look up through all known serializers.
|
28
|
-
# Raises
|
31
|
+
# Raises ActiveJob::SerializationError if it can't find a proper serializer.
|
29
32
|
def serialize(argument)
|
30
33
|
serializer = serializers.detect { |s| s.serialize?(argument) }
|
31
34
|
raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
|
@@ -63,6 +66,7 @@ module ActiveJob
|
|
63
66
|
TimeWithZoneSerializer,
|
64
67
|
TimeSerializer,
|
65
68
|
ModuleSerializer,
|
66
|
-
RangeSerializer
|
69
|
+
RangeSerializer,
|
70
|
+
BigDecimalSerializer
|
67
71
|
end
|
68
72
|
end
|