Class: OnlineMigrations::LockRetrier
- Inherits:
-
Object
- Object
- OnlineMigrations::LockRetrier
- Defined in:
- lib/online_migrations/lock_retrier.rb
Overview
This class provides a way to automatically retry code that relies on acquiring a database lock in a way designed to minimize impact on a busy production database.
This class defines an interface for child classes to implement to configure timing configurations and the maximum number of attempts.
There are two predefined implementations (see OnlineMigrations::ConstantLockRetrier and OnlineMigrations::ExponentialLockRetrier). It is easy to provide more sophisticated implementations.
Direct Known Subclasses
ConstantLockRetrier, ExponentialLockRetrier, NullLockRetrier
Instance Method Summary collapse
-
#attempts(_command = nil, _arguments = []) ⇒ Object
Returns the number of retrying attempts.
-
#delay(_attempt, _command = nil, _arguments = []) ⇒ Object
Returns sleep time after unsuccessful lock attempt (in seconds).
-
#lock_timeout(_attempt, _command = nil, _arguments = []) ⇒ Object
Returns database lock timeout value (in seconds) for specified attempt number.
-
#with_lock_retries(connection, command = nil, *arguments, &block) ⇒ void
Executes the block with a retry mechanism that alters the ‘lock_timeout` and sleep time between attempts.
Instance Method Details
#attempts(_command = nil, _arguments = []) ⇒ Object
Returns the number of retrying attempts
56 57 58 |
# File 'lib/online_migrations/lock_retrier.rb', line 56 def attempts(_command = nil, _arguments = []) raise NotImplementedError end |
#delay(_attempt, _command = nil, _arguments = []) ⇒ Object
Returns sleep time after unsuccessful lock attempt (in seconds)
78 79 80 |
# File 'lib/online_migrations/lock_retrier.rb', line 78 def delay(_attempt, _command = nil, _arguments = []) raise NotImplementedError end |
#lock_timeout(_attempt, _command = nil, _arguments = []) ⇒ Object
Returns database lock timeout value (in seconds) for specified attempt number
68 |
# File 'lib/online_migrations/lock_retrier.rb', line 68 def lock_timeout(_attempt, _command = nil, _arguments = []); end |
#with_lock_retries(connection, command = nil, *arguments, &block) ⇒ void
This method returns an undefined value.
Executes the block with a retry mechanism that alters the ‘lock_timeout` and sleep time between attempts.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/online_migrations/lock_retrier.rb', line 93 def with_lock_retries(connection, command = nil, *arguments, &block) return yield if lock_retries_disabled? current_attempt = 0 begin current_attempt += 1 current_lock_timeout = lock_timeout(current_attempt, command, arguments) if current_lock_timeout with_lock_timeout(connection, current_lock_timeout.in_milliseconds, &block) else yield end rescue ActiveRecord::LockWaitTimeout, ActiveRecord::Deadlocked => e if current_attempt <= attempts(command, arguments) current_delay = delay(current_attempt, command, arguments) problem = e.is_a?(ActiveRecord::Deadlocked) ? "Deadlock detected." : "Lock timeout." Utils.say("#{problem} Retrying in #{current_delay} seconds...") sleep(current_delay) retry end raise end end |