Module: Redis::LockKey

Included in:
Redis
Defined in:
lib/lock_key/lock_key.rb

Defined Under Namespace

Classes: LockAttemptTimeout

Constant Summary collapse

VALUE_DELIMETER =
"-:-:-"
@@defaults =
{
  :wait_for => 60,    # seconds to wait to obtain a lock
  :expire   => 60,    # seconds till key expires
  :raise    => true,  # raise a LockKey::LockAttemptTimeout if the lock cannot be obtained
  :sleep_for => 0.5
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.defaultsObject



33
# File 'lib/lock_key/lock_key.rb', line 33

def self.defaults; @@defaults; end

.defaults=(defaults) ⇒ Object



32
# File 'lib/lock_key/lock_key.rb', line 32

def self.defaults=(defaults); @@defaults = @@defaults.merge(defaults); end

.lock_key_idObject

The lock key id for this thread. Uses uuid so that concurrency is not an issue with respect to keys



37
# File 'lib/lock_key/lock_key.rb', line 37

def self.lock_key_id; Thread.current[:lock_key_id] ||= UUID_GEN.call; end

Instance Method Details

#kill_lock!(key) ⇒ Object



68
69
70
# File 'lib/lock_key/lock_key.rb', line 68

def kill_lock!(key)
  _redis_.del(lock_key_for(key))
end

#lock_key(key, opts = {}) ⇒ Object

Locks a key in redis options are same as default. If a block is given the lock is automatically released If no block is given, be sure to unlock the key when you’re done.

Note: Concurrency is hard, and deadlock is always a danger. Don’t do any more than is absolutely needed inside the lock so that the lock exists for the shortest time possible.

Parameters:

  • key

    String The Redis key to lock

  • opts (defaults to: {})

    Hash The options hash for the lock

Options Hash (opts):

  • :wait_for (Object)

    Numeric The time to wait for to obtain a lock

  • :expire (Object)

    Numeric The time before the lock expires

  • :raise (Object)

    Causes a raise if a lock cannot be obtained

  • :sleep_for (Object)

    the time to sleep between checks



53
54
55
56
57
58
59
60
61
62
# File 'lib/lock_key/lock_key.rb', line 53

def lock_key(key, opts={})
  is_block, got_lock = block_given?, false
  options = LockKey.defaults.merge(opts)

  got_lock = obtain_lock(key, options)
  yield if is_block && got_lock
  got_lock
ensure
  unlock_key(key, options) if is_block && got_lock
end

#locked_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/lock_key/lock_key.rb', line 64

def locked_key?(key)
  !!fetch(key)
end

#unlock_key(key, opts = {}) ⇒ Object

Manually unlocks a key.

This method is mainly intended for applications where the lock is obtained in one thread and then passed to another thread to be released. If you are obtaining and releasing a lock in the same thread, you should prefer the block form of lock_key over this method.

Examples:

# Unlock the key if this thread owns it.
redis.lock_key "foo"
# do stuff
redis.unlock_key "foo"
# Unlock the key in a multithreaded env
key_value = redis.lock_key "foo"
Thread.new do
  # do stuff
  redis.unlock_key "foo", :key => key_value
end

Parameters:

  • key

    String The Redis key to unlock

  • opts (defaults to: {})

    Hash An options hash

Options Hash (opts):

  • :key (Object)

    The value of the key to unlock.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/lock_key/lock_key.rb', line 96

def unlock_key(key, opts={})
  held_value = opts[:key]
  value = fetch(key)
  return true unless value
  if value == held_value || i_have_the_lock?(value)
    kill_lock!(key)
    true
  else
    false
  end
end