Skip to content

Retry on "ActiveRecord::Deadlocked" errors (in addition to ActiveRecord::LockWaitTimeout)#7

Merged
tomhallett-cdd merged 9 commits intomasterfrom
bugs/182515477-ar-deadlocked-exception
Mar 21, 2025
Merged

Retry on "ActiveRecord::Deadlocked" errors (in addition to ActiveRecord::LockWaitTimeout)#7
tomhallett-cdd merged 9 commits intomasterfrom
bugs/182515477-ar-deadlocked-exception

Conversation

@tomhallett-cdd
Copy link

@tomhallett-cdd tomhallett-cdd commented Mar 20, 2025

Context: Before this PR, the gem was rescuing from ActiveRecord::LockWaitTimeout exceptions (which is good), but ActiveRecord::Deadlocked exceptions were not getting caught (which is the issue). That means when our rails app is throwing a Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction error, our deadlock_retry gem was not retrying the transaction.

Fix: After this PR, we rescue from both exceptions todo the retry logic.

Notes:

  1. The logger was improved with a few things:
  • which activerecord exception class was raised
  • when we've reached the max number of retries
  • when we're in a nested transaction, therefore the outer transaction will do the retry
  1. The exceptions we are rescuing from are the same as the ones which Rails' built-in deadlock retry use (ala Rails 7.1): https://github.com/rails/rails/blob/e9d7ca5e0b834ff2ce3d43965deac670ff8ac790/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L1079. This is good from a "we are retrying on the right things" and from a perspective that "hopefully we can cleanly migrate off this gem and onto Rails default behavior easily" in the near future.

  2. Added some README directions for install/setup.

  3. This PR should fix the dependabot security alerts:

* Adding different tests for LockWaitTimeout error vs Deadlocked error.
* Bumping gem to rails 7.1 so brakeman will pass.
* Adding error class to log message so we can see which type of
  error was thrown.
* The "innodb_status_cmd" was throwing errors in tests.
* Added Installation instructions to README
Adding logs for when the max retries has been reached and when we are in a nested transaction.

Switching the tests to non-regex matches, because they were getting more brittle with text escaping (brackets, paranthesis).
@tomhallett-cdd tomhallett-cdd requested a review from kwerle March 21, 2025 17:52
Copy link

@kwerle kwerle left a comment

Choose a reason for hiding this comment

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

Just a little color.

DeadlockRetry.class_variable_set(:@@deadlock_logger_severity, nil)
end

def print_logs(logs)
Copy link

Choose a reason for hiding this comment

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

This gem depends on rails. Should we just use Rails.logger?
Oh. Where is this method used?

Copy link
Author

Choose a reason for hiding this comment

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

It's not used directly - it's a silly utility method I used when writing the specs. As I beefed up the logs, it became a bit harder to know "what is actually getting logged", so instead of constantly tailing log/test.log, I used this print function. I also ended up committing those logs as examples in the specs ie: here, because I wanted "documentation" on here's what the logs look like. (If you look at that spec, you'll see that it asserts the "nested transaction" line should appear 8 times, but it's hard to tell what order the lines occur in the logs. Rather then spending a bunch of time to assert which log entry exists in what order, I thought this was a quick way to at least document what Peter and others can see in the logs)

Copy link
Author

Choose a reason for hiding this comment

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

I'm happy to delete it too

Copy link

Choose a reason for hiding this comment

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

Yeah - not used, ditch it.

Copy link
Author

Choose a reason for hiding this comment

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

sounds good. deleted.

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.

@tomhallett-cdd tomhallett-cdd merged commit a93efcc into master Mar 21, 2025
1 check passed
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

Successfully merging this pull request may close these issues.

2 participants