mirror of
https://gitea.invidious.io/iv-org/shard-crystal-db.git
synced 2024-08-15 00:53:32 +00:00
Allow DB::Pool to be used a generic connection pool (#131)
* Allow DB::Pool to be a generic connection pool * Use fully qualified class name for consistency Co-authored-by: Brian J. Cardiff <bcardiff@gmail.com> * Wrap only the necessary code in an `ensure` * Add spec for http client pool * Fix ICE in crystal-sqlite3 Co-authored-by: Brian J. Cardiff <bcardiff@gmail.com>
This commit is contained in:
parent
ed686ad301
commit
291b65b853
5 changed files with 166 additions and 15 deletions
52
spec/http_client_pool_spec.cr
Normal file
52
spec/http_client_pool_spec.cr
Normal file
|
@ -0,0 +1,52 @@
|
|||
require "./spec_helper"
|
||||
require "./support/http"
|
||||
|
||||
describe DB::Pool do
|
||||
it "distributes evenly the requests" do
|
||||
mutex = Mutex.new
|
||||
requests_per_connection = Hash(Socket::Address, Int32).new
|
||||
|
||||
server = HTTP::Server.new do |context|
|
||||
remote_address = context.request.remote_address.not_nil!
|
||||
mutex.synchronize do
|
||||
requests_per_connection[remote_address] ||= 0
|
||||
requests_per_connection[remote_address] += 1
|
||||
end
|
||||
sleep context.request.query_params["delay"].to_f
|
||||
context.response.print "ok"
|
||||
end
|
||||
address = server.bind_unused_port "127.0.0.1"
|
||||
|
||||
run_server(server) do
|
||||
fixed_pool_size = 5
|
||||
expected_per_connection = 5
|
||||
requests = fixed_pool_size * expected_per_connection
|
||||
|
||||
pool = DB::Pool.new(
|
||||
initial_pool_size: fixed_pool_size,
|
||||
max_pool_size: fixed_pool_size,
|
||||
max_idle_pool_size: fixed_pool_size) {
|
||||
HTTP::Client.new(URI.parse("http://127.0.0.1:#{address.port}/"))
|
||||
}
|
||||
|
||||
done = Channel(Nil).new
|
||||
|
||||
requests.times do
|
||||
spawn do
|
||||
pool.checkout do |http|
|
||||
http.get("/?delay=0.1")
|
||||
end
|
||||
done.send(nil)
|
||||
end
|
||||
end
|
||||
|
||||
spawn do
|
||||
requests.times { done.receive }
|
||||
done.close
|
||||
end
|
||||
wait_for { done.closed? }
|
||||
|
||||
requests_per_connection.values.should eq([expected_per_connection] * fixed_pool_size)
|
||||
end
|
||||
end
|
||||
end
|
16
spec/support/fibers.cr
Normal file
16
spec/support/fibers.cr
Normal file
|
@ -0,0 +1,16 @@
|
|||
def wait_until_blocked(f : Fiber, timeout = 5.seconds)
|
||||
now = Time.monotonic
|
||||
|
||||
until f.resumable?
|
||||
Fiber.yield
|
||||
raise "fiber failed to block within #{timeout}" if (Time.monotonic - now) > timeout
|
||||
end
|
||||
end
|
||||
|
||||
def wait_until_finished(f : Fiber, timeout = 5.seconds)
|
||||
now = Time.monotonic
|
||||
until f.dead?
|
||||
Fiber.yield
|
||||
raise "fiber failed to finish within #{timeout}" if (Time.monotonic - now) > timeout
|
||||
end
|
||||
end
|
48
spec/support/http.cr
Normal file
48
spec/support/http.cr
Normal file
|
@ -0,0 +1,48 @@
|
|||
require "http"
|
||||
require "./fibers"
|
||||
|
||||
def wait_for(timeout = 5.seconds)
|
||||
now = Time.monotonic
|
||||
|
||||
until yield
|
||||
Fiber.yield
|
||||
|
||||
if (Time.monotonic - now) > timeout
|
||||
raise "block failed to evaluate to true within #{timeout}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method which runs *server*
|
||||
# 1. Spawns `server.listen` in a new fiber.
|
||||
# 2. Waits until `server.listening?`.
|
||||
# 3. Yields to the given block.
|
||||
# 4. Ensures the server is closed.
|
||||
# 5. After returning from the block, it waits for the server to gracefully
|
||||
# shut down before continuing execution in the current fiber.
|
||||
# 6. If the listening fiber raises an exception, it is rescued and re-raised
|
||||
# in the current fiber.
|
||||
def run_server(server)
|
||||
server_done = Channel(Exception?).new
|
||||
|
||||
f = spawn do
|
||||
server.listen
|
||||
rescue exc
|
||||
server_done.send exc
|
||||
else
|
||||
server_done.send nil
|
||||
end
|
||||
|
||||
begin
|
||||
wait_for { server.listening? }
|
||||
wait_until_blocked f
|
||||
|
||||
yield server_done
|
||||
ensure
|
||||
server.close unless server.closed?
|
||||
|
||||
if exc = server_done.receive
|
||||
raise exc
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue