Skip to content

Commit

Permalink
Fix memory leak in the curb instrumentation
Browse files Browse the repository at this point in the history
On long-running connection Curb use-cases like
Elasticsearch clients with Curb transport the `request` variable
points to the same Curb object not just for one request but for all.

Therefore, for each succesful request following the first one,
`original_callback` points to the previous on_failure callback set by newrelic.
So, an infinite chain of callbacks is created since newrelic's on_failure
callback maintains a reference to `original_callback`.

The changes force `original_callback` to point to the actual original callback on
subsequent requests instead of pointing to the newrelic's callback.
That way no reference is maintained for newrelic's callback of the
previous request & the memory leak is prevented by the GC.
  • Loading branch information
charkost committed Oct 1, 2022
1 parent f5523ff commit 1ad0632
Showing 1 changed file with 9 additions and 1 deletion.
10 changes: 9 additions & 1 deletion lib/new_relic/agent/instrumentation/curb/instrumentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,14 @@ def install_completion_callback(request, wrapped_response, segment)
# our on_failure callback hook.
def install_failure_callback(request, wrapped_response, segment)
return if request._nr_failure_instrumented

original_callback = request.on_failure
nr_original_callback = original_callback&.instance_variable_get(:@__newrelic_original_callback)
original_callback = nr_original_callback || original_callback

request._nr_original_on_failure = original_callback
request.on_failure do |failed_request, error|

newrelic_callback = Proc.new do |failed_request, error|
begin
if segment
noticible_error = NewRelic::Agent::NoticibleError.new(error[0].name, error[-1])
Expand All @@ -175,6 +180,9 @@ def install_failure_callback(request, wrapped_response, segment)
end
request._nr_failure_instrumented = true
end
newrelic_callback.instance_variable_set(:@__newrelic_original_callback, original_callback)

request.on_failure(&newrelic_callback)
end

# on_failure callbacks cannot be removed in the on_complete
Expand Down

0 comments on commit 1ad0632

Please sign in to comment.