activejob 6.0.3.3 → 6.1.1
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 +82 -149
- data/MIT-LICENSE +1 -1
- data/README.md +1 -3
- data/lib/active_job.rb +1 -1
- data/lib/active_job/base.rb +3 -0
- data/lib/active_job/callbacks.rb +44 -4
- data/lib/active_job/core.rb +3 -2
- data/lib/active_job/enqueuing.rb +3 -13
- data/lib/active_job/exceptions.rb +29 -20
- data/lib/active_job/execution.rb +9 -1
- data/lib/active_job/gem_version.rb +3 -3
- data/lib/active_job/instrumentation.rb +40 -0
- data/lib/active_job/log_subscriber.rb +140 -0
- data/lib/active_job/logging.rb +3 -132
- data/lib/active_job/queue_adapter.rb +3 -0
- data/lib/active_job/queue_adapters.rb +5 -1
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/test_adapter.rb +6 -2
- data/lib/active_job/queue_name.rb +2 -2
- data/lib/active_job/railtie.rb +4 -0
- data/lib/active_job/serializers.rb +4 -1
- data/lib/active_job/serializers/date_time_serializer.rb +1 -5
- data/lib/active_job/serializers/module_serializer.rb +20 -0
- data/lib/active_job/serializers/object_serializer.rb +1 -1
- data/lib/active_job/serializers/time_object_serializer.rb +13 -0
- data/lib/active_job/serializers/time_serializer.rb +1 -5
- data/lib/active_job/serializers/time_with_zone_serializer.rb +1 -5
- data/lib/active_job/test_helper.rb +81 -80
- metadata +15 -11
data/lib/active_job/enqueuing.rb
CHANGED
@@ -54,9 +54,9 @@ module ActiveJob
|
|
54
54
|
|
55
55
|
run_callbacks :enqueue do
|
56
56
|
if scheduled_at
|
57
|
-
|
57
|
+
queue_adapter.enqueue_at self, scheduled_at
|
58
58
|
else
|
59
|
-
|
59
|
+
queue_adapter.enqueue self
|
60
60
|
end
|
61
61
|
|
62
62
|
successfully_enqueued = true
|
@@ -65,17 +65,7 @@ module ActiveJob
|
|
65
65
|
if successfully_enqueued
|
66
66
|
self
|
67
67
|
else
|
68
|
-
|
69
|
-
false
|
70
|
-
else
|
71
|
-
ActiveSupport::Deprecation.warn(
|
72
|
-
"Rails 6.1 will return false when the enqueuing is aborted. Make sure your code doesn't depend on it" \
|
73
|
-
" returning the instance of the job and set `config.active_job.return_false_on_aborted_enqueue = true`" \
|
74
|
-
" to remove the deprecations."
|
75
|
-
)
|
76
|
-
|
77
|
-
self
|
78
|
-
end
|
68
|
+
false
|
79
69
|
end
|
80
70
|
end
|
81
71
|
end
|
@@ -7,6 +7,10 @@ module ActiveJob
|
|
7
7
|
module Exceptions
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
|
+
included do
|
11
|
+
class_attribute :retry_jitter, instance_accessor: false, instance_predicate: false, default: 0.0
|
12
|
+
end
|
13
|
+
|
10
14
|
module ClassMethods
|
11
15
|
# Catch the exception and reschedule job for re-execution after so many seconds, for a specific number of attempts.
|
12
16
|
# If the exception keeps getting raised beyond the specified number of attempts, the exception is allowed to
|
@@ -18,23 +22,25 @@ module ActiveJob
|
|
18
22
|
#
|
19
23
|
# ==== Options
|
20
24
|
# * <tt>:wait</tt> - Re-enqueues the job with a delay specified either in seconds (default: 3 seconds),
|
21
|
-
# as a computing proc that the number of executions so far as an argument, or as a symbol reference of
|
22
|
-
# <tt>:exponentially_longer</tt>, which applies the wait algorithm of <tt>(executions **
|
23
|
-
# (first wait 3s, then 18s, then 83s, etc)
|
25
|
+
# as a computing proc that takes the number of executions so far as an argument, or as a symbol reference of
|
26
|
+
# <tt>:exponentially_longer</tt>, which applies the wait algorithm of <tt>((executions**4) + (Kernel.rand * (executions**4) * jitter)) + 2</tt>
|
27
|
+
# (first wait ~3s, then ~18s, then ~83s, etc)
|
24
28
|
# * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts)
|
25
29
|
# * <tt>:queue</tt> - Re-enqueues the job on a different queue
|
26
30
|
# * <tt>:priority</tt> - Re-enqueues the job with a different priority
|
31
|
+
# * <tt>:jitter</tt> - A random delay of wait time used when calculating backoff. The default is 15% (0.15) which represents the upper bound of possible wait time (expressed as a percentage)
|
27
32
|
#
|
28
33
|
# ==== Examples
|
29
34
|
#
|
30
35
|
# class RemoteServiceJob < ActiveJob::Base
|
31
|
-
# retry_on CustomAppException # defaults to 3s wait, 5 attempts
|
36
|
+
# retry_on CustomAppException # defaults to ~3s wait, 5 attempts
|
32
37
|
# retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 }
|
33
38
|
#
|
34
39
|
# retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3
|
35
40
|
# retry_on Net::OpenTimeout, Timeout::Error, wait: :exponentially_longer, attempts: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
|
36
41
|
# # To retry at most 10 times for each individual exception:
|
37
42
|
# # retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10
|
43
|
+
# # retry_on Net::ReadTimeout, wait: 5.seconds, jitter: 0.30, attempts: 10
|
38
44
|
# # retry_on Timeout::Error, wait: :exponentially_longer, attempts: 10
|
39
45
|
#
|
40
46
|
# retry_on(YetAnotherCustomAppException) do |job, error|
|
@@ -47,12 +53,11 @@ module ActiveJob
|
|
47
53
|
# # Might raise Net::OpenTimeout or Timeout::Error when the remote service is down
|
48
54
|
# end
|
49
55
|
# end
|
50
|
-
def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
|
56
|
+
def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: JITTER_DEFAULT)
|
51
57
|
rescue_from(*exceptions) do |error|
|
52
58
|
executions = executions_for(exceptions)
|
53
|
-
|
54
59
|
if executions < attempts
|
55
|
-
retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions), queue: queue, priority: priority, error: error
|
60
|
+
retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions, jitter: jitter), queue: queue, priority: priority, error: error
|
56
61
|
else
|
57
62
|
if block_given?
|
58
63
|
instrument :retry_stopped, error: error do
|
@@ -115,22 +120,27 @@ module ActiveJob
|
|
115
120
|
# end
|
116
121
|
# end
|
117
122
|
def retry_job(options = {})
|
118
|
-
instrument :enqueue_retry,
|
123
|
+
instrument :enqueue_retry, options.slice(:error, :wait) do
|
119
124
|
enqueue options
|
120
125
|
end
|
121
126
|
end
|
122
127
|
|
123
128
|
private
|
124
|
-
|
129
|
+
JITTER_DEFAULT = Object.new
|
130
|
+
private_constant :JITTER_DEFAULT
|
131
|
+
|
132
|
+
def determine_delay(seconds_or_duration_or_algorithm:, executions:, jitter: JITTER_DEFAULT)
|
133
|
+
jitter = jitter == JITTER_DEFAULT ? self.class.retry_jitter : (jitter || 0.0)
|
134
|
+
|
125
135
|
case seconds_or_duration_or_algorithm
|
126
136
|
when :exponentially_longer
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
137
|
+
delay = executions**4
|
138
|
+
delay_jitter = determine_jitter_for_delay(delay, jitter)
|
139
|
+
delay + delay_jitter + 2
|
140
|
+
when ActiveSupport::Duration, Integer
|
141
|
+
delay = seconds_or_duration_or_algorithm.to_i
|
142
|
+
delay_jitter = determine_jitter_for_delay(delay, jitter)
|
143
|
+
delay + delay_jitter
|
134
144
|
when Proc
|
135
145
|
algorithm = seconds_or_duration_or_algorithm
|
136
146
|
algorithm.call(executions)
|
@@ -139,10 +149,9 @@ module ActiveJob
|
|
139
149
|
end
|
140
150
|
end
|
141
151
|
|
142
|
-
def
|
143
|
-
|
144
|
-
|
145
|
-
ActiveSupport::Notifications.instrument("#{name}.active_job", payload, &block)
|
152
|
+
def determine_jitter_for_delay(delay, jitter)
|
153
|
+
return 0.0 if jitter.zero?
|
154
|
+
Kernel.rand * delay * jitter
|
146
155
|
end
|
147
156
|
|
148
157
|
def executions_for(exceptions)
|
data/lib/active_job/execution.rb
CHANGED
@@ -29,13 +29,21 @@ module ActiveJob
|
|
29
29
|
|
30
30
|
# Performs the job immediately. The job is not sent to the queuing adapter
|
31
31
|
# but directly executed by blocking the execution of others until it's finished.
|
32
|
+
# `perform_now` returns the value of your job's `perform` method.
|
32
33
|
#
|
33
|
-
# MyJob
|
34
|
+
# class MyJob < ActiveJob::Base
|
35
|
+
# def perform
|
36
|
+
# "Hello World!"
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# puts MyJob.new(*args).perform_now # => "Hello World!"
|
34
41
|
def perform_now
|
35
42
|
# Guard against jobs that were persisted before we started counting executions by zeroing out nil counters
|
36
43
|
self.executions = (executions || 0) + 1
|
37
44
|
|
38
45
|
deserialize_arguments_if_needed
|
46
|
+
|
39
47
|
run_callbacks :perform do
|
40
48
|
perform(*arguments)
|
41
49
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module Instrumentation #:nodoc:
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
around_enqueue do |_, block|
|
9
|
+
scheduled_at ? instrument(:enqueue_at, &block) : instrument(:enqueue, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
around_perform do |_, block|
|
13
|
+
instrument :perform_start
|
14
|
+
instrument :perform, &block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def instrument(operation, payload = {}, &block)
|
20
|
+
enhanced_block = ->(event_payload) do
|
21
|
+
value = block.call if block
|
22
|
+
|
23
|
+
if defined?(@_halted_callback_hook_called) && @_halted_callback_hook_called
|
24
|
+
event_payload[:aborted] = true
|
25
|
+
@_halted_callback_hook_called = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveSupport::Notifications.instrument \
|
32
|
+
"#{operation}.active_job", payload.merge(adapter: queue_adapter, job: self), &enhanced_block
|
33
|
+
end
|
34
|
+
|
35
|
+
def halted_callback_hook(*)
|
36
|
+
super
|
37
|
+
@_halted_callback_hook_called = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/filters"
|
4
|
+
require "active_support/log_subscriber"
|
5
|
+
|
6
|
+
module ActiveJob
|
7
|
+
class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc:
|
8
|
+
def enqueue(event)
|
9
|
+
job = event.payload[:job]
|
10
|
+
ex = event.payload[:exception_object]
|
11
|
+
|
12
|
+
if ex
|
13
|
+
error do
|
14
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}: #{ex.class} (#{ex.message})"
|
15
|
+
end
|
16
|
+
elsif event.payload[:aborted]
|
17
|
+
info do
|
18
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}, a before_enqueue callback halted the enqueuing execution."
|
19
|
+
end
|
20
|
+
else
|
21
|
+
info do
|
22
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def enqueue_at(event)
|
28
|
+
job = event.payload[:job]
|
29
|
+
ex = event.payload[:exception_object]
|
30
|
+
|
31
|
+
if ex
|
32
|
+
error do
|
33
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}: #{ex.class} (#{ex.message})"
|
34
|
+
end
|
35
|
+
elsif event.payload[:aborted]
|
36
|
+
info do
|
37
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}, a before_enqueue callback halted the enqueuing execution."
|
38
|
+
end
|
39
|
+
else
|
40
|
+
info do
|
41
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def perform_start(event)
|
47
|
+
info do
|
48
|
+
job = event.payload[:job]
|
49
|
+
"Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} enqueued at #{job.enqueued_at}" + args_info(job)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def perform(event)
|
54
|
+
job = event.payload[:job]
|
55
|
+
ex = event.payload[:exception_object]
|
56
|
+
if ex
|
57
|
+
error do
|
58
|
+
"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(ex.backtrace).join("\n")
|
59
|
+
end
|
60
|
+
elsif event.payload[:aborted]
|
61
|
+
error do
|
62
|
+
"Error performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms: a before_perform callback halted the job execution"
|
63
|
+
end
|
64
|
+
else
|
65
|
+
info do
|
66
|
+
"Performed #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def enqueue_retry(event)
|
72
|
+
job = event.payload[:job]
|
73
|
+
ex = event.payload[:error]
|
74
|
+
wait = event.payload[:wait]
|
75
|
+
|
76
|
+
info do
|
77
|
+
if ex
|
78
|
+
"Retrying #{job.class} in #{wait.to_i} seconds, due to a #{ex.class}."
|
79
|
+
else
|
80
|
+
"Retrying #{job.class} in #{wait.to_i} seconds."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def retry_stopped(event)
|
86
|
+
job = event.payload[:job]
|
87
|
+
ex = event.payload[:error]
|
88
|
+
|
89
|
+
error do
|
90
|
+
"Stopped retrying #{job.class} due to a #{ex.class}, which reoccurred on #{job.executions} attempts."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def discard(event)
|
95
|
+
job = event.payload[:job]
|
96
|
+
ex = event.payload[:error]
|
97
|
+
|
98
|
+
error do
|
99
|
+
"Discarded #{job.class} due to a #{ex.class}."
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def queue_name(event)
|
105
|
+
event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
|
106
|
+
end
|
107
|
+
|
108
|
+
def args_info(job)
|
109
|
+
if job.class.log_arguments? && job.arguments.any?
|
110
|
+
" with arguments: " +
|
111
|
+
job.arguments.map { |arg| format(arg).inspect }.join(", ")
|
112
|
+
else
|
113
|
+
""
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def format(arg)
|
118
|
+
case arg
|
119
|
+
when Hash
|
120
|
+
arg.transform_values { |value| format(value) }
|
121
|
+
when Array
|
122
|
+
arg.map { |value| format(value) }
|
123
|
+
when GlobalID::Identification
|
124
|
+
arg.to_global_id rescue arg
|
125
|
+
else
|
126
|
+
arg
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def scheduled_at(event)
|
131
|
+
Time.at(event.payload[:job].scheduled_at).utc
|
132
|
+
end
|
133
|
+
|
134
|
+
def logger
|
135
|
+
ActiveJob::Base.logger
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
ActiveJob::LogSubscriber.attach_to :active_job
|
data/lib/active_job/logging.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/string/filters"
|
4
3
|
require "active_support/tagged_logging"
|
5
4
|
require "active_support/logger"
|
6
5
|
|
@@ -10,32 +9,10 @@ module ActiveJob
|
|
10
9
|
|
11
10
|
included do
|
12
11
|
cattr_accessor :logger, default: ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
|
12
|
+
class_attribute :log_arguments, instance_accessor: false, default: true
|
13
13
|
|
14
|
-
around_enqueue
|
15
|
-
|
16
|
-
block.call
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
around_perform do |job, block|
|
21
|
-
tag_logger(job.class.name, job.job_id) do
|
22
|
-
payload = { adapter: job.class.queue_adapter, job: job }
|
23
|
-
ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup)
|
24
|
-
ActiveSupport::Notifications.instrument("perform.active_job", payload) do
|
25
|
-
block.call
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
around_enqueue do |job, block|
|
31
|
-
if job.scheduled_at
|
32
|
-
ActiveSupport::Notifications.instrument("enqueue_at.active_job",
|
33
|
-
adapter: job.class.queue_adapter, job: job, &block)
|
34
|
-
else
|
35
|
-
ActiveSupport::Notifications.instrument("enqueue.active_job",
|
36
|
-
adapter: job.class.queue_adapter, job: job, &block)
|
37
|
-
end
|
38
|
-
end
|
14
|
+
around_enqueue { |_, block| tag_logger(&block) }
|
15
|
+
around_perform { |job, block| tag_logger(job.class.name, job.job_id, &block) }
|
39
16
|
end
|
40
17
|
|
41
18
|
private
|
@@ -51,111 +28,5 @@ module ActiveJob
|
|
51
28
|
def logger_tagged_by_active_job?
|
52
29
|
logger.formatter.current_tags.include?("ActiveJob")
|
53
30
|
end
|
54
|
-
|
55
|
-
class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc:
|
56
|
-
def enqueue(event)
|
57
|
-
info do
|
58
|
-
job = event.payload[:job]
|
59
|
-
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def enqueue_at(event)
|
64
|
-
info do
|
65
|
-
job = event.payload[:job]
|
66
|
-
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def perform_start(event)
|
71
|
-
info do
|
72
|
-
job = event.payload[:job]
|
73
|
-
"Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} enqueued at #{job.enqueued_at}" + args_info(job)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def perform(event)
|
78
|
-
job = event.payload[:job]
|
79
|
-
ex = event.payload[:exception_object]
|
80
|
-
if ex
|
81
|
-
error do
|
82
|
-
"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(ex.backtrace).join("\n")
|
83
|
-
end
|
84
|
-
else
|
85
|
-
info do
|
86
|
-
"Performed #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def enqueue_retry(event)
|
92
|
-
job = event.payload[:job]
|
93
|
-
ex = event.payload[:error]
|
94
|
-
wait = event.payload[:wait]
|
95
|
-
|
96
|
-
info do
|
97
|
-
if ex
|
98
|
-
"Retrying #{job.class} in #{wait.to_i} seconds, due to a #{ex.class}."
|
99
|
-
else
|
100
|
-
"Retrying #{job.class} in #{wait.to_i} seconds."
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def retry_stopped(event)
|
106
|
-
job = event.payload[:job]
|
107
|
-
ex = event.payload[:error]
|
108
|
-
|
109
|
-
error do
|
110
|
-
"Stopped retrying #{job.class} due to a #{ex.class}, which reoccurred on #{job.executions} attempts."
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def discard(event)
|
115
|
-
job = event.payload[:job]
|
116
|
-
ex = event.payload[:error]
|
117
|
-
|
118
|
-
error do
|
119
|
-
"Discarded #{job.class} due to a #{ex.class}."
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
def queue_name(event)
|
125
|
-
event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
|
126
|
-
end
|
127
|
-
|
128
|
-
def args_info(job)
|
129
|
-
if job.arguments.any?
|
130
|
-
" with arguments: " +
|
131
|
-
job.arguments.map { |arg| format(arg).inspect }.join(", ")
|
132
|
-
else
|
133
|
-
""
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def format(arg)
|
138
|
-
case arg
|
139
|
-
when Hash
|
140
|
-
arg.transform_values { |value| format(value) }
|
141
|
-
when Array
|
142
|
-
arg.map { |value| format(value) }
|
143
|
-
when GlobalID::Identification
|
144
|
-
arg.to_global_id rescue arg
|
145
|
-
else
|
146
|
-
arg
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def scheduled_at(event)
|
151
|
-
Time.at(event.payload[:job].scheduled_at).utc
|
152
|
-
end
|
153
|
-
|
154
|
-
def logger
|
155
|
-
ActiveJob::Base.logger
|
156
|
-
end
|
157
|
-
end
|
158
31
|
end
|
159
32
|
end
|
160
|
-
|
161
|
-
ActiveJob::Logging::LogSubscriber.attach_to :active_job
|