Closed watzon closed 4 years ago
@watzon I'm just curious about what kind of problem you try to solve with a pool connection?
As things sit, HTTP clients cannot be used across fibers/threads. If you try you end up getting a massive stack trace that points to an OpenSSL problem, when in reality it's just that HTTP::Client itself isn't thread safe. To get around that you can use a connection pool so that each fiber just pulls a client out of the pool, uses it, and checks it back in.
Not great for memory I have to say, but it works.
Interesting. I'll try to implement this.
Probably I will not implement this feature for crest
.
But you can easily wrap HTTP::Client
with a connection pool. Something like this:
class HTTP::PooledClient
getter pool
def initialize(*args, pool_size = 5, pool_timeout = 10.0, **args2)
@pool = ConnectionPool(HTTP::Client).new(capacity: pool_size, timeout: pool_timeout) do
HTTP::Client.new(*args, **args2)
end
end
macro method_missing(call)
# Delegates all methods to a `HTTP::Client` instance from the connection pool.
with_pool_connection { |conn| conn.{{call}} }
end
private def with_pool_connection
conn = begin
@pool.checkout
rescue IO::TimeoutError
raise Exception.new("No free connection (used #{@pool.size} of #{@pool.capacity}) after timeout of #{@pool.timeout}s")
end
begin
yield(conn)
ensure
@pool.checkin(conn)
end
end
end
I checked with code and looks like it works as you want:
url = "https://httpbin.org"
client = HTTP::PooledClient.new(URI.parse(url))
15.times do |i|
spawn do
url = "/delay/#{rand(1..5)}"
response = client.get(url)
print "[#{i}] "
puts JSON.parse(response.body)["url"]
end
end
Fiber.yield
gets
Result
[3] https://httpbin.org/delay/1
[1] https://httpbin.org/delay/2
[4] https://httpbin.org/delay/3
[6] https://httpbin.org/delay/1
[5] https://httpbin.org/delay/3
[0] https://httpbin.org/delay/5
[2] https://httpbin.org/delay/5
[7] https://httpbin.org/delay/2
[9] https://httpbin.org/delay/1
[8] https://httpbin.org/delay/2
[10] https://httpbin.org/delay/1
[11] https://httpbin.org/delay/3
[12] https://httpbin.org/delay/3
[13] https://httpbin.org/delay/5
[14] https://httpbin.org/delay/4
Understandable, thanks :+1:
It would be nice, for my use case at least, if crest had the ability to maintain a pool of internal clients, and gave the user the ability to decide how large that pool was. Something like ysbaddaden/pool could be used underneath.