Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
deadlock_retry changes

== v2.2.2

* Retry on ActiveRecord::Deadlocked, in addition to ActiveRecord::LockWaitTimeout

== v2.1.0

* update for rails 5 keyword args
Expand Down
47 changes: 34 additions & 13 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,39 +1,60 @@
PATH
remote: .
specs:
deadlock_retry (1.2.0)
deadlock_retry (2.2.2)

GEM
remote: http://rubygems.org/
specs:
activemodel (6.1.7.2)
activesupport (= 6.1.7.2)
activerecord (6.1.7.2)
activemodel (= 6.1.7.2)
activesupport (= 6.1.7.2)
activesupport (6.1.7.2)
activemodel (7.1.5.1)
activesupport (= 7.1.5.1)
activerecord (7.1.5.1)
activemodel (= 7.1.5.1)
activesupport (= 7.1.5.1)
timeout (>= 0.4.0)
activesupport (7.1.5.1)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
mutex_m
securerandom (>= 0.3)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
concurrent-ruby (1.2.0)
i18n (1.12.0)
base64 (0.2.0)
benchmark (0.4.0)
bigdecimal (3.1.9)
byebug (11.1.3)
concurrent-ruby (1.3.5)
connection_pool (2.5.0)
drb (2.2.1)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
minitest (5.17.0)
logger (1.6.6)
minitest (5.25.5)
minitest-color (0.0.2)
minitest (~> 5)
mocha (2.0.2)
ruby2_keywords (>= 0.0.5)
mutex_m (0.3.0)
ruby2_keywords (0.0.5)
securerandom (0.4.1)
timeout (0.4.3)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
zeitwerk (2.6.6)

PLATFORMS
aarch64-linux

DEPENDENCIES
activerecord (~> 6.0)
activerecord (~> 7.1.5.1)
byebug
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only reason we use byebug at all is because it works better with our selenium testing. If I could figure out how to make the standard debugger work well, we'd ditch it.

deadlock_retry!
minitest-color
mocha

BUNDLED WITH
Expand Down
40 changes: 40 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,43 @@ Add it to your Rails application by installing the gem:
and including a reference to it in your application's Gemfile:

gem 'deadlock_retry'


## Installation

```
cd ~/dev
git clone git@github.com:cdd/deadlock_retry.git
cd deadlock_retry

# build the docker container
make

# manually update the Gemfile.lock
make shell
bundle install
exit

# run the the test suite
make test
```

## Development

```
make guard
```

## Bumping the version

1. Bump the version number in `lib/deadlock_retry/version.rb`

2. Add an entry to `CHANGELOG.md`

3. Run the following so Gemfile.lock is updated:

```
make shell
bundle install
exit
```
2 changes: 1 addition & 1 deletion deadlock_retry.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.homepage = %q{http://github.com/mperham/deadlock_retry}
s.require_paths = ["lib"]
s.add_development_dependency 'mocha'
s.add_development_dependency 'activerecord', ENV['ACTIVERECORD_VERSION'] || ' ~>6.0'
s.add_development_dependency 'activerecord', ENV['ACTIVERECORD_VERSION'] || ' ~> 7.1.5.1'
s.add_development_dependency 'byebug'
s.add_development_dependency 'minitest-color'
end
27 changes: 19 additions & 8 deletions lib/deadlock_retry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@ def transaction(requires_new: nil, isolation: nil, joinable: true, &block)

begin
super(requires_new: requires_new, isolation: isolation, joinable: joinable, &block)
rescue ActiveRecord::LockWaitTimeout => error
raise if in_nested_transaction?
rescue ActiveRecord::LockWaitTimeout, ActiveRecord::Deadlocked => e
if in_nested_transaction?
logger.info { "CDD_DEADLOCK_RETRY_NESTED_TRANSACTION Deadlock detected in a nested transaction, not retrying. [#{e.class}]" }
raise
end

if retry_count >= MAXIMUM_RETRIES_ON_DEADLOCK
logger.info { "CDD_DEADLOCK_RETRY_MAXIMUM_RETRIES_EXCEEDED Deadlock detected and maximum retries exceeded (maximum: #{MAXIMUM_RETRIES_ON_DEADLOCK}), not retrying. [#{e.class}]" }
raise
end

raise if retry_count >= MAXIMUM_RETRIES_ON_DEADLOCK
retry_count += 1
logger.info { "Deadlock detected on retry #{retry_count}, restarting transaction" }
pause_seconds = exponential_pause_seconds(retry_count)
logger.info { "CDD_DEADLOCK_RETRY_RETRYING_TRANSACTION Deadlock detected on retry #{retry_count}, retrying transaction in #{pause_seconds} seconds. [#{e.class}]" }
log_innodb_status if DeadlockRetry.innodb_status_cmd
exponential_pause(retry_count)
sleep_pause(pause_seconds)
retry
end
end
Expand All @@ -28,11 +36,14 @@ def transaction(requires_new: nil, isolation: nil, joinable: true, &block)

WAIT_TIMES = [0, 1, 2, 4, 8, 16, 32]

def exponential_pause(count)
sec = WAIT_TIMES[count-1] || 32
def exponential_pause_seconds(count)
# sleep 0, 1, 2, 4, ... seconds up to the MAXIMUM_RETRIES.
# Cap the pause time at 32 seconds.
sleep(sec) if sec != 0
WAIT_TIMES[count-1] || 32
end

def sleep_pause(seconds)
sleep(seconds) if seconds != 0
end

def in_nested_transaction?
Expand Down
2 changes: 1 addition & 1 deletion lib/deadlock_retry/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module DeadlockRetry
VERSION = '2.1.0'
VERSION = '2.2.2'
end
Loading