class ActiveRecord::Bogacs::Validator
Every frequency seconds, the validator will perform connection validation on a pool it operates.
Configure the frequency by setting ‘:validate_frequency` in your AR configuration.
We recommend not setting values too low as that would drain the pool’s performance under heavy concurrent connection retrieval. Connections are also validated upon checkout - the validator is intended to detect long idle pooled connections “ahead of time” instead of upon retrieval.
@note Do not use a reaper with the validator! Reaping (stale connection detection and removal) is part of the validation process and will only slow things down as all pool connection updates needs to be synchronized.
Constants
- TimerTask
Attributes
Public Class Methods
‘Validator.new(pool, spec.config).run` @private
# File lib/active_record/bogacs/validator.rb, line 30 def initialize(pool, frequency = 60, timeout = nil) @pool = pool; PoolAdaptor.adapt! pool if frequency # validate every 60s by default frequency = frequency.to_f @frequency = frequency > 0.0 ? frequency : false else @frequency = nil end if timeout timeout = timeout.to_f @timeout = timeout > 0.0 ? timeout : 0 else @timeout = @frequency end @running = nil end
Public Instance Methods
# File lib/active_record/bogacs/validator.rb, line 47 def run return unless frequency @running = true; start end
# File lib/active_record/bogacs/validator.rb, line 61 def running?; @running end
# File lib/active_record/bogacs/validator.rb, line 55 def start TimerTask.new(:execution_interval => frequency, :timeout_interval => timeout) do validate_connections end end
# File lib/active_record/bogacs/validator.rb, line 63 def validate start = Time.now conns = connections logger && logger.debug("[validator] found #{conns.size} candidates to validate") invalid = 0 conns.each { |connection| invalid += 1 if validate_connection(connection) == false } logger && logger.info("[validator] validated pool in #{Time.now - start}s (removed #{invalid} connections from pool)") invalid end
Private Instance Methods
# File lib/active_record/bogacs/validator.rb, line 75 def connections connections = pool.connections.dup connections.map! do |conn| if conn if owner = conn.owner if owner.alive? nil # owner.alive? ... do not touch else # stale-conn (reaping) pool.remove conn # remove is synchronized conn.disconnect! rescue nil nil end elsif conn.in_use? # no owner? (likely a nasty bug) logger && logger.warn("[validator] found in-use connection ##{conn.object_id} without owner - removing from pool") pool.remove_without_owner conn # synchronized conn.disconnect! rescue nil nil else conn # conn not in-use - candidate for validation end end end connections.compact end
def synchronize(&block); pool.synchronize(&block) end
# File lib/active_record/bogacs/validator.rb, line 124 def logger @logger ||= ( pool.respond_to?(:logger) ? pool.logger : nil ) rescue nil end
# File lib/active_record/bogacs/validator.rb, line 100 def validate_connection(conn) return nil if conn.in_use? pool.synchronize do # make sure it won't get checked-out while validating return nil if conn.in_use? # NOTE: active? is assumed to behave e.g. connection_alive_timeout used # on AR-JDBC active? might return false as the JDBC connection is lazy # ... but that is just fine! begin return true if conn.active? # validate the connection - ping the DB rescue => e logger && logger.info("[validator] connection ##{conn.object_id} failed to validate: #{e.inspect}") end # TODO support seconds_idle - only validate if certain amount since use passed logger && logger.debug("[validator] found non-active connection ##{conn.object_id} - removing from pool") pool.remove_without_owner conn # not active - remove conn.disconnect! rescue nil return false end end