Class: SimpleMutex::Mutex
- Inherits:
-
Object
- Object
- SimpleMutex::Mutex
- Defined in:
- lib/simple_mutex/mutex.rb
Constant Summary collapse
- DEFAULT_EXPIRES_IN =
1 hour
60 * 60
- ERR_MSGS =
{ unlock: { unknown: lambda do |lock_key| "something when wrong when deleting lock key <#{lock_key}>." end, key_not_found: lambda do |lock_key| "lock not found for lock key <#{lock_key}>." end, signature_mismatch: lambda do |lock_key| "signature mismatch for lock key <#{lock_key}>." end, }.freeze, lock: { basic: lambda do |lock_key| "failed to acquire lock <#{lock_key}>." end, }.freeze, }.freeze
- BaseError =
Class.new(::StandardError) do attr_reader :lock_key def initialize(msg, lock_key) @lock_key = lock_key super(msg) end end
- LockError =
Class.new(BaseError)
- UnlockError =
Class.new(BaseError)
Class Attribute Summary collapse
-
.redis ⇒ Object
Returns the value of attribute redis.
Instance Attribute Summary collapse
-
#expires_in ⇒ Object
readonly
Returns the value of attribute expires_in.
-
#lock_key ⇒ Object
readonly
Returns the value of attribute lock_key.
-
#payload ⇒ Object
readonly
Returns the value of attribute payload.
-
#signature ⇒ Object
readonly
Returns the value of attribute signature.
Class Method Summary collapse
- .lock(lock_key, **options) ⇒ Object
- .lock!(lock_key, **options) ⇒ Object
- .raise_error(error_class, msg_template, lock_key) ⇒ Object
- .signature_valid?(raw_data, signature) ⇒ Boolean
- .unlock(lock_key, signature: nil, force: false) ⇒ Object
- .unlock!(lock_key, signature: nil, force: false) ⇒ Object
- .with_lock(lock_key, **options, &block) ⇒ Object
Instance Method Summary collapse
-
#initialize(lock_key, expires_in: DEFAULT_EXPIRES_IN, signature: SecureRandom.uuid, payload: nil) ⇒ Mutex
constructor
A new instance of Mutex.
- #lock ⇒ Object
- #lock! ⇒ Object
- #lock_obtained? ⇒ Boolean
- #unlock(force: false) ⇒ Object
- #unlock!(force: false) ⇒ Object
- #with_lock ⇒ Object
Constructor Details
#initialize(lock_key, expires_in: DEFAULT_EXPIRES_IN, signature: SecureRandom.uuid, payload: nil) ⇒ Mutex
Returns a new instance of Mutex.
115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/simple_mutex/mutex.rb', line 115 def initialize(lock_key, expires_in: DEFAULT_EXPIRES_IN, signature: SecureRandom.uuid, payload: nil) ::SimpleMutex.redis_check! self.lock_key = lock_key self.expires_in = expires_in.to_i self.signature = signature self.payload = payload end |
Class Attribute Details
.redis ⇒ Object
Returns the value of attribute redis.
42 43 44 |
# File 'lib/simple_mutex/mutex.rb', line 42 def redis @redis end |
Instance Attribute Details
#expires_in ⇒ Object
Returns the value of attribute expires_in.
113 114 115 |
# File 'lib/simple_mutex/mutex.rb', line 113 def expires_in @expires_in end |
#lock_key ⇒ Object
Returns the value of attribute lock_key.
113 114 115 |
# File 'lib/simple_mutex/mutex.rb', line 113 def lock_key @lock_key end |
#payload ⇒ Object
Returns the value of attribute payload.
113 114 115 |
# File 'lib/simple_mutex/mutex.rb', line 113 def payload @payload end |
#signature ⇒ Object
Returns the value of attribute signature.
113 114 115 |
# File 'lib/simple_mutex/mutex.rb', line 113 def signature @signature end |
Class Method Details
.lock(lock_key, **options) ⇒ Object
44 45 46 |
# File 'lib/simple_mutex/mutex.rb', line 44 def lock(lock_key, **) new(lock_key, **).lock end |
.lock!(lock_key, **options) ⇒ Object
48 49 50 |
# File 'lib/simple_mutex/mutex.rb', line 48 def lock!(lock_key, **) new(lock_key, **).lock! end |
.raise_error(error_class, msg_template, lock_key) ⇒ Object
97 98 99 100 101 102 |
# File 'lib/simple_mutex/mutex.rb', line 97 def raise_error(error_class, msg_template, lock_key) template_base = error_class.name.split("::").last.gsub("Error", "").downcase.to_sym error_msg = ERR_MSGS[template_base][msg_template].call(lock_key) raise(error_class.new(error_msg, lock_key)) end |
.signature_valid?(raw_data, signature) ⇒ Boolean
104 105 106 107 108 109 110 |
# File 'lib/simple_mutex/mutex.rb', line 104 def signature_valid?(raw_data, signature) return false if raw_data.nil? JSON.parse(raw_data)["signature"] == signature rescue JSON::ParseError, TypeError false end |
.unlock(lock_key, signature: nil, force: false) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/simple_mutex/mutex.rb', line 52 def unlock(lock_key, signature: nil, force: false) ::SimpleMutex.redis_check! redis = ::SimpleMutex.redis redis.watch(lock_key) do raw_data = redis.get(lock_key) if raw_data && (force || signature_valid?(raw_data, signature)) redis.multi { |multi| multi.del(lock_key) }.first.positive? else redis.unwatch false end end end |
.unlock!(lock_key, signature: nil, force: false) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/simple_mutex/mutex.rb', line 69 def unlock!(lock_key, signature: nil, force: false) ::SimpleMutex.redis_check! redis = ::SimpleMutex.redis redis.watch(lock_key) do raw_data = redis.get(lock_key) begin raise_error(UnlockError, :key_not_found, lock_key) unless raw_data unless force || signature_valid?(raw_data, signature) raise_error(UnlockError, :signature_mismatch, lock_key) end success = redis.multi { |multi| multi.del(lock_key) }.first.positive? raise_error(UnlockError, :unknown, lock_key) unless success ensure redis.unwatch end end end |
.with_lock(lock_key, **options, &block) ⇒ Object
93 94 95 |
# File 'lib/simple_mutex/mutex.rb', line 93 def with_lock(lock_key, **, &block) new(lock_key, **).with_lock(&block) end |
Instance Method Details
#lock ⇒ Object
127 128 129 |
# File 'lib/simple_mutex/mutex.rb', line 127 def lock !!redis.set(lock_key, generate_data, nx: true, ex: expires_in) end |
#lock! ⇒ Object
149 150 151 |
# File 'lib/simple_mutex/mutex.rb', line 149 def lock! lock or raise_error(LockError, :basic) end |
#lock_obtained? ⇒ Boolean
145 146 147 |
# File 'lib/simple_mutex/mutex.rb', line 145 def lock_obtained? self.class.signature_valid?(redis.get(lock_key), signature) end |
#unlock(force: false) ⇒ Object
131 132 133 |
# File 'lib/simple_mutex/mutex.rb', line 131 def unlock(force: false) self.class.unlock(lock_key, signature: signature, force: force) end |
#unlock!(force: false) ⇒ Object
153 154 155 |
# File 'lib/simple_mutex/mutex.rb', line 153 def unlock!(force: false) self.class.unlock!(lock_key, signature: signature, force: force) end |
#with_lock ⇒ Object
135 136 137 138 139 140 141 142 143 |
# File 'lib/simple_mutex/mutex.rb', line 135 def with_lock lock! begin yield ensure unlock end end |