diff --git a/lib/datadog/statsd/sender.rb b/lib/datadog/statsd/sender.rb index 9f50cc8..85394d5 100644 --- a/lib/datadog/statsd/sender.rb +++ b/lib/datadog/statsd/sender.rb @@ -104,6 +104,8 @@ def start # start background thread @sender_thread = @thread_class.new(&method(:send_loop)) @sender_thread.name = "Statsd Sender" unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') + # advise multi-threaded app servers to ignore this thread for the purposes of fork safety warnings + @sender_thread.thread_variable_set(:fork_safe, true) rescue ThreadError => e @logger.debug { "Statsd: Failed to start sender thread: #{e.message}" } if @logger @mx.synchronize { @done = true } diff --git a/spec/statsd/sender_spec.rb b/spec/statsd/sender_spec.rb index 95c1f01..b0bf85d 100644 --- a/spec/statsd/sender_spec.rb +++ b/spec/statsd/sender_spec.rb @@ -48,6 +48,13 @@ |thds| thds.any? { |t| t.name == "Statsd Sender" } } end + + it 'marks the sender thread as fork safe' do + subject.start + expect(Thread.list).to satisfy { + |thds| thds.any? { |t| t.name == "Statsd Sender" && t.thread_variable_get(:fork_safe) } + } + end end context 'when the sender is started' do @@ -204,9 +211,9 @@ let(:thread_class) do if Thread.instance_methods.include?(:name=) - fake_thread = instance_double(Thread, { "alive?" => true, "name=" => true, "join" => true }) + fake_thread = instance_double(Thread, { "alive?" => true, "name=" => true, "join" => true, "thread_variable_set" => true }) else - fake_thread = instance_double(Thread, { "alive?" => true, "join" => true }) + fake_thread = instance_double(Thread, { "alive?" => true, "join" => true, "thread_variable_set" => true }) end class_double(Thread, new: fake_thread) end