Skip to content

Commit

Permalink
Monitor the health of AR connections
Browse files Browse the repository at this point in the history
  • Loading branch information
rsamoilov committed Aug 30, 2024
1 parent 606855d commit 5a06c89
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/rage/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ def manually_release_ar_connections?
defined?(ActiveRecord) && ActiveRecord.version < Gem::Version.create("7.2.0")
end

# whether we should manually reconnect closed AR connections;
# AR 7.1+ does this automatically while executing the query;
def should_manually_restore_ar_connections?
defined?(ActiveRecord) && ActiveRecord.version < Gem::Version.create("7.1.0")
end

def inspect
"#<#{self.class.name}>"
end
Expand Down
40 changes: 40 additions & 0 deletions lib/rage/ext/active_record/connection_pool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,30 @@ def to_a
end
end

# reconnect closed connections on checkout;
# only included with `Rage.config.should_manually_restore_ar_connections?`
module ConnectionWithVerify
def connection
conn = super

if conn.__needs_reconnect
conn.reconnect!
conn.__needs_reconnect = false
end

conn
end
end
if Rage.config.internal.should_manually_restore_ar_connections?
prepend ConnectionWithVerify
end

def self.extended(instance)
instance.class.alias_method :__checkout__, :checkout
instance.class.alias_method :__remove__, :remove

ActiveRecord::ConnectionAdapters::AbstractAdapter.attr_accessor(:__idle_since)
ActiveRecord::ConnectionAdapters::AbstractAdapter.attr_accessor(:__needs_reconnect)
end

def __init_rage_extension
Expand Down Expand Up @@ -65,6 +84,26 @@ def __init_rage_extension
end
end

# monitor connections health
if Rage.config.internal.should_manually_restore_ar_connections?
Iodine.run_every(1_000) do
i = 0
while i < @__connections.length
conn = @__connections[i]

unless conn.__needs_reconnect
needs_reconnect = !conn.active? rescue true
if needs_reconnect
conn.__needs_reconnect = true
conn.disconnect!
end
end

i += 1
end
end
end

# resume blocked fibers once connections become available
Iodine.subscribe("ext:ar-connection-released") do
if @__blocked.length > 0 && @__connections.length > 0
Expand Down Expand Up @@ -135,6 +174,7 @@ def flush(minimum_idle = @__idle_timeout)
conn = @__connections[i]
if conn.__idle_since && current_time - conn.__idle_since >= minimum_idle
conn.__idle_since = nil
conn.__needs_reconnect = true
conn.disconnect!
end
i += 1
Expand Down

0 comments on commit 5a06c89

Please sign in to comment.