I was trying to fetch several images from the internet with Sketchup::Http and noticed that requests were being dropped without any error. Here is a sample code that demonstrates the issue. The code downloads and saves an image file 100 times:
requests_finished = []
url = "https://freetestdata.com/wp-content/uploads/2021/09/png-5mb-1.png"
100.times do |i|
request = Sketchup::Http::Request.new(url, Sketchup::Http::GET)
request.start do |req, res|
filename = File.join(ENV['temp'], "test_image_#{i}.png")
File.open(filename, 'wb') do |file|
file.write(res.body)
end
puts "Request #{i} finished"
requests_finished << i
end
end
When I run this code, only few of the requests actually finish (the number varies and it’s around 10). All other request are silently discarded. This is the output I get
Because (in the 1st example) you are not keeping persistent references to the objects and Ruby’s garbage collection is destroying the objects.
Because (in the 2nd example) you are storing references in the array.
Notice in the API documentation that the example snippets assign the request object reference to a persistent instance variable, … ie: @request.
This need to keep references to objects to prevent garbage collection is basic Ruby 101.
When you no longer need an object, assign it’s reference to nil and garbage collection will clean it up on it’s next sweep.
If the reference is a local reference inside a method, then this reference will automatically “go out of scope” when the method ends, and any object so referenced will become unreferenced and subsequently garbage collected.