diff --git a/lib/ddtrace/contrib/rack/middlewares.rb b/lib/ddtrace/contrib/rack/middlewares.rb index 6eb44b77b8d..254c3ee6f13 100644 --- a/lib/ddtrace/contrib/rack/middlewares.rb +++ b/lib/ddtrace/contrib/rack/middlewares.rb @@ -40,7 +40,7 @@ def initialize(app, options = {}) def configure # ensure that the configuration is executed only once - return if @tracer && @service + return clean_context if @tracer && @service # retrieve the current tracer and service @tracer = @options.fetch(:tracer) @@ -135,6 +135,15 @@ def call(env) [status, headers, response] end + + private + + # TODO: Remove this once we change how context propagation works. This + # ensures we clean thread-local variables on each HTTP request avoiding + # memory leaks. + def clean_context + @tracer.provider.context = Datadog::Context.new + end end end end diff --git a/test/contrib/rack/helpers.rb b/test/contrib/rack/helpers.rb index 223a246cfe8..38657525557 100644 --- a/test/contrib/rack/helpers.rb +++ b/test/contrib/rack/helpers.rb @@ -14,6 +14,7 @@ class RackBaseTest < Minitest::Test def app tracer = @tracer + # rubocop:disable Metrics/BlockLength Rack::Builder.new do use Datadog::Contrib::Rack::TraceMiddleware, tracer: tracer @@ -73,6 +74,18 @@ def app [500, { 'Content-Type' => 'text/html' }, 'OK'] end) end + + map '/leak/' do + handler = proc do + tracer.trace('leaky-span-1') + tracer.trace('leaky-span-2') + tracer.trace('leaky-span-3') + + [200, { 'Content-Type' => 'text/html' }, 'OK'] + end + + run(handler) + end end.to_app end diff --git a/test/contrib/rack/middleware_test.rb b/test/contrib/rack/middleware_test.rb index 4743a76ec85..528b3fa2fdf 100644 --- a/test/contrib/rack/middleware_test.rb +++ b/test/contrib/rack/middleware_test.rb @@ -239,6 +239,14 @@ def test_request_middleware_non_standard_error assert_equal(1, span.status) assert_nil(span.parent) end + + def test_middleware_context_cleaning + get '/leak' + get '/success' + + assert_equal(0, @tracer.provider.context.trace.length) + assert_equal(1, @tracer.writer.spans.length) + end end class CustomTracerTest < RackBaseTest