class WithAdvisoryLock::Base
Attributes
connection[R]
lock_name[R]
timeout_seconds[R]
transaction[R]
Public Class Methods
lock_stack()
click to toggle source
# File lib/with_advisory_lock/base.rb, line 43 def self.lock_stack # access doesn't need to be synchronized as it is only accessed by the current thread. Thread.current[:with_advisory_lock_stack] ||= [] end
new(connection, lock_name, options)
click to toggle source
# File lib/with_advisory_lock/base.rb, line 24 def initialize(connection, lock_name, options) options = { timeout_seconds: options } unless options.respond_to?(:fetch) options.assert_valid_keys :timeout_seconds, :shared, :transaction @connection = connection @lock_name = lock_name @timeout_seconds = options.fetch(:timeout_seconds, nil) @shared = options.fetch(:shared, false) @transaction = options.fetch(:transaction, false) end
Public Instance Methods
already_locked?()
click to toggle source
# File lib/with_advisory_lock/base.rb, line 49 def already_locked? lock_stack.include? lock_stack_item end
lock_stack_item()
click to toggle source
# File lib/with_advisory_lock/base.rb, line 39 def lock_stack_item @lock_stack_item ||= LockStackItem.new(lock_str, shared) end
lock_str()
click to toggle source
# File lib/with_advisory_lock/base.rb, line 35 def lock_str @lock_str ||= "#{ENV['WITH_ADVISORY_LOCK_PREFIX']}#{lock_name}" end
stable_hashcode(input)
click to toggle source
# File lib/with_advisory_lock/base.rb, line 63 def stable_hashcode(input) if input.is_a? Numeric input.to_i else # Ruby MRI's String#hash is randomly seeded as of Ruby 1.9 so # make sure we use a deterministic hash. Zlib.crc32(input.to_s) end end
unique_column_name()
click to toggle source
Prevent AR from caching results improperly
# File lib/with_advisory_lock/base.rb, line 100 def unique_column_name "t#{SecureRandom.hex}" end
with_advisory_lock_if_needed() { || ... }
click to toggle source
# File lib/with_advisory_lock/base.rb, line 53 def with_advisory_lock_if_needed(&block) if already_locked? Result.new(true, yield) elsif timeout_seconds == 0 yield_with_lock(&block) else yield_with_lock_and_timeout(&block) end end
yield_with_lock() { |: nil| ... }
click to toggle source
# File lib/with_advisory_lock/base.rb, line 84 def yield_with_lock if try_lock begin lock_stack.push(lock_stack_item) result = block_given? ? yield : nil Result.new(true, result) ensure lock_stack.pop release_lock end else FAILED_TO_LOCK end end
yield_with_lock_and_timeout(&block)
click to toggle source
# File lib/with_advisory_lock/base.rb, line 73 def yield_with_lock_and_timeout(&block) give_up_at = Time.now + @timeout_seconds if @timeout_seconds while @timeout_seconds.nil? || Time.now < give_up_at r = yield_with_lock(&block) return r if r.lock_was_acquired? # Randomizing sleep time may help reduce contention. sleep(rand(0.05..0.15)) end FAILED_TO_LOCK end