Class: EM::Hiredis::PersistentLock

Inherits:
Object
  • Object
show all
Defined in:
lib/em-hiredis/persistent_lock.rb

Overview

A lock that automatically re-acquires a lock before it loses it

The lock is configured with the following two parameters

:lock_timeout - Specifies how long each lock is acquired for. Setting

this low means that locks need to be re-acquired very often, but a long
timout means that a process that fails without cleaning up after itself
(i.e. without releasing it's underlying lock) will block the anther
process from picking up this lock
replaced for a long while

:retry_interval - Specifies how frequently to retry acquiring the lock in

the case that the lock is held by another process, or there's an error
communicating with redis

Instance Method Summary collapse

Constructor Details

#initialize(redis, key, options = {}) ⇒ PersistentLock

Returns a new instance of PersistentLock.



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/em-hiredis/persistent_lock.rb', line 20

def initialize(redis, key, options = {})
  @redis, @key = redis, key
  @timeout = options[:lock_timeout] || 100
  @retry_timeout = options[:retry_interval] || 60

  @lock = EM::Hiredis::Lock.new(redis, key, @timeout)
  @locked = false
  EM.next_tick {
    @running = true
    acquire
  }
end

Instance Method Details

#acquireObject

Acquire the lock (called automatically by initialize)



34
35
36
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
# File 'lib/em-hiredis/persistent_lock.rb', line 34

def acquire
  return unless @running

  @lock.acquire.callback {
    if !@locked
      @onlocked.call if @onlocked
      @locked = true
    end

    # Re-acquire lock near the end of the period
    @extend_timer = EM.add_timer(@timeout.to_f * 2 / 3) {
      acquire()
    }
  }.errback { |e|
    if @locked
      # We were previously locked
      @onunlocked.call if @onunlocked
      @locked = false
    end

    if e.kind_of?(EM::Hiredis::RedisError)
      err = e.redis_error
      EM::Hiredis.logger.warn "Unexpected error acquiring #{@lock} #{err}"
    end

    @retry_timer = EM.add_timer(@retry_timeout) {
      acquire() unless @locked
    }
  }
end

#locked?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/em-hiredis/persistent_lock.rb', line 77

def locked?
  @locked
end

#onlocked(&blk) ⇒ Object



17
# File 'lib/em-hiredis/persistent_lock.rb', line 17

def onlocked(&blk); @onlocked = blk; self; end

#onunlocked(&blk) ⇒ Object



18
# File 'lib/em-hiredis/persistent_lock.rb', line 18

def onunlocked(&blk); @onunlocked = blk; self; end

#stopObject



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/em-hiredis/persistent_lock.rb', line 65

def stop
  @running = false
  EM.cancel_timer(@extend_timer) if @extend_timer
  EM.cancel_timer(@retry_timer) if @retry_timer
  if @locked
    # We were previously locked
    @onunlocked.call if @onunlocked
    @locked = false
  end
  @lock.unlock
end