class Redis::Helper::Lock

ロックの管理クラス

Constants

DEFAULT_TIMEOUT

ロック取得のタイムアウト(sec)

Public Class Methods

new(redis, lock_key, options = {}) click to toggle source

@param [Redis] redis redisのインスタンス @param [String] lock_key ロックを保持するキー @param [Hash] options オプション @option options [Integer] timeout タイムアウト時間(sec)

# File lib/redis/helper/lock.rb, line 12
def initialize(redis, lock_key, options = {})
  @redis        = redis
  @lock_key     = lock_key
  @options      = options
  @locked_by_self = false
end

Public Instance Methods

lock() { || ... } click to toggle source

ロックをかけてブロック内の処理を実行 @yield ロック中に実行する処理のブロック

# File lib/redis/helper/lock.rb, line 21
def lock
  raise ArgumentError unless block_given?
  if Thread.current[@lock_key]
    yield
  else
    begin
      Thread.current[@lock_key] = true
      try_lock!(Time.now.to_f)
      yield
    ensure
      unlock
      Thread.current[@lock_key] = nil
    end
  end
end
unlock() click to toggle source

ロックを開放 (自身でかけたロックの場合のみ開放する)

# File lib/redis/helper/lock.rb, line 39
def unlock
  if @locked_by_self
    @redis.del(@lock_key)
    @locked_by_self = false
  end
end

Private Instance Methods

expiration() click to toggle source

ロックの有効期限 @return [Float] 有効期限(UNIXタイムスタンプ)

# File lib/redis/helper/lock.rb, line 74
def expiration
  (Time.now + timeout).to_f
end
timeout() click to toggle source

ロック取得と取得したロックがタイムアウトするまでの時間 @return [Float] タイムアウト時間(sec)

# File lib/redis/helper/lock.rb, line 80
def timeout
  @timeout ||= (@options[:timeout] || DEFAULT_TIMEOUT).to_f
end
try_lock!(start) click to toggle source

ロックを取得 @param [Float] start ロック取得開始時間のUNIXタイムスタンプ @yield ロック中に実行する処理のブロック @raise [Redis::Helper::LockTimeout] ロックの取得に失敗した

# File lib/redis/helper/lock.rb, line 51
def try_lock!(start)
  loop do
    if @redis.setnx(@lock_key, expiration)
      @locked_by_self = true
      break
    end

    current = @redis.get(@lock_key).to_f
    if current < Time.now.to_f
      old = @redis.getset(@lock_key, expiration).to_f
      if old < Time.now.to_f
        @locked_by_self = true
        break
      end
    end

    Kernel.sleep(0.1)
    raise ::Redis::Helper::LockTimeout if (Time.now.to_f - start) > timeout
  end
end