activejob 8.0.3 → 8.1.0.rc1
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 +75 -30
- data/README.md +7 -5
- data/lib/active_job/arguments.rb +47 -44
- data/lib/active_job/base.rb +3 -4
- data/lib/active_job/configured_job.rb +6 -1
- 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 +11 -1
- data/lib/active_job/enqueue_after_transaction_commit.rb +1 -26
- data/lib/active_job/enqueuing.rb +8 -4
- data/lib/active_job/exceptions.rb +17 -8
- 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 +61 -6
- data/lib/active_job/queue_adapters/abstract_adapter.rb +6 -0
- data/lib/active_job/queue_adapters/async_adapter.rb +5 -1
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +19 -0
- data/lib/active_job/queue_adapters/test_adapter.rb +5 -1
- data/lib/active_job/railtie.rb +9 -19
- 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 +54 -15
- data/lib/active_job/structured_event_subscriber.rb +216 -0
- data/lib/active_job.rb +3 -0
- metadata +14 -9
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +0 -56
- data/lib/active_job/timezones.rb +0 -13
- data/lib/active_job/translation.rb +0 -13
|
@@ -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,7 +12,7 @@ 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
18
|
# Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
|
|
@@ -35,6 +35,10 @@ module ActiveJob
|
|
|
35
35
|
perform_or_enqueue(perform_enqueued_at_jobs && !filtered?(job), job, job_data)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def stopping?
|
|
39
|
+
@stopping.is_a?(Proc) ? @stopping.call : @stopping
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
private
|
|
39
43
|
def job_to_hash(job, extras = {})
|
|
40
44
|
job.serialize.tap do |job_data|
|
data/lib/active_job/railtie.rb
CHANGED
|
@@ -19,7 +19,7 @@ module ActiveJob
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
initializer "active_job.custom_serializers" do |app|
|
|
22
|
-
|
|
22
|
+
ActiveSupport.on_load(:active_job) do
|
|
23
23
|
custom_serializers = app.config.active_job.custom_serializers
|
|
24
24
|
ActiveJob::Serializers.add_serializers custom_serializers
|
|
25
25
|
end
|
|
@@ -29,25 +29,14 @@ module ActiveJob
|
|
|
29
29
|
ActiveSupport.on_load(:active_job) do
|
|
30
30
|
ActiveSupport.on_load(:active_record) do
|
|
31
31
|
ActiveJob::Base.include EnqueueAfterTransactionCommit
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
but due the nature of this behavior, it is not recommended to be set globally.
|
|
38
|
-
MSG
|
|
39
|
-
|
|
40
|
-
value = case app.config.active_job.enqueue_after_transaction_commit
|
|
41
|
-
when :always
|
|
42
|
-
true
|
|
43
|
-
when :never
|
|
44
|
-
false
|
|
45
|
-
else
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
ActiveJob::Base.enqueue_after_transaction_commit = value
|
|
50
|
-
end
|
|
36
|
+
initializer "active_job.action_controller_parameters" do |app|
|
|
37
|
+
ActiveSupport.on_load(:active_job) do
|
|
38
|
+
ActiveSupport.on_load(:action_controller) do
|
|
39
|
+
ActiveJob::Serializers.add_serializers ActiveJob::Serializers::ActionControllerParametersSerializer
|
|
51
40
|
end
|
|
52
41
|
end
|
|
53
42
|
end
|
|
@@ -70,6 +59,7 @@ module ActiveJob
|
|
|
70
59
|
options = options.except(
|
|
71
60
|
:log_query_tags_around_perform,
|
|
72
61
|
:custom_serializers,
|
|
62
|
+
# This config can't be applied globally, so we need to remove otherwise it will be applied to `ActiveJob::Base`.
|
|
73
63
|
:enqueue_after_transaction_commit
|
|
74
64
|
)
|
|
75
65
|
|
|
@@ -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 = { Arguments::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
|
|
@@ -19,16 +19,17 @@ module ActiveJob
|
|
|
19
19
|
autoload :ModuleSerializer
|
|
20
20
|
autoload :RangeSerializer
|
|
21
21
|
autoload :BigDecimalSerializer
|
|
22
|
+
autoload :ActionControllerParametersSerializer
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
@serializers = Set.new
|
|
25
|
+
@serializers_index = {}
|
|
25
26
|
|
|
26
27
|
class << self
|
|
27
28
|
# Returns serialized representative of the passed object.
|
|
28
29
|
# Will look up through all known serializers.
|
|
29
30
|
# Raises ActiveJob::SerializationError if it can't find a proper serializer.
|
|
30
31
|
def serialize(argument)
|
|
31
|
-
serializer = serializers.
|
|
32
|
+
serializer = @serializers_index[argument.class] || serializers.find { |s| s.serialize?(argument) }
|
|
32
33
|
raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
|
|
33
34
|
serializer.serialize(argument)
|
|
34
35
|
end
|
|
@@ -47,24 +48,62 @@ module ActiveJob
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
# Returns list of known serializers.
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
attr_reader :serializers
|
|
52
|
+
|
|
53
|
+
def serializers=(serializers)
|
|
54
|
+
@serializers = serializers
|
|
55
|
+
index_serializers
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# Adds new serializers to a list of known serializers.
|
|
55
59
|
def add_serializers(*new_serializers)
|
|
56
|
-
|
|
60
|
+
new_serializers = new_serializers.flatten
|
|
61
|
+
new_serializers.map! do |s|
|
|
62
|
+
if s.is_a?(Class) && s < ObjectSerializer
|
|
63
|
+
s.instance
|
|
64
|
+
else
|
|
65
|
+
s
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@serializers += new_serializers
|
|
70
|
+
index_serializers
|
|
71
|
+
@serializers
|
|
57
72
|
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
def index_serializers
|
|
76
|
+
@serializers_index.clear
|
|
77
|
+
serializers.each do |s|
|
|
78
|
+
if s.respond_to?(:klass)
|
|
79
|
+
@serializers_index[s.klass] = s
|
|
80
|
+
elsif s.respond_to?(:klass, true)
|
|
81
|
+
klass = s.send(:klass)
|
|
82
|
+
ActiveJob.deprecator.warn(<<~MSG.squish)
|
|
83
|
+
#{s.class.name}#klass method should be public.
|
|
84
|
+
This will raise an error in Rails 8.2.
|
|
85
|
+
MSG
|
|
86
|
+
@serializers_index[klass] = s
|
|
87
|
+
else
|
|
88
|
+
ActiveJob.deprecator.warn(
|
|
89
|
+
<<~MSG.squish
|
|
90
|
+
#{s.class.name} should implement a public #klass method.
|
|
91
|
+
This will raise an error in Rails 8.2.
|
|
92
|
+
MSG
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
58
97
|
end
|
|
59
98
|
|
|
60
|
-
add_serializers SymbolSerializer,
|
|
61
|
-
DurationSerializer,
|
|
62
|
-
DateTimeSerializer,
|
|
63
|
-
DateSerializer,
|
|
64
|
-
TimeWithZoneSerializer,
|
|
65
|
-
TimeSerializer,
|
|
66
|
-
ModuleSerializer,
|
|
67
|
-
RangeSerializer,
|
|
68
|
-
BigDecimalSerializer
|
|
99
|
+
add_serializers SymbolSerializer.instance,
|
|
100
|
+
DurationSerializer.instance,
|
|
101
|
+
DateTimeSerializer.instance,
|
|
102
|
+
DateSerializer.instance,
|
|
103
|
+
TimeWithZoneSerializer.instance,
|
|
104
|
+
TimeSerializer.instance,
|
|
105
|
+
ModuleSerializer.instance,
|
|
106
|
+
RangeSerializer.instance,
|
|
107
|
+
BigDecimalSerializer.instance
|
|
69
108
|
end
|
|
70
109
|
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/structured_event_subscriber"
|
|
4
|
+
|
|
5
|
+
module ActiveJob
|
|
6
|
+
class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber # :nodoc:
|
|
7
|
+
def enqueue(event)
|
|
8
|
+
job = event.payload[:job]
|
|
9
|
+
adapter = event.payload[:adapter]
|
|
10
|
+
exception = event.payload[:exception_object] || job.enqueue_error
|
|
11
|
+
payload = {
|
|
12
|
+
job_class: job.class.name,
|
|
13
|
+
job_id: job.job_id,
|
|
14
|
+
queue: job.queue_name,
|
|
15
|
+
adapter: ActiveJob.adapter_name(adapter),
|
|
16
|
+
aborted: event.payload[:aborted],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if exception
|
|
20
|
+
payload[:exception_class] = exception.class.name
|
|
21
|
+
payload[:exception_message] = exception.message
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if job.class.log_arguments?
|
|
25
|
+
payload[:arguments] = job.arguments
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
emit_event("active_job.enqueued", payload)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def enqueue_at(event)
|
|
32
|
+
job = event.payload[:job]
|
|
33
|
+
adapter = event.payload[:adapter]
|
|
34
|
+
exception = event.payload[:exception_object] || job.enqueue_error
|
|
35
|
+
payload = {
|
|
36
|
+
job_class: job.class.name,
|
|
37
|
+
job_id: job.job_id,
|
|
38
|
+
queue: job.queue_name,
|
|
39
|
+
scheduled_at: job.scheduled_at,
|
|
40
|
+
adapter: ActiveJob.adapter_name(adapter),
|
|
41
|
+
aborted: event.payload[:aborted],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if exception
|
|
45
|
+
payload[:exception_class] = exception.class.name
|
|
46
|
+
payload[:exception_message] = exception.message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if job.class.log_arguments?
|
|
50
|
+
payload[:arguments] = job.arguments
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
emit_event("active_job.enqueued_at", payload)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def enqueue_all(event)
|
|
57
|
+
jobs = event.payload[:jobs]
|
|
58
|
+
adapter = event.payload[:adapter]
|
|
59
|
+
enqueued_count = event.payload[:enqueued_count].to_i
|
|
60
|
+
failed_count = jobs.size - enqueued_count
|
|
61
|
+
|
|
62
|
+
emit_event("active_job.bulk_enqueued",
|
|
63
|
+
adapter: ActiveJob.adapter_name(adapter),
|
|
64
|
+
job_count: jobs.size,
|
|
65
|
+
enqueued_count: enqueued_count,
|
|
66
|
+
failed_enqueue_count: failed_count,
|
|
67
|
+
enqueued_classes: jobs.filter_map { |job| job.class.name }.tally
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def perform_start(event)
|
|
72
|
+
job = event.payload[:job]
|
|
73
|
+
payload = {
|
|
74
|
+
job_class: job.class.name,
|
|
75
|
+
job_id: job.job_id,
|
|
76
|
+
queue: job.queue_name,
|
|
77
|
+
enqueued_at: job.enqueued_at&.utc&.iso8601(9),
|
|
78
|
+
}
|
|
79
|
+
if job.class.log_arguments?
|
|
80
|
+
payload[:arguments] = job.arguments
|
|
81
|
+
end
|
|
82
|
+
emit_event("active_job.started", payload)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def perform(event)
|
|
86
|
+
job = event.payload[:job]
|
|
87
|
+
exception = event.payload[:exception_object]
|
|
88
|
+
payload = {
|
|
89
|
+
job_class: job.class.name,
|
|
90
|
+
job_id: job.job_id,
|
|
91
|
+
queue: job.queue_name,
|
|
92
|
+
aborted: event.payload[:aborted],
|
|
93
|
+
duration: event.duration.round(2),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if exception
|
|
97
|
+
payload[:exception_class] = exception.class.name
|
|
98
|
+
payload[:exception_message] = exception.message
|
|
99
|
+
payload[:exception_backtrace] = exception.backtrace
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
emit_event("active_job.completed", payload)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def enqueue_retry(event)
|
|
106
|
+
job = event.payload[:job]
|
|
107
|
+
exception = event.payload[:error]
|
|
108
|
+
wait = event.payload[:wait]
|
|
109
|
+
|
|
110
|
+
emit_event("active_job.retry_scheduled",
|
|
111
|
+
job_class: job.class.name,
|
|
112
|
+
job_id: job.job_id,
|
|
113
|
+
executions: job.executions,
|
|
114
|
+
wait_seconds: wait.to_i,
|
|
115
|
+
exception_class: exception&.class&.name,
|
|
116
|
+
exception_message: exception&.message
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def retry_stopped(event)
|
|
121
|
+
job = event.payload[:job]
|
|
122
|
+
exception = event.payload[:error]
|
|
123
|
+
|
|
124
|
+
emit_event("active_job.retry_stopped",
|
|
125
|
+
job_class: job.class.name,
|
|
126
|
+
job_id: job.job_id,
|
|
127
|
+
executions: job.executions,
|
|
128
|
+
exception_class: exception.class.name,
|
|
129
|
+
exception_message: exception.message
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def discard(event)
|
|
134
|
+
job = event.payload[:job]
|
|
135
|
+
exception = event.payload[:error]
|
|
136
|
+
|
|
137
|
+
emit_event("active_job.discarded",
|
|
138
|
+
job_class: job.class.name,
|
|
139
|
+
job_id: job.job_id,
|
|
140
|
+
exception_class: exception.class.name,
|
|
141
|
+
exception_message: exception.message
|
|
142
|
+
)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def interrupt(event)
|
|
146
|
+
job = event.payload[:job]
|
|
147
|
+
description = event.payload[:description]
|
|
148
|
+
reason = event.payload[:reason]
|
|
149
|
+
|
|
150
|
+
emit_event("active_job.interrupt",
|
|
151
|
+
job_class: job.class.name,
|
|
152
|
+
job_id: job.job_id,
|
|
153
|
+
description: description,
|
|
154
|
+
reason: reason,
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def resume(event)
|
|
159
|
+
job = event.payload[:job]
|
|
160
|
+
description = event.payload[:description]
|
|
161
|
+
|
|
162
|
+
emit_event("active_job.resume",
|
|
163
|
+
job_class: job.class.name,
|
|
164
|
+
job_id: job.job_id,
|
|
165
|
+
description: description,
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def step_skipped(event)
|
|
170
|
+
job = event.payload[:job]
|
|
171
|
+
step = event.payload[:step]
|
|
172
|
+
|
|
173
|
+
emit_event("active_job.step_skipped",
|
|
174
|
+
job_class: job.class.name,
|
|
175
|
+
job_id: job.job_id,
|
|
176
|
+
step: step.name,
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def step_started(event)
|
|
181
|
+
job = event.payload[:job]
|
|
182
|
+
step = event.payload[:step]
|
|
183
|
+
|
|
184
|
+
emit_event("active_job.step_started",
|
|
185
|
+
job_class: job.class.name,
|
|
186
|
+
job_id: job.job_id,
|
|
187
|
+
step: step.name,
|
|
188
|
+
cursor: step.cursor,
|
|
189
|
+
resumed: step.resumed?,
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def step(event)
|
|
194
|
+
job = event.payload[:job]
|
|
195
|
+
step = event.payload[:step]
|
|
196
|
+
exception = event.payload[:exception_object]
|
|
197
|
+
payload = {
|
|
198
|
+
job_class: job.class.name,
|
|
199
|
+
job_id: job.job_id,
|
|
200
|
+
step: step.name,
|
|
201
|
+
cursor: step.cursor,
|
|
202
|
+
interrupted: event.payload[:interrupted],
|
|
203
|
+
duration: event.duration.round(2),
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if exception
|
|
207
|
+
payload[:exception_class] = exception.class.name
|
|
208
|
+
payload[:exception_message] = exception.message
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
emit_event("active_job.step", payload)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
ActiveJob::StructuredEventSubscriber.attach_to :active_job
|
data/lib/active_job.rb
CHANGED
|
@@ -39,9 +39,12 @@ module ActiveJob
|
|
|
39
39
|
autoload :Arguments
|
|
40
40
|
autoload :DeserializationError, "active_job/arguments"
|
|
41
41
|
autoload :SerializationError, "active_job/arguments"
|
|
42
|
+
autoload :UnknownJobClassError, "active_job/core"
|
|
42
43
|
autoload :EnqueueAfterTransactionCommit
|
|
43
44
|
|
|
44
45
|
eager_autoload do
|
|
46
|
+
autoload :Continuable
|
|
47
|
+
autoload :Continuation
|
|
45
48
|
autoload :Serializers
|
|
46
49
|
autoload :ConfiguredJob
|
|
47
50
|
end
|