|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +# Copyright The OpenTelemetry Authors |
| 4 | +# |
| 5 | +# SPDX-License-Identifier: Apache-2.0 |
| 6 | + |
| 7 | +require 'test_helper' |
| 8 | + |
| 9 | +require_relative '../../../../../lib/opentelemetry/instrumentation/active_job' |
| 10 | + |
| 11 | +require 'active_job/continuation/test_helper' if defined?(ActiveJob::Continuable) |
| 12 | + |
| 13 | +describe OpenTelemetry::Instrumentation::ActiveJob::Handlers::Interrupt do |
| 14 | + let(:instrumentation) { OpenTelemetry::Instrumentation::ActiveJob::Instrumentation.instance } |
| 15 | + let(:config) { { propagation_style: :link, span_naming: :queue } } |
| 16 | + let(:exporter) { EXPORTER } |
| 17 | + let(:spans) { exporter.finished_spans } |
| 18 | + let(:process_span) { spans.find { |s| s.name == 'default process' } } |
| 19 | + |
| 20 | + before do |
| 21 | + skip 'Requires ActiveJob::Continuable (Rails 8.1+)' unless defined?(ActiveJob::Continuable) |
| 22 | + |
| 23 | + singleton_class.include ActiveJob::Continuation::TestHelper |
| 24 | + |
| 25 | + OpenTelemetry::Instrumentation::ActiveJob::Handlers.unsubscribe |
| 26 | + instrumentation.instance_variable_set(:@config, config) |
| 27 | + instrumentation.instance_variable_set(:@installed, false) |
| 28 | + |
| 29 | + instrumentation.install(config) |
| 30 | + ActiveJob::Base.queue_adapter = :test |
| 31 | + |
| 32 | + exporter.reset |
| 33 | + end |
| 34 | + |
| 35 | + after do |
| 36 | + ActiveJob::Base.queue_adapter = :inline |
| 37 | + end |
| 38 | + |
| 39 | + describe 'when a job is interrupted between steps' do |
| 40 | + it 'adds an interrupt event to the process span' do |
| 41 | + ContinuableJob.perform_later |
| 42 | + interrupt_job_after_step(ContinuableJob, :first_step) { perform_enqueued_jobs } |
| 43 | + |
| 44 | + interrupt_events = process_span.events&.select { |e| e.name == 'interrupt' } || [] |
| 45 | + |
| 46 | + _(interrupt_events.length).must_equal 1 |
| 47 | + end |
| 48 | + |
| 49 | + it 'includes the interrupt reason' do |
| 50 | + ContinuableJob.perform_later |
| 51 | + interrupt_job_after_step(ContinuableJob, :first_step) { perform_enqueued_jobs } |
| 52 | + |
| 53 | + interrupt_event = process_span.events.find { |e| e.name == 'interrupt' } |
| 54 | + |
| 55 | + _(interrupt_event.attributes['messaging.active_job.continuation.reason']).must_equal 'stopping' |
| 56 | + end |
| 57 | + |
| 58 | + it 'includes the description' do |
| 59 | + ContinuableJob.perform_later |
| 60 | + interrupt_job_after_step(ContinuableJob, :first_step) { perform_enqueued_jobs } |
| 61 | + |
| 62 | + interrupt_event = process_span.events.find { |e| e.name == 'interrupt' } |
| 63 | + |
| 64 | + _(interrupt_event.attributes['messaging.active_job.continuation.description']).wont_be_nil |
| 65 | + end |
| 66 | + end |
| 67 | + |
| 68 | + describe 'when a job is interrupted during a step' do |
| 69 | + it 'adds an interrupt event to the process span, not the step span' do |
| 70 | + ContinuableWithCursorJob.perform_later |
| 71 | + interrupt_job_during_step(ContinuableWithCursorJob, :process_items, cursor: 2) { perform_enqueued_jobs } |
| 72 | + |
| 73 | + step_span = spans.find { |s| s.name == 'default process_items' } |
| 74 | + step_interrupt_events = step_span&.events&.select { |e| e.name == 'interrupt' } || [] |
| 75 | + process_interrupt_events = process_span.events&.select { |e| e.name == 'interrupt' } || [] |
| 76 | + |
| 77 | + _(step_interrupt_events).must_be(:empty?) |
| 78 | + _(process_interrupt_events.length).must_equal 1 |
| 79 | + end |
| 80 | + end |
| 81 | + |
| 82 | + describe 'when a job completes without interruption' do |
| 83 | + it 'does not add an interrupt event' do |
| 84 | + ContinuableJob.perform_later |
| 85 | + perform_enqueued_jobs |
| 86 | + |
| 87 | + interrupt_events = process_span.events&.select { |e| e.name == 'interrupt' } || [] |
| 88 | + _(interrupt_events).must_be(:empty?) |
| 89 | + end |
| 90 | + end |
| 91 | +end |
0 commit comments