Class: MysqlFramework::Scripts::LockManager
- Inherits:
-
Object
- Object
- MysqlFramework::Scripts::LockManager
- Defined in:
- lib/mysql_framework/scripts/lock_manager.rb
Instance Method Summary collapse
-
#fetch_client ⇒ Object
This method is called to retrieve a Redlock client from the pool.
-
#initialize ⇒ LockManager
constructor
A new instance of LockManager.
-
#release_lock(key:, lock:) ⇒ Object
This method is called to release a lock.
-
#request_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) ⇒ Object
This method is called to request a lock (Default 5 minutes).
-
#with_client ⇒ Object
This method is called to retrieve a Redlock client from the pool and yield it to a block.
-
#with_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) ⇒ Object
This method is called to request and release a lock around yielding to a user supplied block.
Constructor Details
#initialize ⇒ LockManager
Returns a new instance of LockManager.
8 9 10 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 8 def initialize @pool = Queue.new end |
Instance Method Details
#fetch_client ⇒ Object
This method is called to retrieve a Redlock client from the pool
65 66 67 68 69 70 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 65 def fetch_client @pool.pop(true) rescue StandardError # By not letting redlock retry we will rely on the retry that happens in this class Redlock::Client.new([redis_url], retry_jitter: retry_jitter, retry_count: 1, retry_delay: 0) end |
#release_lock(key:, lock:) ⇒ Object
This method is called to release a lock
44 45 46 47 48 49 50 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 44 def release_lock(key:, lock:) return if lock.nil? MysqlFramework.logger.info { "[#{self.class}] - Releasing lock: #{key}." } with_client { |client| client.unlock(lock) } end |
#request_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) ⇒ Object
This method is called to request a lock (Default 5 minutes)
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 13 def request_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) MysqlFramework.logger.info { "[#{self.class}] - Requesting lock: #{key}." } lock = false count = 0 loop do # request a lock lock = with_client { |client| client.lock(key, ttl) } # if lock was received break out of the loop break if lock # lock was not received so increment request count count += 1 MysqlFramework.logger.debug do "[#{self.class}] - Key is currently locked, waiting for lock: #{key} | Wait count: #{count}." end # check if lock requests have exceeded max request attempts raise "Resource is already locked. Lock key: #{key}. Max attempt exceeded." if count == max_attempts # sleep and try requesting the lock again sleep(retry_delay) end lock end |
#with_client ⇒ Object
This method is called to retrieve a Redlock client from the pool and yield it to a block
73 74 75 76 77 78 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 73 def with_client client = fetch_client yield client ensure @pool.push(client) end |
#with_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) ⇒ Object
This method is called to request and release a lock around yielding to a user supplied block
53 54 55 56 57 58 59 60 61 62 |
# File 'lib/mysql_framework/scripts/lock_manager.rb', line 53 def with_lock(key:, ttl: default_ttl, max_attempts: default_max_retries, retry_delay: default_retry_delay) raise 'Block must be specified.' unless block_given? begin lock = request_lock(key: key, ttl: ttl, max_attempts: max_attempts, retry_delay: retry_delay) yield ensure release_lock(key: key, lock: lock) end end |