diff --git a/lib/datadog/tracing/contrib/extensions.rb b/lib/datadog/tracing/contrib/extensions.rb index fde0a34c0f0..c706eb5e66f 100644 --- a/lib/datadog/tracing/contrib/extensions.rb +++ b/lib/datadog/tracing/contrib/extensions.rb @@ -110,6 +110,13 @@ def configure(&block) module Settings InvalidIntegrationError = Class.new(StandardError) + # Used to avoid concurrency issues between registering integrations (e.g. mutation) and reporting the + # current integrations for logging/debugging/telemetry purposes (e.g. iteration) in the + # `@instrumented_integrations` hash. + # + # See https://github.com/DataDog/dd-trace-rb/issues/2851 for details on the original issue. + INSTRUMENTED_INTEGRATIONS_LOCK = Mutex.new + def self.included(base) base.class_eval do settings :contrib do @@ -161,7 +168,10 @@ def instrument(integration_name, options = {}, &block) configuration_name = options[:describes] || :default filtered_options = options.reject { |k, _v| k == :describes } integration.configure(configuration_name, filtered_options, &block) - instrumented_integrations[integration_name] = integration + INSTRUMENTED_INTEGRATIONS_LOCK.synchronize do + @instrumented_integrations ||= {} + @instrumented_integrations[integration_name] = integration + end # Add to activation list integrations_pending_activation << integration @@ -192,14 +202,16 @@ def integrations_pending_activation @integrations_pending_activation ||= Set.new end + # This method is only for logging/debugging/telemetry purposes (e.g. iteration) in the + # `@instrumented_integrations` hash. # @!visibility private def instrumented_integrations - @instrumented_integrations ||= {} + INSTRUMENTED_INTEGRATIONS_LOCK.synchronize { (@instrumented_integrations&.dup || {}).freeze } end # @!visibility private def reset! - instrumented_integrations.clear + INSTRUMENTED_INTEGRATIONS_LOCK.synchronize { @instrumented_integrations&.clear } super end diff --git a/spec/datadog/tracing/contrib/extensions_spec.rb b/spec/datadog/tracing/contrib/extensions_spec.rb index 461fd09852f..ee969b45ef5 100644 --- a/spec/datadog/tracing/contrib/extensions_spec.rb +++ b/spec/datadog/tracing/contrib/extensions_spec.rb @@ -26,6 +26,10 @@ before { registry.add(integration_name, integration) } end + before do + allow(Datadog.logger).to receive(:warn) + end + context 'for' do describe Datadog do describe '#configure' do @@ -244,6 +248,12 @@ def self.patch end end end + + describe '#instrumented_integrations' do + subject(:instrumented_integrations) { settings.instrumented_integrations } + + it { is_expected.to be_frozen } + end end end end