Class: RedisLocker

Inherits:
Object
  • Object
show all
Defined in:
lib/redis-locker.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, time_limit = 5) ⇒ RedisLocker

Returns a new instance of RedisLocker.

Parameters:

  • key (String)
  • time_limit (Integer) (defaults to: 5)

    Number of seconds when locker will be expired



11
12
13
14
15
# File 'lib/redis-locker.rb', line 11

def initialize(key, time_limit = 5)
  @key = key
  @time_limit = time_limit
  @running = false
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



7
8
9
# File 'lib/redis-locker.rb', line 7

def key
  @key
end

#runningObject (readonly)

Returns the value of attribute running.



7
8
9
# File 'lib/redis-locker.rb', line 7

def running
  @running
end

#time_limitObject (readonly)

Returns the value of attribute time_limit.



7
8
9
# File 'lib/redis-locker.rb', line 7

def time_limit
  @time_limit
end

#timestampObject

Returns the value of attribute timestamp.



7
8
9
# File 'lib/redis-locker.rb', line 7

def timestamp
  @timestamp
end

#timestamp_keyObject (readonly)

Returns the value of attribute timestamp_key.



7
8
9
# File 'lib/redis-locker.rb', line 7

def timestamp_key
  @timestamp_key
end

Class Method Details

.loggerObject



98
99
100
# File 'lib/redis-locker.rb', line 98

def self.logger
  @logger ||= Logger.new(STDOUT)
end

.logger=(logger) ⇒ Object



102
103
104
# File 'lib/redis-locker.rb', line 102

def self.logger=(logger)
  @logger = logger
end

.redisObject



106
107
108
# File 'lib/redis-locker.rb', line 106

def self.redis
  @redis
end

.redis=(adapter) ⇒ Object



110
111
112
# File 'lib/redis-locker.rb', line 110

def self.redis=(adapter)
  @redis = adapter
end

Instance Method Details

#current?true, false

Returns:

  • (true, false)


18
19
20
# File 'lib/redis-locker.rb', line 18

def current?
  concurrent_timestamp == timestamp
end

#enter_queueObject

Puts running block information in Redis This information will be used to place running block in a specific position of its queue



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/redis-locker.rb', line 24

def enter_queue
  logger.info("Entering #@key")
  raise 'This block is already in the queue' if running?

  @running = true
  self.timestamp = generate_timestamp.to_s

  redis.set    timestamp_key, '1'
  redis.expire timestamp_key, time_limit
  redis.rpush  key, timestamp
end

#exit_queueObject

Clears all data from queue related to this block



37
38
39
40
41
42
# File 'lib/redis-locker.rb', line 37

def exit_queue
  logger.info("Leaving #@key")
  redis.del timestamp_key
  redis.lrem key, 1, timestamp
  @running = false
end

#get_readytrue, false

Returns true if block is ready to run

Returns:

  • (true, false)


46
47
48
49
50
51
52
53
# File 'lib/redis-locker.rb', line 46

def get_ready
  if ready?
    concurrent_timestamp.nil? ? start_queue : make_current
    true
  else
    current?
  end
end

#ready?Boolean

Returns:

  • (Boolean)


55
56
57
58
59
# File 'lib/redis-locker.rb', line 55

def ready?
  concurrent_timestamp.nil? || current? ||
      (generate_timestamp - concurrent_timestamp.to_f >= time_limit) ||
        redis.get(generate_timestamp_key(concurrent_timestamp)).nil?
end

#redisObject



61
62
63
# File 'lib/redis-locker.rb', line 61

def redis
  self.class.redis
end

#run(&block) ⇒ Object

Waits for the queue and evaluates the block



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/redis-locker.rb', line 66

def run(&block)
  logger.info("Running queue #@key")

  enter_queue
  wait
  begin
    block.call
  ensure
    exit_queue
  end
end

#run!(time_limit = @time_limit, clear_queue_on_timeout = false, &block) ⇒ Object

Parameters:

  • time_limit (Integer) (defaults to: @time_limit)

    Number of seconds after we throw a Timeout::Error

  • clear_queue_on_timeout (true, false) (defaults to: false)

Raises:

  • (Timeout::Error)


81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/redis-locker.rb', line 81

def run!(time_limit = @time_limit, clear_queue_on_timeout = false, &block)
  Timeout::timeout(time_limit) { run(&block) }
rescue Timeout::Error => error
  logger.error("Failed by timeout #{time_limit}s on #@key")

  if clear_queue_on_timeout
    logger.info("Clearing queue #@key")
    clear_queue
  end

  raise error
end

#running?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/redis-locker.rb', line 94

def running?
  @running
end