Skip to content
Browse files

[FIX] matching this gem for Fiverr, also adding an interface to set r…

…etry count on Active::Record
  • Loading branch information...
1 parent 874c80d commit 562a094c4c44c0b410f06b3e523872b69e3ca551 @eladmeidar eladmeidar committed Jun 3, 2012
Showing with 17 additions and 52 deletions.
  1. +16 −51 lib/deadlock_retry.rb
  2. +1 −1 lib/deadlock_retry/version.rb
View
67 lib/deadlock_retry.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/module/attribute_accessors'
-
module DeadlockRetry
def self.included(base)
base.extend(ClassMethods)
@@ -10,8 +8,6 @@ class << self
end
end
- mattr_accessor :innodb_status_cmd
-
module ClassMethods
DEADLOCK_ERROR_MESSAGES = [
"Deadlock found when trying to get lock",
@@ -21,21 +17,16 @@ module ClassMethods
MAXIMUM_RETRIES_ON_DEADLOCK = 3
-
def transaction_with_deadlock_handling(*objects, &block)
retry_count = 0
-
- check_innodb_status_available
-
begin
transaction_without_deadlock_handling(*objects, &block)
rescue ActiveRecord::StatementInvalid => error
raise if in_nested_transaction?
if DEADLOCK_ERROR_MESSAGES.any? { |msg| error.message =~ /#{Regexp.escape(msg)}/ }
- raise if retry_count >= MAXIMUM_RETRIES_ON_DEADLOCK
+ raise if retry_count >= self.class.transaction_lock_retries
retry_count += 1
logger.info "Deadlock detected on retry #{retry_count}, restarting transaction"
- log_innodb_status if DeadlockRetry.innodb_status_cmd
exponential_pause(retry_count)
retry
else
@@ -46,7 +37,7 @@ def transaction_with_deadlock_handling(*objects, &block)
private
- WAIT_TIMES = [0, 1, 2, 4, 8, 16, 32]
+ WAIT_TIMES = [0, 1, 2, 3, 4, 5, 6]
def exponential_pause(count)
sec = WAIT_TIMES[count-1] || 32
@@ -60,48 +51,22 @@ def in_nested_transaction?
connection.open_transactions != 0
end
- def show_innodb_status
- self.connection.select_value(DeadlockRetry.innodb_status_cmd)
- end
-
- # Should we try to log innodb status -- if we don't have permission to,
- # we actually break in-flight transactions, silently (!)
- def check_innodb_status_available
- return unless DeadlockRetry.innodb_status_cmd == nil
-
- if self.connection.adapter_name == "MySQL"
- begin
- mysql_version = self.connection.select_rows('show variables like \'version\'')[0][1]
- cmd = if mysql_version < '5.5'
- 'show innodb status'
- else
- 'show engine innodb status'
- end
- self.connection.select_value(cmd)
- DeadlockRetry.innodb_status_cmd = cmd
- rescue
- logger.info "Cannot log innodb status: #{$!.message}"
- DeadlockRetry.innodb_status_cmd = false
- end
- else
- DeadlockRetry.innodb_status_cmd = false
- end
- end
+ end
+end
- def log_innodb_status
- # show innodb status is the only way to get visiblity into why
- # the transaction deadlocked. log it.
- lines = show_innodb_status
- logger.warn "INNODB Status follows:"
- lines.each_line do |line|
- logger.warn line
- end
- rescue => e
- # Access denied, ignore
- logger.info "Cannot log innodb status: #{e.message}"
+class ActiveRecord::Base
+
+ cattr_reader :maximum_transaction_lock_retries
+
+ def self.transaction_lock_retries
+ @@maximum_transaction_lock_retries || 3
+ end
+
+ def self.transaction_lock_retries=(maximum)
+ if maximum < 0
+ maximum = 0
end
-
+ @@maximum_transaction_lock_retries = maximum
end
end
-
ActiveRecord::Base.send(:include, DeadlockRetry) if defined?(ActiveRecord)
View
2 lib/deadlock_retry/version.rb
@@ -1,3 +1,3 @@
module DeadlockRetry
- VERSION = '1.2.0'
+ VERSION = '1.2.1'
end

0 comments on commit 562a094

Please sign in to comment.
Something went wrong with that request. Please try again.