Class: WithAdvisoryLock::Base
- Inherits:
-
Object
- Object
- WithAdvisoryLock::Base
- Defined in:
- lib/with_advisory_lock/base.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
-
#lock_name ⇒ Object
readonly
Returns the value of attribute lock_name.
-
#timeout_seconds ⇒ Object
readonly
Returns the value of attribute timeout_seconds.
Class Method Summary collapse
Instance Method Summary collapse
- #already_locked? ⇒ Boolean
-
#initialize(connection, lock_name, timeout_seconds) ⇒ Base
constructor
A new instance of Base.
- #lock_str ⇒ Object
- #stable_hashcode(input) ⇒ Object
-
#unique_column_name ⇒ Object
Prevent AR from caching results improperly.
- #with_advisory_lock_if_needed(&block) ⇒ Object
- #yield_with_lock ⇒ Object
- #yield_with_lock_and_timeout(&block) ⇒ Object
Constructor Details
#initialize(connection, lock_name, timeout_seconds) ⇒ Base
Returns a new instance of Base.
22 23 24 25 26 |
# File 'lib/with_advisory_lock/base.rb', line 22 def initialize(connection, lock_name, timeout_seconds) @connection = connection @lock_name = lock_name @timeout_seconds = timeout_seconds end |
Instance Attribute Details
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
20 21 22 |
# File 'lib/with_advisory_lock/base.rb', line 20 def connection @connection end |
#lock_name ⇒ Object (readonly)
Returns the value of attribute lock_name.
20 21 22 |
# File 'lib/with_advisory_lock/base.rb', line 20 def lock_name @lock_name end |
#timeout_seconds ⇒ Object (readonly)
Returns the value of attribute timeout_seconds.
20 21 22 |
# File 'lib/with_advisory_lock/base.rb', line 20 def timeout_seconds @timeout_seconds end |
Class Method Details
.lock_stack ⇒ Object
32 33 34 35 |
# File 'lib/with_advisory_lock/base.rb', line 32 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 |
Instance Method Details
#already_locked? ⇒ Boolean
38 39 40 |
# File 'lib/with_advisory_lock/base.rb', line 38 def already_locked? lock_stack.include? lock_str end |
#lock_str ⇒ Object
28 29 30 |
# File 'lib/with_advisory_lock/base.rb', line 28 def lock_str @lock_str ||= "#{ENV['WITH_ADVISORY_LOCK_PREFIX'].to_s}#{lock_name.to_s}" end |
#stable_hashcode(input) ⇒ Object
52 53 54 55 56 57 58 59 60 |
# File 'lib/with_advisory_lock/base.rb', line 52 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 ⇒ Object
Prevent AR from caching results improperly
89 90 91 |
# File 'lib/with_advisory_lock/base.rb', line 89 def unique_column_name "t#{SecureRandom.hex}" end |
#with_advisory_lock_if_needed(&block) ⇒ Object
42 43 44 45 46 47 48 49 50 |
# File 'lib/with_advisory_lock/base.rb', line 42 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 ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/with_advisory_lock/base.rb', line 73 def yield_with_lock if try_lock begin lock_stack.push(lock_str) 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) ⇒ Object
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/with_advisory_lock/base.rb', line 62 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 do 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 |