julewire-active_job 1.0.1 → 1.1.0
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 +6 -0
- data/docs/propagation.md +4 -0
- data/julewire-active_job.gemspec +2 -2
- data/lib/julewire/active_job/installer.rb +7 -20
- data/lib/julewire/active_job/job_execution.rb +11 -13
- data/lib/julewire/active_job/job_serialization.rb +7 -22
- data/lib/julewire/active_job/log_subscriber_silencer.rb +2 -11
- data/lib/julewire/active_job/railtie.rb +1 -1
- data/lib/julewire/active_job/subscribers/event.rb +7 -14
- data/lib/julewire/active_job/version.rb +1 -1
- data/lib/julewire/active_job.rb +1 -5
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 994a99590e4edc3673032beb690309bf1dd80b9008bd3ada44c7ee75468ad799
|
|
4
|
+
data.tar.gz: 96330738837417e0a150b60b9212ccfd1055264b45f7e5e6d3e51e7b379194be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ba90a55b73280d51badf2b3ac32a27277cc6175537215cd050324785046eee0bf0a983b0d5c4e05a40cbbe6b2aa86754d213de639caa3b0913fdef07029050fd
|
|
7
|
+
data.tar.gz: 2b8ccba07a60b83bb30d5615fb653a672c72ce36e663ac1bb4dd79bf8a5c68f1b83784ce388d740fac1d7d9e8fcd9b7159fc303f580cb31f33c0297fad218d79
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 1.1.0 - 2026-07-20
|
|
4
|
+
|
|
5
|
+
- Restore propagated context through owned carrier envelopes and keep job
|
|
6
|
+
status summaries on Active Job's normal `StandardError` path.
|
|
7
|
+
- Require Julewire 1.1.0 internal gems.
|
|
8
|
+
|
|
3
9
|
## 1.0.1 - 2026-06-25
|
|
4
10
|
|
|
5
11
|
- Default propagation carrier byte limits to 64 KiB and record health when
|
data/docs/propagation.md
CHANGED
|
@@ -15,3 +15,7 @@ Generic job metadata such as class, id, queue, priority, execution count,
|
|
|
15
15
|
timestamps, and status is emitted in the record's `neutral` section as `job.*`
|
|
16
16
|
formatter-coordination fields. Full Active Job metadata, including framework-
|
|
17
17
|
specific status and exception fields, is emitted under `attributes.active_job`.
|
|
18
|
+
|
|
19
|
+
Status classification follows Active Job's normal `StandardError` path. Fatal
|
|
20
|
+
Ruby exceptions such as `SystemExit` or `NoMemoryError` are not converted into
|
|
21
|
+
job status metadata; they keep Ruby's process-level semantics.
|
data/julewire-active_job.gemspec
CHANGED
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.require_paths = ["lib"]
|
|
36
36
|
|
|
37
37
|
spec.add_dependency "activejob", ">= 8.1"
|
|
38
|
-
spec.add_dependency "julewire-core", ">= 1.0
|
|
39
|
-
spec.add_dependency "julewire-rails_support", ">= 1.0
|
|
38
|
+
spec.add_dependency "julewire-core", ">= 1.1.0"
|
|
39
|
+
spec.add_dependency "julewire-rails_support", ">= 1.1.0"
|
|
40
40
|
spec.add_dependency "zeitwerk", ">= 2.8.1"
|
|
41
41
|
end
|
|
@@ -9,17 +9,13 @@ module Julewire
|
|
|
9
9
|
def install!(base: nil, event_reporter: nil, configuration: Configuration.new)
|
|
10
10
|
return unless configuration.enabled?
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
ActiveJob.config = configuration
|
|
13
13
|
base ||= active_job_base
|
|
14
14
|
raise Error, "ActiveJob::Base is not available" unless base
|
|
15
15
|
|
|
16
16
|
install_serialization(base, configuration)
|
|
17
17
|
install_execution_callback(base, configuration)
|
|
18
|
-
|
|
19
|
-
Subscribers::Event.install!(configuration, event_reporter: event_reporter)
|
|
20
|
-
else
|
|
21
|
-
Subscribers::Event.reset!
|
|
22
|
-
end
|
|
18
|
+
Subscribers::Event.install!(configuration, event_reporter: event_reporter)
|
|
23
19
|
LogSubscriberSilencer.silence! if configuration.silence_log_subscriber?
|
|
24
20
|
base
|
|
25
21
|
end
|
|
@@ -33,24 +29,15 @@ module Julewire
|
|
|
33
29
|
|
|
34
30
|
def install_serialization(base, configuration)
|
|
35
31
|
install_serialization_configuration(base, configuration)
|
|
36
|
-
return if base < JobSerialization
|
|
37
32
|
|
|
38
33
|
base.prepend(JobSerialization)
|
|
39
34
|
end
|
|
40
35
|
|
|
41
36
|
def install_serialization_configuration(base, configuration)
|
|
42
|
-
if base.
|
|
43
|
-
|
|
44
|
-
base.class_attribute(
|
|
45
|
-
JobSerialization::CONFIGURATION_METHOD,
|
|
46
|
-
instance_accessor: false,
|
|
47
|
-
instance_predicate: false
|
|
48
|
-
)
|
|
49
|
-
end
|
|
50
|
-
base.public_send("#{JobSerialization::CONFIGURATION_METHOD}=", configuration)
|
|
51
|
-
else
|
|
52
|
-
base.instance_variable_set(JobSerialization::CONFIGURATION_IVAR, configuration)
|
|
37
|
+
if base.singleton_methods(false).include?(JobSerialization::CONFIGURATION_METHOD)
|
|
38
|
+
base.singleton_class.remove_method(JobSerialization::CONFIGURATION_METHOD)
|
|
53
39
|
end
|
|
40
|
+
base.define_singleton_method(JobSerialization::CONFIGURATION_METHOD) { configuration }
|
|
54
41
|
end
|
|
55
42
|
|
|
56
43
|
def install_execution_callback(base, configuration)
|
|
@@ -59,7 +46,7 @@ module Julewire
|
|
|
59
46
|
installed = EXECUTION_INSTALL.fetch(base)
|
|
60
47
|
if installed
|
|
61
48
|
installed.configuration = configuration
|
|
62
|
-
return
|
|
49
|
+
return
|
|
63
50
|
end
|
|
64
51
|
|
|
65
52
|
callback = ExecutionCallback.new(configuration)
|
|
@@ -79,7 +66,7 @@ module Julewire
|
|
|
79
66
|
attr_writer :configuration
|
|
80
67
|
|
|
81
68
|
def call(job, &)
|
|
82
|
-
|
|
69
|
+
JobExecution.call(job, configuration: @configuration, &)
|
|
83
70
|
end
|
|
84
71
|
end
|
|
85
72
|
private_constant :ExecutionCallback
|
|
@@ -6,18 +6,18 @@ module Julewire
|
|
|
6
6
|
module ActiveJob
|
|
7
7
|
module JobExecution
|
|
8
8
|
class << self
|
|
9
|
-
def call(job, configuration
|
|
9
|
+
def call(job, configuration:, &)
|
|
10
10
|
carrier = carrier_for(job)
|
|
11
11
|
return perform_job(job, configuration, &) unless configuration.propagation?
|
|
12
12
|
|
|
13
|
-
result =
|
|
13
|
+
result = Core::Propagation::Carrier.extract_result(
|
|
14
14
|
carrier,
|
|
15
15
|
key: configuration.carrier_key,
|
|
16
16
|
max_bytes: configuration.carrier_max_bytes
|
|
17
17
|
)
|
|
18
18
|
record_carrier_restore_failure(result)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Core::Propagation.restore(result.envelope, owned: true) do
|
|
21
21
|
perform_job(job, configuration, &)
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -38,32 +38,30 @@ module Julewire
|
|
|
38
38
|
|
|
39
39
|
def perform_job(job, configuration, &)
|
|
40
40
|
fields = job_fields(job)
|
|
41
|
-
Core::Integration::Facade.with_execution(**execution_options(
|
|
41
|
+
Core::Integration::Facade.with_execution(**execution_options(configuration, fields)) do
|
|
42
42
|
install_context(fields)
|
|
43
43
|
perform_with_summary(&)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def carrier_for(job)
|
|
48
|
-
job.instance_variable_get(CARRIER_IVAR)
|
|
48
|
+
job.instance_variable_get(CARRIER_IVAR)
|
|
49
49
|
rescue StandardError
|
|
50
|
-
|
|
50
|
+
nil
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def execution_options(
|
|
54
|
-
|
|
53
|
+
def execution_options(configuration, fields)
|
|
54
|
+
{
|
|
55
55
|
type: :job,
|
|
56
|
-
fields: { job_class: fields
|
|
56
|
+
fields: { job_class: fields.fetch(:job_class) },
|
|
57
57
|
attributes: attributes_for(fields),
|
|
58
58
|
neutral: neutral_for(fields),
|
|
59
59
|
inherit_attributes: false,
|
|
60
60
|
summary_event: configuration.summary_event,
|
|
61
61
|
summary_severity: configuration.summary_severity,
|
|
62
|
-
summary_source: configuration.source
|
|
62
|
+
summary_source: configuration.source,
|
|
63
|
+
id: fields[:job_id]
|
|
63
64
|
}
|
|
64
|
-
job_id = fields[:job_id]
|
|
65
|
-
options[:id] = job_id if job_id
|
|
66
|
-
options
|
|
67
65
|
end
|
|
68
66
|
|
|
69
67
|
def install_context(fields)
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
module Julewire
|
|
4
4
|
module ActiveJob
|
|
5
5
|
module JobSerialization
|
|
6
|
-
CONFIGURATION_IVAR = :@julewire_active_job_configuration
|
|
7
6
|
CONFIGURATION_METHOD = :julewire_active_job_configuration
|
|
8
7
|
|
|
9
8
|
def serialize
|
|
@@ -23,16 +22,12 @@ module Julewire
|
|
|
23
22
|
configuration = julewire_active_job_configuration
|
|
24
23
|
return unless configuration.propagation?
|
|
25
24
|
|
|
26
|
-
carrier =
|
|
27
|
-
|
|
28
|
-
key: configuration.carrier_key,
|
|
29
|
-
max_bytes: configuration.carrier_max_bytes
|
|
30
|
-
)
|
|
25
|
+
carrier = Core::Propagation::Carrier.inject(key: configuration.carrier_key,
|
|
26
|
+
max_bytes: configuration.carrier_max_bytes)
|
|
31
27
|
return unless carrier
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
IntegrationHealth.record_success(action: :carrier_inject, component: :job_serialization)
|
|
29
|
+
job_data[configuration.serialized_carrier_key] = carrier.fetch(configuration.carrier_key.to_s)
|
|
30
|
+
IntegrationHealth.record_success
|
|
36
31
|
rescue StandardError => e
|
|
37
32
|
IntegrationHealth.record_failure(e, action: :carrier_inject, component: :job_serialization)
|
|
38
33
|
end
|
|
@@ -46,26 +41,16 @@ module Julewire
|
|
|
46
41
|
|
|
47
42
|
value = job_data[configuration.serialized_carrier_key]
|
|
48
43
|
instance_variable_set(CARRIER_IVAR, value ? { configuration.carrier_key => value } : {})
|
|
49
|
-
IntegrationHealth.record_success
|
|
44
|
+
IntegrationHealth.record_success
|
|
50
45
|
rescue StandardError => e
|
|
51
46
|
IntegrationHealth.record_failure(e, action: :carrier_extract, component: :job_serialization)
|
|
52
47
|
instance_variable_set(CARRIER_IVAR, {})
|
|
53
48
|
end
|
|
54
49
|
|
|
55
50
|
def julewire_active_job_configuration
|
|
56
|
-
|
|
57
|
-
configuration = self.class.public_send(CONFIGURATION_METHOD)
|
|
58
|
-
return configuration if configuration
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
self.class.ancestors.each do |ancestor|
|
|
62
|
-
next unless ancestor.instance_variable_defined?(CONFIGURATION_IVAR)
|
|
63
|
-
|
|
64
|
-
return ancestor.instance_variable_get(CONFIGURATION_IVAR)
|
|
65
|
-
end
|
|
66
|
-
Julewire::ActiveJob.config
|
|
51
|
+
self.class.public_send(CONFIGURATION_METHOD)
|
|
67
52
|
rescue StandardError
|
|
68
|
-
|
|
53
|
+
ActiveJob.config
|
|
69
54
|
end
|
|
70
55
|
end
|
|
71
56
|
end
|
|
@@ -6,17 +6,8 @@ module Julewire
|
|
|
6
6
|
class << self
|
|
7
7
|
def silence!
|
|
8
8
|
Core::Integration::Lifecycle.require_optional("active_job/log_subscriber")
|
|
9
|
-
subscriber_class =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
subscriber_class.detach_from(:active_job) if subscriber_class.respond_to?(:detach_from)
|
|
13
|
-
Julewire::RailsSupport::EventReporter.unsubscribe_log_subscriber(subscriber_class)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def active_job_log_subscriber
|
|
19
|
-
::ActiveJob::LogSubscriber if defined?(::ActiveJob::LogSubscriber)
|
|
9
|
+
subscriber_class = ::ActiveJob::LogSubscriber if defined?(::ActiveJob::LogSubscriber)
|
|
10
|
+
Julewire::RailsSupport::LogSubscribers.detach(subscriber_class, :active_job)
|
|
20
11
|
end
|
|
21
12
|
end
|
|
22
13
|
end
|
|
@@ -21,11 +21,11 @@ module Julewire
|
|
|
21
21
|
return reset! unless configuration.structured_events?
|
|
22
22
|
|
|
23
23
|
Core::Integration::Lifecycle.require_optional(STRUCTURED_EVENT_FILE)
|
|
24
|
-
reporter = event_reporter ||
|
|
25
|
-
return unless
|
|
24
|
+
reporter = event_reporter || RailsSupport::EventReporter.default
|
|
25
|
+
return unless RailsSupport::EventReporter.subscribable?(reporter)
|
|
26
26
|
|
|
27
27
|
install_subscriber(configuration, enabled: true) do |subscriber|
|
|
28
|
-
|
|
28
|
+
RailsSupport::EventReporter.subscribe(reporter, subscriber) { subscriber.accept?(it) }
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -45,7 +45,7 @@ module Julewire
|
|
|
45
45
|
def emit_event(event)
|
|
46
46
|
name = event[:name].to_s
|
|
47
47
|
record = record_for(event, name)
|
|
48
|
-
enrich_continuation_summary(name, record.
|
|
48
|
+
enrich_continuation_summary(name, record.fetch(:attributes).fetch(:active_job))
|
|
49
49
|
Core::Integration::Facade.emit(record)
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -60,13 +60,13 @@ module Julewire
|
|
|
60
60
|
def base_record(event, name, payload)
|
|
61
61
|
values = Core::Integration::Values::Shape
|
|
62
62
|
record = {
|
|
63
|
-
severity: severity_for(name, payload),
|
|
64
63
|
event: name,
|
|
65
64
|
logger: "ActiveJob.event",
|
|
66
65
|
context: values.hash_or_empty(event[:context]),
|
|
67
66
|
attributes: attributes_for(event, payload),
|
|
68
67
|
neutral: neutral_for(event, payload)
|
|
69
68
|
}
|
|
69
|
+
values.append_field(record, :severity, severity_for(name, payload))
|
|
70
70
|
values.append_field(record, :timestamp, values.timestamp(event[:timestamp]))
|
|
71
71
|
values.append_field(record, :source, @configuration.source)
|
|
72
72
|
record
|
|
@@ -81,22 +81,17 @@ module Julewire
|
|
|
81
81
|
|
|
82
82
|
def neutral_for(event, payload)
|
|
83
83
|
values = Core::Integration::Values::Shape
|
|
84
|
-
Core::Fields::FieldSet.merge
|
|
84
|
+
Core::Fields::FieldSet.merge(
|
|
85
85
|
JobAttributes.call(payload),
|
|
86
86
|
values.source_location_attributes(event[:source_location])
|
|
87
87
|
)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def severity_for(name, payload)
|
|
91
|
-
|
|
92
|
-
return :error if exception_payload?(payload)
|
|
93
|
-
|
|
94
|
-
:info
|
|
91
|
+
:error if ERROR_EVENTS.include?(name) || exception_payload?(payload)
|
|
95
92
|
end
|
|
96
93
|
|
|
97
94
|
def exception_payload?(payload)
|
|
98
|
-
return false unless payload.is_a?(Hash)
|
|
99
|
-
|
|
100
95
|
payload.key?(:exception_class) ||
|
|
101
96
|
payload.key?(:exception_message) ||
|
|
102
97
|
payload.key?(:exception_backtrace)
|
|
@@ -111,8 +106,6 @@ module Julewire
|
|
|
111
106
|
end
|
|
112
107
|
|
|
113
108
|
def enrich_continuation_summary(name, payload)
|
|
114
|
-
return unless Core::Integration::Facade.summary_active?
|
|
115
|
-
|
|
116
109
|
case name
|
|
117
110
|
when "active_job.step_started"
|
|
118
111
|
increment_summary(:continuation_steps_started)
|
data/lib/julewire/active_job.rb
CHANGED
|
@@ -23,10 +23,6 @@ module Julewire
|
|
|
23
23
|
def perform(job, &)
|
|
24
24
|
JobExecution.call(job, configuration: config, &)
|
|
25
25
|
end
|
|
26
|
-
|
|
27
|
-
def load_railtie_if_rails!
|
|
28
|
-
Railtie if defined?(::Rails::Railtie)
|
|
29
|
-
end
|
|
30
26
|
end
|
|
31
27
|
end
|
|
32
28
|
|
|
@@ -34,5 +30,5 @@ module Julewire
|
|
|
34
30
|
# Rails-only autoload, skipped when non-Rails processes eager load the gem.
|
|
35
31
|
loader.do_not_eager_load("#{__dir__}/active_job/railtie.rb")
|
|
36
32
|
loader.setup
|
|
37
|
-
Julewire::ActiveJob
|
|
33
|
+
Julewire::ActiveJob::Railtie if defined?(::Rails::Railtie)
|
|
38
34
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: julewire-active_job
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Grebennik
|
|
@@ -29,28 +29,28 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 1.0
|
|
32
|
+
version: 1.1.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 1.0
|
|
39
|
+
version: 1.1.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: julewire-rails_support
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: 1.0
|
|
46
|
+
version: 1.1.0
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: 1.0
|
|
53
|
+
version: 1.1.0
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: zeitwerk
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -116,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
117
|
version: '0'
|
|
118
118
|
requirements: []
|
|
119
|
-
rubygems_version: 4.0.
|
|
119
|
+
rubygems_version: 4.0.16
|
|
120
120
|
specification_version: 4
|
|
121
121
|
summary: Active Job integration for Julewire structured logging.
|
|
122
122
|
test_files: []
|