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
|
@ -1,4 +1,7 @@
|
|||
module DB
|
||||
abstract class Connection
|
||||
end
|
||||
|
||||
class Error < Exception
|
||||
end
|
||||
|
||||
|
@ -11,20 +14,29 @@ module DB
|
|||
class PoolRetryAttemptsExceeded < Error
|
||||
end
|
||||
|
||||
class PoolResourceLost(T) < Error
|
||||
getter resource : T
|
||||
|
||||
def initialize(@resource : T)
|
||||
end
|
||||
end
|
||||
|
||||
class PoolResourceRefused < Error
|
||||
end
|
||||
|
||||
# Raised when an established connection is lost
|
||||
# probably due to socket/network issues.
|
||||
# It is used by the connection pool retry logic.
|
||||
class ConnectionLost < Error
|
||||
getter connection : Connection
|
||||
|
||||
def initialize(@connection)
|
||||
class ConnectionLost < PoolResourceLost(Connection)
|
||||
def connection
|
||||
resource
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a connection is unable to be established
|
||||
# probably due to socket/network or configuration issues.
|
||||
# It is used by the connection pool retry logic.
|
||||
class ConnectionRefused < Error
|
||||
class ConnectionRefused < PoolResourceRefused
|
||||
end
|
||||
|
||||
class Rollback < Error
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
require "weak_ref"
|
||||
|
||||
require "./error"
|
||||
|
||||
module DB
|
||||
class Pool(T)
|
||||
# Pool configuration
|
||||
|
@ -52,12 +54,19 @@ module DB
|
|||
@idle.clear
|
||||
end
|
||||
|
||||
record Stats, open_connections : Int32
|
||||
record Stats,
|
||||
open_connections : Int32,
|
||||
idle_connections : Int32,
|
||||
in_flight_connections : Int32,
|
||||
max_connections : Int32
|
||||
|
||||
# Returns stats of the pool
|
||||
def stats
|
||||
Stats.new(
|
||||
open_connections: @total.size
|
||||
open_connections: @total.size,
|
||||
idle_connections: @idle.size,
|
||||
in_flight_connections: @inflight,
|
||||
max_connections: @max_pool_size,
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -91,10 +100,22 @@ module DB
|
|||
resource
|
||||
end
|
||||
|
||||
res.before_checkout
|
||||
if res.responds_to?(:before_checkout)
|
||||
res.before_checkout
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def checkout(&block : T ->)
|
||||
connection = checkout
|
||||
|
||||
begin
|
||||
yield connection
|
||||
ensure
|
||||
release connection
|
||||
end
|
||||
end
|
||||
|
||||
# ```
|
||||
# selected, is_candidate = pool.checkout_some(candidates)
|
||||
# ```
|
||||
|
@ -122,7 +143,9 @@ module DB
|
|||
sync do
|
||||
if can_increase_idle_pool
|
||||
@idle << resource
|
||||
resource.after_release
|
||||
if resource.responds_to?(:after_release)
|
||||
resource.after_release
|
||||
end
|
||||
idle_pushed = true
|
||||
else
|
||||
resource.close
|
||||
|
@ -153,12 +176,12 @@ module DB
|
|||
begin
|
||||
sleep @retry_delay if i >= current_available
|
||||
return yield
|
||||
rescue e : ConnectionLost
|
||||
rescue e : PoolResourceLost(T)
|
||||
# if the connection is lost close it to release resources
|
||||
# and remove it from the known pool.
|
||||
sync { delete(e.connection) }
|
||||
e.connection.close
|
||||
rescue e : ConnectionRefused
|
||||
sync { delete(e.resource) }
|
||||
e.resource.close
|
||||
rescue e : PoolResourceRefused
|
||||
# a ConnectionRefused means a new connection
|
||||
# was intended to be created
|
||||
# nothing to due but to retry soon
|
||||
|
@ -215,7 +238,7 @@ module DB
|
|||
sync_dec_waiting_resource
|
||||
when timeout(@checkout_timeout.seconds)
|
||||
sync_dec_waiting_resource
|
||||
raise DB::PoolTimeout.new
|
||||
raise DB::PoolTimeout.new("Could not check out a connection in #{@checkout_timeout} seconds")
|
||||
end
|
||||
end
|
||||
{% else %}
|
||||
|
@ -232,7 +255,7 @@ module DB
|
|||
sync_dec_waiting_resource
|
||||
when 1
|
||||
sync_dec_waiting_resource
|
||||
raise DB::PoolTimeout.new
|
||||
raise DB::PoolTimeout.new("Could not check out a connection in #{@checkout_timeout} seconds")
|
||||
else
|
||||
raise DB::Error.new
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue