class RedisLocker

Attributes

key[R]
running[R]
time_limit[R]
timestamp[R]
timestamp_key[R]

Public Class Methods

logger() click to toggle source
# File lib/redis-locker.rb, line 98
def self.logger
  @logger ||= Logger.new(STDOUT)
end
logger=(logger) click to toggle source
# File lib/redis-locker.rb, line 102
def self.logger=(logger)
  @logger = logger
end
new(key, time_limit = 5) click to toggle source

@param [String] key @param [Integer] time_limit Number of seconds when locker will be expired

# File lib/redis-locker.rb, line 11
def initialize(key, time_limit = 5)
  @key = key
  @time_limit = time_limit
  @running = false
end
redis() click to toggle source
# File lib/redis-locker.rb, line 106
def self.redis
  @redis
end
redis=(adapter) click to toggle source
# File lib/redis-locker.rb, line 110
def self.redis=(adapter)
  @redis = adapter
end

Public Instance Methods

current?() click to toggle source

@return [true, false]

# File lib/redis-locker.rb, line 18
def current?
  concurrent_timestamp == timestamp
end
enter_queue() click to toggle source

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

# 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_queue() click to toggle source

Clears all data from queue related to this block

# 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_ready() click to toggle source

Returns true if block is ready to run @return [true, false]

# 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?() click to toggle source
# 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
redis() click to toggle source
# File lib/redis-locker.rb, line 61
def redis
  self.class.redis
end
run(&block) click to toggle source

Waits for the queue and evaluates the block

# 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) click to toggle source

@param [Integer] time_limit Number of seconds after we throw a Timeout::Error @param [true, false] clear_queue_on_timeout @raise [Timeout::Error]

# 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?() click to toggle source
# File lib/redis-locker.rb, line 94
def running?
  @running
end

Protected Instance Methods

generate_timestamp() click to toggle source

@return [Float]

# File lib/redis-locker.rb, line 117
def generate_timestamp
  Time.now.to_f
end

Private Instance Methods

clear_queue() click to toggle source
# File lib/redis-locker.rb, line 123
def clear_queue
  redis.del key
end
concurrent_timestamp() click to toggle source

@return [String]

# File lib/redis-locker.rb, line 128
def concurrent_timestamp
  @concurrent_timestamp ||= fetch_concurrent_timestamp
end
fetch_concurrent_timestamp() click to toggle source

Fetches next concurrent thread ID from the queue

# File lib/redis-locker.rb, line 133
def fetch_concurrent_timestamp
  redis.lindex(key, 0)
end
generate_timestamp_key(timestamp = @timestamp) click to toggle source

@param [String, Float] timestamp

# File lib/redis-locker.rb, line 138
def generate_timestamp_key(timestamp = @timestamp)
  "Locker::__key_#{timestamp}"
end
logger() click to toggle source

@return [Logger]

# File lib/redis-locker.rb, line 143
def logger
  self.class.logger
end
make_current() click to toggle source

Replaces concurrent timestamp

# File lib/redis-locker.rb, line 148
def make_current
  redis.lrem  key, 0, timestamp
  redis.lpop  key
  redis.lpush key, timestamp
end
Also aliased as: replace_concurrent_timestamp
replace_concurrent_timestamp()
Alias for: make_current
start_queue() click to toggle source

Builds queue starting from self

# File lib/redis-locker.rb, line 156
def start_queue
  redis.lpush key, timestamp
end
timestamp=(value) click to toggle source

@param [Float] value

# File lib/redis-locker.rb, line 161
def timestamp=(value)
  @timestamp = value
  @timestamp_key = generate_timestamp_key(@timestamp)
  @timestamp
end
wait() click to toggle source

Locking itself

# File lib/redis-locker.rb, line 168
def wait
  begin
    @concurrent_timestamp = fetch_concurrent_timestamp
  end until get_ready
end