Class: LockAndCacheMsgpack::Action
- Inherits:
-
Object
- Object
- LockAndCacheMsgpack::Action
- Defined in:
- lib/lock_and_cache_msgpack/action.rb
Constant Summary collapse
- NIL =
MessagePack.pack nil
Instance Attribute Summary collapse
-
#blk ⇒ Object
readonly
Returns the value of attribute blk.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
- #digest ⇒ Object
- #expires ⇒ Object
-
#initialize(key, options, blk) ⇒ Action
constructor
A new instance of Action.
- #lock_digest ⇒ Object
- #nil_expires ⇒ Object
- #perform ⇒ Object
- #set_nil ⇒ Object
- #set_non_nil(retval) ⇒ Object
- #storage ⇒ Object
Constructor Details
#initialize(key, options, blk) ⇒ Action
8 9 10 11 12 13 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 8 def initialize(key, , blk) raise "need a block" unless blk @key = key @options = .stringify_keys @blk = blk end |
Instance Attribute Details
#blk ⇒ Object (readonly)
Returns the value of attribute blk.
6 7 8 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 6 def blk @blk end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
4 5 6 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 4 def key @key end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
5 6 7 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 5 def @options end |
Instance Method Details
#digest ⇒ Object
25 26 27 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 25 def digest @digest ||= key.digest end |
#expires ⇒ Object
15 16 17 18 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 15 def expires return @expires if defined?(@expires) @expires = .has_key?('expires') ? ['expires'].to_f.round : nil end |
#lock_digest ⇒ Object
29 30 31 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 29 def lock_digest @lock_digest ||= key.lock_digest end |
#nil_expires ⇒ Object
20 21 22 23 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 20 def nil_expires return @nil_expires if defined?(@nil_expires) @nil_expires = .has_key?('nil_expires') ? ['nil_expires'].to_f.round : nil end |
#perform ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 37 def perform max_lock_wait = .fetch 'max_lock_wait', LockAndCacheMsgpack.max_lock_wait heartbeat_expires = .fetch('heartbeat_expires', LockAndCacheMsgpack.heartbeat_expires).to_f.ceil raise "heartbeat_expires must be >= 2 seconds" unless heartbeat_expires >= 2 heartbeat_frequency = (heartbeat_expires / 2).ceil LockAndCacheMsgpack.logger.debug { "[lock_and_cache] A1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } if storage.exists(digest) and (existing = storage.get(digest)).is_a?(String) return MessagePack.unpack(existing) end LockAndCacheMsgpack.logger.debug { "[lock_and_cache] B1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } retval = nil lock_manager = LockAndCacheMsgpack.lock_manager lock_info = nil begin Timeout.timeout(max_lock_wait, TimeoutWaitingForLock) do until lock_info = lock_manager.lock(lock_digest, heartbeat_expires*1000) LockAndCacheMsgpack.logger.debug { "[lock_and_cache] C1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } sleep rand end end LockAndCacheMsgpack.logger.debug { "[lock_and_cache] D1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } if storage.exists(digest) and (existing = storage.get(digest)).is_a?(String) LockAndCacheMsgpack.logger.debug { "[lock_and_cache] E1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } retval = MessagePack.unpack existing end unless retval LockAndCacheMsgpack.logger.debug { "[lock_and_cache] F1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } done = false begin lock_extender = Thread.new do loop do LockAndCacheMsgpack.logger.debug { "[lock_and_cache] heartbeat1 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } break if done sleep heartbeat_frequency break if done LockAndCacheMsgpack.logger.debug { "[lock_and_cache] heartbeat2 #{key.debug} #{Base64.encode64(digest).strip} #{Digest::SHA1.hexdigest digest}" } lock_manager.lock lock_digest, heartbeat_expires*1000, extend: lock_info end end retval = blk.call retval.nil? ? set_nil : set_non_nil(retval) ensure done = true lock_extender.join if lock_extender.status.nil? end end ensure lock_manager.unlock lock_info if lock_info end retval end |
#set_nil ⇒ Object
90 91 92 93 94 95 96 97 98 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 90 def set_nil if nil_expires storage.setex digest, nil_expires, NIL elsif expires storage.setex digest, expires, NIL else storage.set digest, NIL end end |
#set_non_nil(retval) ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 100 def set_non_nil(retval) raise "expected not null #{retval.inspect}" if retval.nil? if expires storage.setex digest, expires, MessagePack.pack(retval) else storage.set digest, MessagePack.pack(retval) end end |
#storage ⇒ Object
33 34 35 |
# File 'lib/lock_and_cache_msgpack/action.rb', line 33 def storage @storage ||= LockAndCacheMsgpack.storage or raise("must set LockAndCacheMsgpack.storage=[Redis]") end |