Module: Activerecord::Mysql::Reconnect

Defined in:
lib/activerecord/mysql/reconnect/version.rb,
lib/activerecord/mysql/reconnect.rb

Constant Summary collapse

VERSION =
'0.3.1'
DEFAULT_EXECUTION_TRIES =
3
DEFAULT_EXECUTION_RETRY_WAIT =
0.5
WITHOUT_RETRY_KEY =
'activerecord-mysql-reconnect-without-retry'
RETRYABLE_TRANSACTION_KEY =
'activerecord-mysql-reconnect-transaction-retry'
HANDLE_ERROR =
[
  ActiveRecord::StatementInvalid,
  Mysql2::Error,
]
HANDLE_R_ERROR_MESSAGES =
[
  'Lost connection to MySQL server during query',
]
HANDLE_RW_ERROR_MESSAGES =
[
  'MySQL server has gone away',
  'Server shutdown in progress',
  'closed MySQL connection',
  "Can't connect to MySQL server",
  'Query execution was interrupted',
  'Access denied for user',
]
HANDLE_ERROR_MESSAGES =
HANDLE_R_ERROR_MESSAGES + HANDLE_RW_ERROR_MESSAGES
READ_SQL_REGEXP =
/\A\s*(?:SELECT|SHOW|SET)\b/i
RETRY_MODES =
[:r, :rw, :force]
DEFAULT_RETRY_MODE =
:r

Class Method Summary collapse

Class Method Details

.enable_retryObject



61
62
63
# File 'lib/activerecord/mysql/reconnect.rb', line 61

def enable_retry
  !!ActiveRecord::Base.enable_retry
end

.execution_retry_waitObject



57
58
59
# File 'lib/activerecord/mysql/reconnect.rb', line 57

def execution_retry_wait
  ActiveRecord::Base.execution_retry_wait || DEFAULT_EXECUTION_RETRY_WAIT
end

.execution_triesObject



53
54
55
# File 'lib/activerecord/mysql/reconnect.rb', line 53

def execution_tries
  ActiveRecord::Base.execution_tries || DEFAULT_EXECUTION_TRIES
end

.loggerObject



111
112
113
114
115
116
117
# File 'lib/activerecord/mysql/reconnect.rb', line 111

def logger
  if defined?(Rails)
    Rails.logger || ActiveRecord::Base.logger || Logger.new($stderr)
  else
    ActiveRecord::Base.logger || Logger.new($stderr)
  end
end

.retry_modeObject



73
74
75
# File 'lib/activerecord/mysql/reconnect.rb', line 73

def retry_mode
  @activerecord_mysql_reconnect_retry_mode || DEFAULT_RETRY_MODE
end

.retry_mode=(v) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/activerecord/mysql/reconnect.rb', line 65

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) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/activerecord/mysql/reconnect.rb', line 77

def retryable(opts)
  block     = opts.fetch(:proc)
  on_error  = opts[:on_error]
  conn      = opts[:connection]
  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

        opt_msgs = ["cause: #{e} [#{e.class}]"]

        if conn and conn.kind_of?(Mysql2::Client)
          opt_msgs << 'connection: ' + [:host, :database, :username].map {|k| "#{k}=#{conn.query_options[k]}" }.join(";")
        end

        logger.warn("MySQL server has gone away. Trying to reconnect in #{wait} seconds. (#{opt_msgs.join(', ')})")
        sleep(wait)
        next
      else
        raise e
      end
    end
  end

  return retval
end

.retryable_transactionObject



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/activerecord/mysql/reconnect.rb', line 132

def retryable_transaction
  begin
    Thread.current[RETRYABLE_TRANSACTION_KEY] = []

    ActiveRecord::Base.transaction do
      yield
    end
  ensure
    Thread.current[RETRYABLE_TRANSACTION_KEY] = nil
  end
end

.retryable_transaction_bufferObject



144
145
146
# File 'lib/activerecord/mysql/reconnect.rb', line 144

def retryable_transaction_buffer
  Thread.current[RETRYABLE_TRANSACTION_KEY]
end

.without_retryObject



119
120
121
122
123
124
125
126
# File 'lib/activerecord/mysql/reconnect.rb', line 119

def without_retry
  begin
    Thread.current[WITHOUT_RETRY_KEY] = true
    yield
  ensure
    Thread.current[WITHOUT_RETRY_KEY] = nil
  end
end

.without_retry?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/activerecord/mysql/reconnect.rb', line 128

def without_retry?
  !!Thread.current[WITHOUT_RETRY_KEY]
end