Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deadlock retry fails to save record that raises a deadlock in after hooks #10

Open
mdimas opened this issue Feb 4, 2012 · 4 comments
Open

Comments

@mdimas
Copy link

mdimas commented Feb 4, 2012

If a deadlock occurs in an after commit hook for a record deadlock_retry will retry the commit but issues an "UPDATE" instead of an "INSERT" statement, resulting in the record never being saved even though calling #save returns true. This is easily demonstrated with the following code:

require 'deadlock_retry'

class MyTest < ActiveRecord::Base

  after_create :deadlock_error
  after_commit :puts_after_commit, :on => :create

  def deadlock_error
    unless @errored
      @errored = true
      raise ActiveRecord::StatementInvalid.new("Deadlock found when trying to get lock")
    end
    return
  end

  def puts_after_commit
    puts "After Commit"
  end
end

my_test = MyTest.new(:name => "Testing")

if my_test.save
  MyTest.find(my_test.id)
end

This will have the following output:

> my_test = MyTest.new(:name => "Testing")
=> #<MyTest id: nil, name: "Testing"> 
> if my_test.save
?>     MyTest.find(my_test.id)
?>   end

After Commit
ActiveRecord::RecordNotFound: Couldn't find MyTest with ID=1
from /Users/dimas/.rvm/gems/ree-1.8.7-2011.03/gems/activerecord-3.0.11/lib/active_record/relation/finder_methods.rb:306:in `find_one'
from /Users/dimas/.rvm/gems/ree-1.8.7-2011.03/gems/activerecord-3.0.11/lib/active_record/relation/finder_methods.rb:291:in `find_with_ids'
from /Users/dimas/.rvm/gems/ree-1.8.7-2011.03/gems/activerecord-3.0.11/lib/active_record/relation/finder_methods.rb:107:in `find'
from /Users/dimas/.rvm/gems/ree-1.8.7-2011.03/gems/activerecord-3.0.11/lib/active_record/base.rb:444:in `__send__'
from /Users/dimas/.rvm/gems/ree-1.8.7-2011.03/gems/activerecord-3.0.11/lib/active_record/base.rb:444:in `find'
from (irb):22

And if you look at the log you'll see:

SQL (0.1ms)  BEGIN
SQL (1.9ms)  describe `my_tests`
AREL (0.2ms)  INSERT INTO `my_tests` (`name`) VALUES ('Testing')
SQL (0.5ms)  ROLLBACK
Deadlock detected on retry 1, restarting transaction
SQL (3.3ms)  BEGIN
AREL (0.3ms)  UPDATE `my_tests` SET `name` = 'Testing' WHERE `my_tests`.`id` = 1
SQL (0.1ms)  COMMIT
MyTest Load (0.2ms)  SELECT `my_tests`.* FROM `my_tests` WHERE `my_tests`.`id` = 1 LIMIT 1
@mdimas
Copy link
Author

mdimas commented Feb 15, 2012

Is there a fix for this issue?

@artemv
Copy link

artemv commented Dec 5, 2013

arrgh just faced this issue on Prod, after using the gem for couple years! now need to remove the gem, sigh..

@artemv
Copy link

artemv commented Dec 5, 2013

Btw code example can be simpler:

require 'deadlock_retry'

class MyTest < ActiveRecord::Base
  after_create :deadlock_error

  def deadlock_error
    raise ActiveRecord::StatementInvalid.new("Deadlock found when trying to get lock")
  end
end

my_test = MyTest.new(:name => "Testing")

if my_test.save
  MyTest.find(my_test.id)
end

with same output : ActiveRecord::RecordNotFound: Couldn't find MyTest with ID=1

@readysetawesome
Copy link

I'm thinking about using this gem, just came across this issue. FWIW I don't see the problem when running either of the above examples in a console. The second, shorter example bails after 3 retries and raises ActiveRecord::StatementInvalid: Deadlock found when trying to get lock. The first example fails once, retries with "Deadlock detected on retry 1, restarting transaction", then finishes on a second iteration. The put is not executed until after successful 2nd iteration:

   (0.1ms)  BEGIN
  SQL (0.2ms)  INSERT INTO `my_tests` (`name`) VALUES ('Testing')
   (0.2ms)  ROLLBACK
Deadlock detected on retry 1, restarting transaction
   (0.1ms)  BEGIN
  SQL (0.1ms)  INSERT INTO `my_tests` (`name`) VALUES ('Testing')
   (0.2ms)  COMMIT
After Commit
  MyTest Load (0.3ms)  SELECT `my_tests`.* FROM `my_tests` WHERE `my_tests`.`id` = 10 LIMIT 1
 => #<MyTest id: 10, name: "Testing">

this running on rails v 3.2.16

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants