# frozen_string_literal: true # Copyright The OpenTelemetry Authors # # SPDX-License-Identifier: Apache-2.0 require_relative 'mappers/attribute' require_relative 'handlers/default' require_relative 'handlers/enqueue' require_relative 'handlers/perform' module OpenTelemetry module Instrumentation module ActiveJob # Module that contains custom event handlers, which are used to generate spans per event module Handlers module_function # Subscribes Event Handlers to relevant ActiveJob notifications # # The following events are recorded as spans: # - enqueue # - enqueue_at # - enqueue_retry # - perform # - retry_stopped # - discard # # Ingress and Egress spans (perform, enqueue, enqueue_at) use Messaging semantic conventions for naming the span, # while internal spans keep their ActiveSupport event name. # # @note this method is not thread safe and should not be used in a multi-threaded context # @note Why no perform_start? # This event causes much heartache as it is the first in a series of events that is triggered. # It should not be the ingress span because it does not measure anything. # https://github.com/rails/rails/blob/v6.1.7.6/activejob/lib/active_job/instrumentation.rb#L14 # https://github.com/rails/rails/blob/v7.0.8/activejob/lib/active_job/instrumentation.rb#L19 def subscribe return unless Array(@subscriptions).empty? mapper = Mappers::Attribute.new config = ActiveJob::Instrumentation.instance.config parent_span_provider = OpenTelemetry::Instrumentation::ActiveJob # TODO, use delegation instead of inheritance default_handler = Handlers::Default.new(parent_span_provider, mapper, config) enqueue_handler = Handlers::Enqueue.new(parent_span_provider, mapper, config) perform_handler = Handlers::Perform.new(parent_span_provider, mapper, config) handlers_by_pattern = { 'enqueue' => enqueue_handler, 'enqueue_at' => enqueue_handler, 'enqueue_retry' => default_handler, 'perform' => perform_handler, 'retry_stopped' => default_handler, 'discard' => default_handler } @subscriptions = handlers_by_pattern.map do |key, handler| ::ActiveSupport::Notifications.subscribe("#{key}.active_job", handler) end end # Removes Event Handler Subscriptions for ActiveJob notifications # @note this method is not thread-safe and should not be used in a multi-threaded context def unsubscribe @subscriptions&.each { |subscriber| ::ActiveSupport::Notifications.unsubscribe(subscriber) } @subscriptions = nil end end end end end