activejob 7.2.2.1 → 8.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +90 -50
- data/README.md +8 -6
- data/lib/active_job/arguments.rb +51 -48
- data/lib/active_job/base.rb +5 -6
- data/lib/active_job/configured_job.rb +5 -4
- data/lib/active_job/continuable.rb +102 -0
- data/lib/active_job/continuation/step.rb +83 -0
- data/lib/active_job/continuation/test_helper.rb +89 -0
- data/lib/active_job/continuation/validation.rb +50 -0
- data/lib/active_job/continuation.rb +332 -0
- data/lib/active_job/core.rb +22 -4
- data/lib/active_job/enqueue_after_transaction_commit.rb +20 -10
- data/lib/active_job/enqueuing.rb +11 -8
- data/lib/active_job/exceptions.rb +16 -6
- data/lib/active_job/execution_state.rb +11 -0
- data/lib/active_job/gem_version.rb +3 -3
- data/lib/active_job/instrumentation.rb +12 -12
- data/lib/active_job/log_subscriber.rb +64 -5
- data/lib/active_job/queue_adapter.rb +1 -0
- data/lib/active_job/queue_adapters/abstract_adapter.rb +5 -7
- data/lib/active_job/queue_adapters/async_adapter.rb +6 -2
- data/lib/active_job/queue_adapters/delayed_job_adapter.rb +0 -8
- data/lib/active_job/queue_adapters/inline_adapter.rb +0 -4
- data/lib/active_job/queue_adapters/queue_classic_adapter.rb +0 -8
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +19 -0
- data/lib/active_job/queue_adapters/test_adapter.rb +5 -9
- data/lib/active_job/queue_adapters.rb +0 -4
- data/lib/active_job/railtie.rb +15 -6
- data/lib/active_job/serializers/action_controller_parameters_serializer.rb +25 -0
- data/lib/active_job/serializers/big_decimal_serializer.rb +3 -4
- data/lib/active_job/serializers/date_serializer.rb +3 -4
- data/lib/active_job/serializers/date_time_serializer.rb +3 -4
- data/lib/active_job/serializers/duration_serializer.rb +5 -6
- data/lib/active_job/serializers/module_serializer.rb +3 -4
- data/lib/active_job/serializers/object_serializer.rb +11 -14
- data/lib/active_job/serializers/range_serializer.rb +9 -9
- data/lib/active_job/serializers/symbol_serializer.rb +4 -5
- data/lib/active_job/serializers/time_serializer.rb +3 -4
- data/lib/active_job/serializers/time_with_zone_serializer.rb +3 -4
- data/lib/active_job/serializers.rb +62 -18
- data/lib/active_job/structured_event_subscriber.rb +220 -0
- data/lib/active_job.rb +3 -12
- metadata +17 -15
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +0 -49
- data/lib/active_job/timezones.rb +0 -13
- data/lib/active_job/translation.rb +0 -13
|
@@ -26,24 +26,24 @@ module ActiveJob
|
|
|
26
26
|
instrument(:perform) { super }
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def instrument(operation, payload = {}, &block) # :nodoc:
|
|
30
|
+
payload[:job] = self
|
|
31
|
+
payload[:adapter] = queue_adapter
|
|
32
|
+
|
|
33
|
+
ActiveSupport::Notifications.instrument("#{operation}.active_job", payload) do |payload|
|
|
34
|
+
value = block.call(payload) if block
|
|
35
|
+
payload[:aborted] = @_halted_callback_hook_called if defined?(@_halted_callback_hook_called)
|
|
36
|
+
@_halted_callback_hook_called = nil
|
|
37
|
+
value
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
29
41
|
private
|
|
30
42
|
def _perform_job
|
|
31
43
|
instrument(:perform_start)
|
|
32
44
|
super
|
|
33
45
|
end
|
|
34
46
|
|
|
35
|
-
def instrument(operation, payload = {}, &block)
|
|
36
|
-
payload[:job] = self
|
|
37
|
-
payload[:adapter] = queue_adapter
|
|
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
|
|
43
|
-
value
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
47
|
def halted_callback_hook(*)
|
|
48
48
|
super
|
|
49
49
|
@_halted_callback_hook_called = true
|
|
@@ -50,7 +50,7 @@ module ActiveJob
|
|
|
50
50
|
info do
|
|
51
51
|
jobs = event.payload[:jobs]
|
|
52
52
|
adapter = event.payload[:adapter]
|
|
53
|
-
enqueued_count = event.payload[:enqueued_count]
|
|
53
|
+
enqueued_count = event.payload[:enqueued_count].to_i
|
|
54
54
|
|
|
55
55
|
if enqueued_count == jobs.size
|
|
56
56
|
enqueued_jobs_message(adapter, jobs)
|
|
@@ -87,8 +87,9 @@ module ActiveJob
|
|
|
87
87
|
job = event.payload[:job]
|
|
88
88
|
ex = event.payload[:exception_object]
|
|
89
89
|
if ex
|
|
90
|
+
cleaned_backtrace = backtrace_cleaner.clean(ex.backtrace)
|
|
90
91
|
error do
|
|
91
|
-
"Error performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms: #{ex.class} (#{ex.message}):\n" + Array(
|
|
92
|
+
"Error performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms: #{ex.class} (#{ex.message}):\n" + Array(cleaned_backtrace).join("\n")
|
|
92
93
|
end
|
|
93
94
|
elsif event.payload[:aborted]
|
|
94
95
|
error do
|
|
@@ -137,6 +138,64 @@ module ActiveJob
|
|
|
137
138
|
end
|
|
138
139
|
subscribe_log_level :discard, :error
|
|
139
140
|
|
|
141
|
+
def interrupt(event)
|
|
142
|
+
job = event.payload[:job]
|
|
143
|
+
info do
|
|
144
|
+
"Interrupted #{job.class} (Job ID: #{job.job_id}) #{event.payload[:description]} (#{event.payload[:reason]})"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
subscribe_log_level :interrupt, :info
|
|
148
|
+
|
|
149
|
+
def resume(event)
|
|
150
|
+
job = event.payload[:job]
|
|
151
|
+
info do
|
|
152
|
+
"Resuming #{job.class} (Job ID: #{job.job_id}) #{event.payload[:description]}"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
subscribe_log_level :resume, :info
|
|
156
|
+
|
|
157
|
+
def step_skipped(event)
|
|
158
|
+
job = event.payload[:job]
|
|
159
|
+
info do
|
|
160
|
+
"Step '#{event.payload[:step].name}' skipped #{job.class}"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
subscribe_log_level :step_skipped, :info
|
|
164
|
+
|
|
165
|
+
def step_started(event)
|
|
166
|
+
job = event.payload[:job]
|
|
167
|
+
step = event.payload[:step]
|
|
168
|
+
info do
|
|
169
|
+
if step.resumed?
|
|
170
|
+
"Step '#{step.name}' resumed from cursor '#{step.cursor}' for #{job.class} (Job ID: #{job.job_id})"
|
|
171
|
+
else
|
|
172
|
+
"Step '#{step.name}' started for #{job.class} (Job ID: #{job.job_id})"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
subscribe_log_level :step_started, :info
|
|
177
|
+
|
|
178
|
+
def step(event)
|
|
179
|
+
job = event.payload[:job]
|
|
180
|
+
step = event.payload[:step]
|
|
181
|
+
ex = event.payload[:exception_object]
|
|
182
|
+
|
|
183
|
+
if event.payload[:interrupted]
|
|
184
|
+
info do
|
|
185
|
+
"Step '#{step.name}' interrupted at cursor '#{step.cursor}' for #{job.class} (Job ID: #{job.job_id}) in #{event.duration.round(2)}ms"
|
|
186
|
+
end
|
|
187
|
+
elsif ex
|
|
188
|
+
error do
|
|
189
|
+
"Error during step '#{step.name}' at cursor '#{step.cursor}' for #{job.class} (Job ID: #{job.job_id}) in #{event.duration.round(2)}ms: #{ex.class} (#{ex.message})"
|
|
190
|
+
end
|
|
191
|
+
else
|
|
192
|
+
info do
|
|
193
|
+
"Step '#{step.name}' completed for #{job.class} (Job ID: #{job.job_id}) in #{event.duration.round(2)}ms"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
subscribe_log_level :step, :error
|
|
198
|
+
|
|
140
199
|
private
|
|
141
200
|
def queue_name(event)
|
|
142
201
|
ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
|
|
@@ -189,15 +248,15 @@ module ActiveJob
|
|
|
189
248
|
end
|
|
190
249
|
|
|
191
250
|
def log_enqueue_source
|
|
192
|
-
source =
|
|
251
|
+
source = enqueue_source_location
|
|
193
252
|
|
|
194
253
|
if source
|
|
195
254
|
logger.info("↳ #{source}")
|
|
196
255
|
end
|
|
197
256
|
end
|
|
198
257
|
|
|
199
|
-
def
|
|
200
|
-
backtrace_cleaner.
|
|
258
|
+
def enqueue_source_location
|
|
259
|
+
backtrace_cleaner.first_clean_frame
|
|
201
260
|
end
|
|
202
261
|
|
|
203
262
|
def enqueued_jobs_message(adapter, enqueued_jobs)
|
|
@@ -50,6 +50,7 @@ module ActiveJob
|
|
|
50
50
|
case name_or_adapter
|
|
51
51
|
when Symbol, String
|
|
52
52
|
queue_adapter = ActiveJob::QueueAdapters.lookup(name_or_adapter).new
|
|
53
|
+
queue_adapter.try(:check_adapter)
|
|
53
54
|
assign_adapter(name_or_adapter.to_s, queue_adapter)
|
|
54
55
|
else
|
|
55
56
|
if queue_adapter?(name_or_adapter)
|
|
@@ -7,13 +7,7 @@ module ActiveJob
|
|
|
7
7
|
# Active Job supports multiple job queue systems. ActiveJob::QueueAdapters::AbstractAdapter
|
|
8
8
|
# forms the abstraction layer which makes this possible.
|
|
9
9
|
class AbstractAdapter
|
|
10
|
-
|
|
11
|
-
# from inside a transaction. Most adapters should return true, but some adapters
|
|
12
|
-
# that use the same database as Active Record and are transaction aware can return
|
|
13
|
-
# false to continue enqueuing jobs as part of the transaction.
|
|
14
|
-
def enqueue_after_transaction_commit?
|
|
15
|
-
true
|
|
16
|
-
end
|
|
10
|
+
attr_accessor :stopping
|
|
17
11
|
|
|
18
12
|
def enqueue(job)
|
|
19
13
|
raise NotImplementedError
|
|
@@ -22,6 +16,10 @@ module ActiveJob
|
|
|
22
16
|
def enqueue_at(job, timestamp)
|
|
23
17
|
raise NotImplementedError
|
|
24
18
|
end
|
|
19
|
+
|
|
20
|
+
def stopping?
|
|
21
|
+
!!@stopping
|
|
22
|
+
end
|
|
25
23
|
end
|
|
26
24
|
end
|
|
27
25
|
end
|
|
@@ -74,7 +74,7 @@ module ActiveJob
|
|
|
74
74
|
class Scheduler # :nodoc:
|
|
75
75
|
DEFAULT_EXECUTOR_OPTIONS = {
|
|
76
76
|
min_threads: 0,
|
|
77
|
-
max_threads:
|
|
77
|
+
max_threads: ENV.fetch("RAILS_MAX_THREADS", 5).to_i,
|
|
78
78
|
auto_terminate: true,
|
|
79
79
|
idletime: 60, # 1 minute
|
|
80
80
|
max_queue: 0, # unlimited
|
|
@@ -86,7 +86,11 @@ module ActiveJob
|
|
|
86
86
|
def initialize(**options)
|
|
87
87
|
self.immediate = false
|
|
88
88
|
@immediate_executor = Concurrent::ImmediateExecutor.new
|
|
89
|
-
@async_executor = Concurrent::ThreadPoolExecutor.new(
|
|
89
|
+
@async_executor = Concurrent::ThreadPoolExecutor.new(
|
|
90
|
+
name: "ActiveJob-async-scheduler",
|
|
91
|
+
**DEFAULT_EXECUTOR_OPTIONS,
|
|
92
|
+
**options
|
|
93
|
+
)
|
|
90
94
|
end
|
|
91
95
|
|
|
92
96
|
def enqueue(job, queue_name:)
|
|
@@ -16,14 +16,6 @@ module ActiveJob
|
|
|
16
16
|
#
|
|
17
17
|
# Rails.application.config.active_job.queue_adapter = :delayed_job
|
|
18
18
|
class DelayedJobAdapter < AbstractAdapter
|
|
19
|
-
def initialize(enqueue_after_transaction_commit: false)
|
|
20
|
-
@enqueue_after_transaction_commit = enqueue_after_transaction_commit
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def enqueue_after_transaction_commit? # :nodoc:
|
|
24
|
-
@enqueue_after_transaction_commit
|
|
25
|
-
end
|
|
26
|
-
|
|
27
19
|
def enqueue(job) # :nodoc:
|
|
28
20
|
delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, priority: job.priority)
|
|
29
21
|
job.provider_job_id = delayed_job.id
|
|
@@ -11,10 +11,6 @@ module ActiveJob
|
|
|
11
11
|
#
|
|
12
12
|
# Rails.application.config.active_job.queue_adapter = :inline
|
|
13
13
|
class InlineAdapter < AbstractAdapter
|
|
14
|
-
def enqueue_after_transaction_commit? # :nodoc:
|
|
15
|
-
false
|
|
16
|
-
end
|
|
17
|
-
|
|
18
14
|
def enqueue(job) # :nodoc:
|
|
19
15
|
Base.execute(job.serialize)
|
|
20
16
|
end
|
|
@@ -19,14 +19,6 @@ module ActiveJob
|
|
|
19
19
|
#
|
|
20
20
|
# Rails.application.config.active_job.queue_adapter = :queue_classic
|
|
21
21
|
class QueueClassicAdapter < AbstractAdapter
|
|
22
|
-
def initialize(enqueue_after_transaction_commit: false)
|
|
23
|
-
@enqueue_after_transaction_commit = enqueue_after_transaction_commit
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def enqueue_after_transaction_commit? # :nodoc:
|
|
27
|
-
@enqueue_after_transaction_commit
|
|
28
|
-
end
|
|
29
|
-
|
|
30
22
|
def enqueue(job) # :nodoc:
|
|
31
23
|
qc_job = build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
|
|
32
24
|
job.provider_job_id = qc_job["id"] if qc_job.is_a?(Hash)
|
|
@@ -18,6 +18,25 @@ module ActiveJob
|
|
|
18
18
|
#
|
|
19
19
|
# Rails.application.config.active_job.queue_adapter = :sidekiq
|
|
20
20
|
class SidekiqAdapter < AbstractAdapter
|
|
21
|
+
def initialize(*) # :nodoc:
|
|
22
|
+
@stopping = false
|
|
23
|
+
|
|
24
|
+
Sidekiq.configure_server do |config|
|
|
25
|
+
config.on(:quiet) { @stopping = true }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Sidekiq.configure_client do |config|
|
|
29
|
+
config.on(:quiet) { @stopping = true }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check_adapter
|
|
34
|
+
ActiveJob.deprecator.warn <<~MSG.squish
|
|
35
|
+
The built-in `sidekiq` adapter is deprecated and will be removed in Rails 8.2.
|
|
36
|
+
Please upgrade `sidekiq` gem to version 7.3.3 or later to use the `sidekiq` gem's adapter.
|
|
37
|
+
MSG
|
|
38
|
+
end
|
|
39
|
+
|
|
21
40
|
def enqueue(job) # :nodoc:
|
|
22
41
|
job.provider_job_id = JobWrapper.set(
|
|
23
42
|
wrapped: job.class,
|
|
@@ -12,17 +12,9 @@ module ActiveJob
|
|
|
12
12
|
#
|
|
13
13
|
# Rails.application.config.active_job.queue_adapter = :test
|
|
14
14
|
class TestAdapter < AbstractAdapter
|
|
15
|
-
attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at, :
|
|
15
|
+
attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at, :stopping)
|
|
16
16
|
attr_writer(:enqueued_jobs, :performed_jobs)
|
|
17
17
|
|
|
18
|
-
def initialize(enqueue_after_transaction_commit: true)
|
|
19
|
-
@enqueue_after_transaction_commit = enqueue_after_transaction_commit
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def enqueue_after_transaction_commit? # :nodoc:
|
|
23
|
-
@enqueue_after_transaction_commit
|
|
24
|
-
end
|
|
25
|
-
|
|
26
18
|
# Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
|
|
27
19
|
def enqueued_jobs
|
|
28
20
|
@enqueued_jobs ||= []
|
|
@@ -43,6 +35,10 @@ module ActiveJob
|
|
|
43
35
|
perform_or_enqueue(perform_enqueued_at_jobs && !filtered?(job), job, job_data)
|
|
44
36
|
end
|
|
45
37
|
|
|
38
|
+
def stopping?
|
|
39
|
+
@stopping.is_a?(Proc) ? @stopping.call : @stopping
|
|
40
|
+
end
|
|
41
|
+
|
|
46
42
|
private
|
|
47
43
|
def job_to_hash(job, extras = {})
|
|
48
44
|
job.serialize.tap do |job_data|
|
|
@@ -12,7 +12,6 @@ module ActiveJob
|
|
|
12
12
|
# * {Resque}[https://github.com/resque/resque]
|
|
13
13
|
# * {Sidekiq}[https://sidekiq.org]
|
|
14
14
|
# * {Sneakers}[https://github.com/jondot/sneakers]
|
|
15
|
-
# * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
|
|
16
15
|
# * Please Note: We are not accepting pull requests for new adapters. See the {README}[link:files/activejob/README_md.html] for more details.
|
|
17
16
|
#
|
|
18
17
|
# For testing and development Active Job has three built-in adapters:
|
|
@@ -32,7 +31,6 @@ module ActiveJob
|
|
|
32
31
|
# | Resque | Yes | Yes | Yes (Gem) | Queue | Global | Yes |
|
|
33
32
|
# | Sidekiq | Yes | Yes | Yes | Queue | No | Job |
|
|
34
33
|
# | Sneakers | Yes | Yes | No | Queue | Queue | No |
|
|
35
|
-
# | Sucker Punch | Yes | Yes | Yes | No | No | No |
|
|
36
34
|
# | Active Job Async | Yes | Yes | Yes | No | No | No |
|
|
37
35
|
# | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
|
|
38
36
|
# | Active Job Test | No | Yes | N/A | N/A | N/A | N/A |
|
|
@@ -119,12 +117,10 @@ module ActiveJob
|
|
|
119
117
|
autoload :InlineAdapter
|
|
120
118
|
autoload :BackburnerAdapter
|
|
121
119
|
autoload :DelayedJobAdapter
|
|
122
|
-
autoload :QueAdapter
|
|
123
120
|
autoload :QueueClassicAdapter
|
|
124
121
|
autoload :ResqueAdapter
|
|
125
122
|
autoload :SidekiqAdapter
|
|
126
123
|
autoload :SneakersAdapter
|
|
127
|
-
autoload :SuckerPunchAdapter
|
|
128
124
|
autoload :TestAdapter
|
|
129
125
|
|
|
130
126
|
ADAPTER = "Adapter"
|
data/lib/active_job/railtie.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "rails"
|
|
3
4
|
require "global_id/railtie"
|
|
4
5
|
require "active_job"
|
|
5
6
|
|
|
@@ -19,7 +20,7 @@ module ActiveJob
|
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
initializer "active_job.custom_serializers" do |app|
|
|
22
|
-
|
|
23
|
+
ActiveSupport.on_load(:active_job_arguments) do
|
|
23
24
|
custom_serializers = app.config.active_job.custom_serializers
|
|
24
25
|
ActiveJob::Serializers.add_serializers custom_serializers
|
|
25
26
|
end
|
|
@@ -29,10 +30,14 @@ module ActiveJob
|
|
|
29
30
|
ActiveSupport.on_load(:active_job) do
|
|
30
31
|
ActiveSupport.on_load(:active_record) do
|
|
31
32
|
ActiveJob::Base.include EnqueueAfterTransactionCommit
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
initializer "active_job.action_controller_parameters" do |app|
|
|
38
|
+
ActiveSupport.on_load(:active_job) do
|
|
39
|
+
ActiveSupport.on_load(:action_controller) do
|
|
40
|
+
ActiveJob::Serializers.add_serializers ActiveJob::Serializers::ActionControllerParametersSerializer
|
|
36
41
|
end
|
|
37
42
|
end
|
|
38
43
|
end
|
|
@@ -54,7 +59,9 @@ module ActiveJob
|
|
|
54
59
|
# Configs used in other initializers
|
|
55
60
|
options = options.except(
|
|
56
61
|
:log_query_tags_around_perform,
|
|
57
|
-
:custom_serializers
|
|
62
|
+
:custom_serializers,
|
|
63
|
+
# This config can't be applied globally, so we need to remove otherwise it will be applied to `ActiveJob::Base`.
|
|
64
|
+
:enqueue_after_transaction_commit
|
|
58
65
|
)
|
|
59
66
|
|
|
60
67
|
options.each do |k, v|
|
|
@@ -91,7 +98,9 @@ module ActiveJob
|
|
|
91
98
|
app.config.active_record.query_log_tags |= [:job]
|
|
92
99
|
|
|
93
100
|
ActiveSupport.on_load(:active_record) do
|
|
94
|
-
ActiveRecord::QueryLogs.taggings
|
|
101
|
+
ActiveRecord::QueryLogs.taggings = ActiveRecord::QueryLogs.taggings.merge(
|
|
102
|
+
job: ->(context) { context[:job].class.name if context[:job] }
|
|
103
|
+
)
|
|
95
104
|
end
|
|
96
105
|
end
|
|
97
106
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveJob
|
|
4
|
+
module Serializers
|
|
5
|
+
class ActionControllerParametersSerializer < ObjectSerializer
|
|
6
|
+
def serialize(argument)
|
|
7
|
+
Arguments.serialize_argument(argument.to_h.with_indifferent_access)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def deserialize(hash)
|
|
11
|
+
raise NotImplementedError # Serialized as a HashWithIndifferentAccess
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def serialize?(argument)
|
|
15
|
+
argument.respond_to?(:permitted?) && argument.respond_to?(:to_h)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def klass
|
|
19
|
+
if defined?(ActionController::Parameters)
|
|
20
|
+
ActionController::Parameters
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -6,20 +6,19 @@ module ActiveJob
|
|
|
6
6
|
def serialize(duration)
|
|
7
7
|
# Ideally duration.parts would be wrapped in an array before passing to Arguments.serialize,
|
|
8
8
|
# but we continue passing the bare hash for backwards compatibility:
|
|
9
|
-
super("value" => duration.value, "parts" => Arguments.serialize(duration.parts))
|
|
9
|
+
super("value" => duration.value, "parts" => Arguments.serialize(duration.parts.to_a))
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def deserialize(hash)
|
|
13
13
|
value = hash["value"]
|
|
14
|
-
parts = Arguments.deserialize(hash["parts"])
|
|
14
|
+
parts = Arguments.deserialize(hash["parts"].to_h)
|
|
15
15
|
# `parts` is originally a hash, but will have been flattened to an array by Arguments.serialize
|
|
16
16
|
klass.new(value, parts.to_h)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
19
|
+
def klass
|
|
20
|
+
ActiveSupport::Duration
|
|
21
|
+
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
end
|
|
@@ -17,11 +17,9 @@ module ActiveJob
|
|
|
17
17
|
# Money.new(hash["amount"], hash["currency"])
|
|
18
18
|
# end
|
|
19
19
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# Money
|
|
24
|
-
# end
|
|
20
|
+
# def klass
|
|
21
|
+
# Money
|
|
22
|
+
# end
|
|
25
23
|
# end
|
|
26
24
|
class ObjectSerializer
|
|
27
25
|
include Singleton
|
|
@@ -30,6 +28,11 @@ module ActiveJob
|
|
|
30
28
|
delegate :serialize?, :serialize, :deserialize, to: :instance
|
|
31
29
|
end
|
|
32
30
|
|
|
31
|
+
def initialize
|
|
32
|
+
super
|
|
33
|
+
@template = { Serializers::OBJECT_SERIALIZER_KEY => self.class.name }.freeze
|
|
34
|
+
end
|
|
35
|
+
|
|
33
36
|
# Determines if an argument should be serialized by a serializer.
|
|
34
37
|
def serialize?(argument)
|
|
35
38
|
argument.is_a?(klass)
|
|
@@ -37,19 +40,13 @@ module ActiveJob
|
|
|
37
40
|
|
|
38
41
|
# Serializes an argument to a JSON primitive type.
|
|
39
42
|
def serialize(hash)
|
|
40
|
-
|
|
43
|
+
@template.merge(hash)
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
# Deserializes an argument from a JSON primitive type.
|
|
44
|
-
def deserialize(
|
|
45
|
-
raise NotImplementedError
|
|
47
|
+
def deserialize(hash)
|
|
48
|
+
raise NotImplementedError, "#{self.class.name} should implement a public #deserialize(hash) method"
|
|
46
49
|
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
# The class of the object that will be serialized.
|
|
50
|
-
def klass # :doc:
|
|
51
|
-
raise NotImplementedError
|
|
52
|
-
end
|
|
53
50
|
end
|
|
54
51
|
end
|
|
55
52
|
end
|
|
@@ -3,21 +3,21 @@
|
|
|
3
3
|
module ActiveJob
|
|
4
4
|
module Serializers
|
|
5
5
|
class RangeSerializer < ObjectSerializer
|
|
6
|
-
KEYS = %w[begin end exclude_end].freeze
|
|
7
|
-
|
|
8
6
|
def serialize(range)
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
super(
|
|
8
|
+
"begin" => Arguments.serialize_argument(range.begin),
|
|
9
|
+
"end" => Arguments.serialize_argument(range.end),
|
|
10
|
+
"exclude_end" => range.exclude_end?, # Always boolean, no need to serialize
|
|
11
|
+
)
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def deserialize(hash)
|
|
14
|
-
|
|
15
|
+
Range.new(*Arguments.deserialize([hash["begin"], hash["end"]]), hash["exclude_end"])
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
18
|
+
def klass
|
|
19
|
+
::Range
|
|
20
|
+
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -4,17 +4,16 @@ module ActiveJob
|
|
|
4
4
|
module Serializers
|
|
5
5
|
class SymbolSerializer < ObjectSerializer # :nodoc:
|
|
6
6
|
def serialize(argument)
|
|
7
|
-
super("value" => argument.
|
|
7
|
+
super("value" => argument.name)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def deserialize(argument)
|
|
11
11
|
argument["value"].to_sym
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
end
|
|
14
|
+
def klass
|
|
15
|
+
Symbol
|
|
16
|
+
end
|
|
18
17
|
end
|
|
19
18
|
end
|
|
20
19
|
end
|