module Activerecord::Mysql::Reconnect
Constants
- DEFAULT_EXECUTION_RETRY_WAIT
- DEFAULT_EXECUTION_TRIES
- DEFAULT_RETRY_MODE
- HANDLE_ERROR
- READ_SQL_REGEXP
- RETRY_MODES
- VERSION
- WITHOUT_RETRY_KEY
Public Class Methods
enable_retry()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 74 def enable_retry !!ActiveRecord::Base.enable_retry end
execution_retry_wait()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 69 def execution_retry_wait wait = ActiveRecord::Base.execution_retry_wait || DEFAULT_EXECUTION_RETRY_WAIT wait.kind_of?(BigDecimal) ? wait : BigDecimal(wait.to_s) end
execution_tries()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 65 def execution_tries ActiveRecord::Base.execution_tries || DEFAULT_EXECUTION_TRIES end
handle_r_error_messages()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 57 def handle_r_error_messages @@handle_r_error_messages end
handle_rw_error_messages()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 61 def handle_rw_error_messages @@handle_rw_error_messages end
logger()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 151 def logger if defined?(Rails) Rails.logger || ActiveRecord::Base.logger || Logger.new($stderr) else ActiveRecord::Base.logger || Logger.new($stderr) end end
retry_databases()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 114 def retry_databases @activerecord_mysql_reconnect_retry_databases || [] end
retry_databases=(v)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 90 def retry_databases=(v) v ||= [] unless v.kind_of?(Array) v = [v] end @activerecord_mysql_reconnect_retry_databases = v.map do |database| if database.instance_of?(Symbol) database = Regexp.escape(database.to_s) [/.*/, /\A#{database}\z/] else host = '%' database = database.to_s if database =~ /:/ host, database = database.split(':', 2) end [create_pattern_match_regex(host), create_pattern_match_regex(database)] end end end
retry_mode()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 86 def retry_mode @activerecord_mysql_reconnect_retry_mode || DEFAULT_RETRY_MODE end
retry_mode=(v)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 78 def retry_mode=(v) unless RETRY_MODES.include?(v) raise "Invalid retry_mode. Please set one of the following: #{RETRY_MODES.map {|i| i.inspect }.join(', ')}" end @activerecord_mysql_reconnect_retry_mode = v end
retryable(opts)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 118 def retryable(opts) block = opts.fetch(:proc) on_error = opts[:on_error] conn = opts[:connection] sql = opts[:sql] tries = self.execution_tries retval = nil retryable_loop(tries) do |n| begin retval = block.call break rescue => e if enable_retry and (tries.zero? or n < tries) and should_handle?(e, opts) on_error.call if on_error wait = self.execution_retry_wait * n logger.warn("MySQL server has gone away. Trying to reconnect in #{wait.to_f} seconds. (#{build_error_message(e, sql, conn)})") sleep(wait) next else if enable_retry and n > 1 logger.warn("Query retry failed. (#{build_error_message(e, sql, conn)})") end raise e end end end return retval end
without_retry() { || ... }
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 159 def without_retry begin Thread.current[WITHOUT_RETRY_KEY] = true yield ensure Thread.current[WITHOUT_RETRY_KEY] = nil end end
without_retry?()
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 168 def without_retry? !!Thread.current[WITHOUT_RETRY_KEY] end
Private Class Methods
build_error_message(e, sql, conn)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 255 def build_error_message(e, sql, conn) msgs = {cause: "#{e.message} [#{e.class}]"} msgs[:sql] = sql if sql if conn conn_info = connection_info(conn) msgs[:connection] = [:host, :database, :username].map {|k| "#{k}=#{conn_info[k]}" }.join(";") end msgs.map {|k, v| "#{k}: #{v}" }.join(", ") end
connection_info(conn)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 222 def connection_info(conn) conn_info = {} if conn.kind_of?(Mysql2::Client) [:host, :database, :username].each {|k| conn_info[k] = conn.query_options[k] } elsif conn.kind_of?(Hash) conn_info = conn.dup end return conn_info end
create_pattern_match_regex(str)
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 234 def create_pattern_match_regex(str) ss = StringScanner.new(str) buf = [] until ss.eos? if (tok = ss.scan(/[^\\%_]+/)) buf << Regexp.escape(tok) elsif (tok = ss.scan(/\\/)) buf << Regexp.escape(ss.getch) elsif (tok = ss.scan(/%/)) buf << '.*' elsif (tok = ss.scan(/_/)) buf << '.' else raise 'must not happen' end end /\A#{buf.join}\z/ end
retryable_loop(n) { |n| ... }
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 174 def retryable_loop(n) if n.zero? loop { n += 1 ; yield(n) } else n.times {|i| yield(i + 1) } end end
should_handle?(e, opts = {})
click to toggle source
# File lib/activerecord/mysql/reconnect.rb, line 182 def should_handle?(e, opts = {}) sql = opts[:sql] retry_mode = opts[:retry_mode] conn = opts[:connection] if without_retry? return false end if conn and not retry_databases.empty? conn_info = connection_info(conn) included = retry_databases.any? do |host, database| host =~ conn_info[:host] and database =~ conn_info[:database] end return false unless included end unless HANDLE_ERROR.any? {|i| e.kind_of?(i) } return false end unless Regexp.union(@@handle_r_error_messages.values + @@handle_rw_error_messages.values) =~ e.message return false end if sql and READ_SQL_REGEXP !~ sql if retry_mode == :r return false end if retry_mode != :force and Regexp.union(@@handle_r_error_messages.values) =~ e.message return false end end return true end