Skip to content

Commit 243c2a0

Browse files
committed
fix(jobs): preserve serialized context precedence
1 parent eb85c08 commit 243c2a0

2 files changed

Lines changed: 33 additions & 5 deletions

File tree

‎sentry-rails/lib/sentry/rails/active_job.rb‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ def capture_exception(job, e, extension = Sentry.job_extensions.for(job))
310310
}
311311

312312
contexts = error_data[:contexts]
313-
contexts = contexts.merge(execution_context) if Sentry.configuration.data_collection.queues
313+
contexts = contexts.merge(matching_keys(execution_context, contexts)) if Sentry.configuration.data_collection.queues
314314
options[:contexts] = contexts if Sentry.configuration.data_collection.queues || !contexts.empty?
315315

316316
integration = Sentry.job_extensions.call(extension, :integration, job) || Sentry::Rails
@@ -319,17 +319,25 @@ def capture_exception(job, e, extension = Sentry.job_extensions.for(job))
319319

320320
def additive_error_data(data, extension_scope_contexts)
321321
scope = Sentry.get_current_scope
322+
extension_scope_contexts = matching_keys(extension_scope_contexts, scope.contexts)
322323

323324
{
324-
contexts: data.fetch(:contexts, {}).to_h do |name, context|
325+
contexts: matching_keys(data.fetch(:contexts, {}), scope.contexts).to_h do |name, context|
325326
scope_context = scope.contexts.fetch(name, {})
326-
[name, scope_context.merge(context).merge(values_not_supplied_by(scope_context, extension_scope_contexts.fetch(name, {})))]
327+
context = matching_keys(context, scope_context)
328+
extension_context = matching_keys(extension_scope_contexts.fetch(name, {}), scope_context)
329+
[name, scope_context.merge(context).merge(values_not_supplied_by(scope_context, extension_context))]
327330
end,
328-
tags: data.fetch(:tags, {}).reject { |key, _value| scope.tags.key?(key) },
329-
extra: data.fetch(:extra, {}).reject { |key, _value| scope.extra.key?(key) }
331+
tags: matching_keys(data.fetch(:tags, {}), scope.tags).reject { |key, _value| scope.tags.key?(key) },
332+
extra: matching_keys(data.fetch(:extra, {}), scope.extra).reject { |key, _value| scope.extra.key?(key) }
330333
}
331334
end
332335

336+
def matching_keys(data, reference)
337+
keys = reference.keys.to_h { |key| [key.to_s, key] }
338+
data.transform_keys { |key| keys.fetch(key.to_s, key) }
339+
end
340+
333341
def values_not_supplied_by(scope_context, extension_context)
334342
scope_context.reject { |key, value| extension_context.key?(key) && extension_context[key] == value }
335343
end

‎sentry-rails/spec/sentry/rails/active_job_job_extensions_spec.rb‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,26 @@ def error_data(job, _exception)
119119
end
120120
end
121121

122+
describe "string-keyed error context" do
123+
it "preserves serialized ActiveJob metadata while adding backend fields" do
124+
register_extension do
125+
def error_data(_job, _exception)
126+
{ contexts: { "active_job" => { "job_id" => "backend-id", "attempt" => 3 } } }
127+
end
128+
end
129+
130+
event = JSON.parse(JSON.generate(perform_failing_job.to_h))
131+
132+
expect(event.dig("contexts", "active_job")).to include(
133+
"job_id" => event.dig("extra", "job_id"),
134+
"job_class" => failing_job.name,
135+
"queue" => "default",
136+
"provider_job_id" => event.dig("extra", "provider_job_id"),
137+
"attempt" => 3
138+
)
139+
end
140+
end
141+
122142
describe "error data overlapping the job's scope" do
123143
it "does not let the extension's error data replace tags and extra already on the job's scope" do
124144
register_extension do

0 commit comments

Comments
 (0)