Skip to content
Browse files

Ensure a deadlocked transaction is retried from beginning of the tran…

…saction.

Prior to this, if #transaction were called recursively, a deadlock
resulted in merely the innermost transaction call being retried,
which did not actually retry the transaction.
  • Loading branch information...
1 parent d182952 commit 303e830b2f5c3bb2a3ea1874c5084f895ae5d9d9 @jamis jamis committed Oct 14, 2008
Showing with 34 additions and 2 deletions.
  1. +1 −0 .gitignore
  2. +1 −0 lib/deadlock_retry.rb
  3. +32 −2 test/deadlock_retry_test.rb
View
1 .gitignore
@@ -0,0 +1 @@
+*.swp
View
1 lib/deadlock_retry.rb
@@ -44,6 +44,7 @@ def transaction_with_deadlock_handling(*objects, &block)
begin
transaction_without_deadlock_handling(*objects, &block)
rescue ActiveRecord::StatementInvalid => error
+ raise unless connection.open_transactions.zero?
if DEADLOCK_ERROR_MESSAGES.any? { |msg| error.message =~ /#{Regexp.escape(msg)}/ }
raise if retry_count >= MAXIMUM_RETRIES_ON_DEADLOCK
retry_count += 1
View
34 test/deadlock_retry_test.rb
@@ -20,8 +20,21 @@
require "#{File.dirname(__FILE__)}/../lib/deadlock_retry"
class MockModel
- def self.transaction(*objects, &block)
- block.call
+ @@open_transactions = 0
+
+ def self.transaction(*objects)
+ @@open_transactions += 1
+ yield
+ ensure
+ @@open_transactions -= 1
+ end
+
+ def self.open_transactions
+ @@open_transactions
+ end
+
+ def self.connection
+ self
end
def self.logger
@@ -62,4 +75,21 @@ def test_error_if_unrecognized_error
MockModel.transaction { raise ActiveRecord::StatementInvalid, "Something else" }
end
end
+
+ def test_error_in_nested_transaction_should_retry_outermost_transaction
+ tries = 0
+ errors = 0
+
+ MockModel.transaction do
+ tries += 1
+ MockModel.transaction do
+ MockModel.transaction do
+ errors += 1
+ raise ActiveRecord::StatementInvalid, "MySQL::Error: Lock wait timeout exceeded" unless errors > 3
+ end
+ end
+ end
+
+ assert_equal 4, tries
+ end
end

0 comments on commit 303e830

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