Description
Describe the bug
I am investigating a memory leak in one of the systems I own and I think it is coming from Stripe::StripeObject
.
To Reproduce
I was able to run some tests using the Stripe gem and Faraday gem on a separate instance and these were the results:
From 2:15pm until 2:35pm I was making requests to an endpoint that uses the Stripe gem and from 2:35 onwards it was using Faraday.
As you can see, the memory increases linearly when using the Stripe gem, but stays almost constant using Faraday.
This was the code using Rails + Grape:
CUSTOMER_ID = "cus_" # Use an existing customer id
desc "Check if the memory leak is in Stripe::Customer.retrieve"
get '/1' do
customer = Stripe::Customer.retrieve(CUSTOMER_ID, api_key: ENV["STRIPE_API_KEY"])
{ customer: { id: customer.id } }
end
desc "Use Faraday to see if the memory leak still persists"
get '/2' do
response = Faraday.get("https://api.stripe.com/v1/customers/#{CUSTOMER_ID}") do |request|
request.headers['Authorization'] = "Bearer #{ENV["STRIPE_API_KEY"]}"
# Use the same API version defined in the Stripe gem
request.headers['Stripe-Version'] = Stripe.api_version
end
response_body = JSON.parse(response.body)
{ customer: { id: response_body['id'] } }
end
Then I created a script to hit the endpoints 5000 times each with a delay in between to make it easier to identify in the graphs.
Expected behavior
I would expect the memory to stay constant or be freed on a garbage collection.
Code snippets
No response
OS
Aws Linux 2 and Ubuntu 24
Language version
Ruby 3.3.3
Library version
stripe-ruby v11.7.0 and 13.1.0
API version
2024-04-10
Additional context
My guess is that it is related to Stripe::StripeObject#add_accessors
method, I think the dynamic methods are not being garbage collected when the object is destroyed.
This seems to have been going on for a little while (maybe years?), we only noticed a few months ago once we started getting a bit more traffic in one of our services.