lib/postgres/vacuum/jobs/monitor_job.rb in postgres-vacuum-monitor-0.16.0 vs lib/postgres/vacuum/jobs/monitor_job.rb in postgres-vacuum-monitor-0.17.0

- old
+ new

@@ -96,15 +96,43 @@ def with_each_db_name_and_connection databases = Set.new ActiveRecord::Base.connection_handler.connection_pools.map do |connection_pool| db_name = connection_pool.db_config.configuration_hash[:database] + next unless databases.add?(db_name) - # activerecord allocates a connection pool per call to establish_connection - # multiple pools might interact with the same database so we use the - # database name to dedup - connection_pool.with_connection { |conn| yield(db_name, conn) } if databases.add?(db_name) + # ActiveRecord allocates a connection pool per call to `.establish_connection` + # As a result, multiple pools might interact with the same database, so we use + # the database name to dedupe. + connection_pool.with_connection do |connection| + original_timeout = statement_timeout(connection) + set_statement_timeout(connection, "#{configured_timeout_seconds}s") + + yield(db_name, connection) + ensure + set_statement_timeout(connection, original_timeout) + end + + # We want to avoid hanging onto a bad connection that would cause all future + # jobs to fail, so we eagerly clear the pool. + rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionTimeoutError + connection_pool.disconnect! + raise end + end + + def statement_timeout(connection) + result = connection.execute('SHOW statement_timeout').first + result['statement_timeout'] if result.present? + end + + def set_statement_timeout(connection, timeout) + query = ActiveRecord::Base.sanitize_sql(['SET statement_timeout = ?', timeout]) + connection.execute(query) + end + + def configured_timeout_seconds + Postgres::Vacuum::Monitor.configuration.monitor_statement_timeout_seconds end ConfigurationError = Class.new(StandardError) end end