class MongoMutex::Mutex

Constants

DUPLICATE_KEY_ERROR
LOCKED_AT
LOCKED_BY

Public Class Methods

new(collection, lock_id, locker_id, options = {}) click to toggle source
# File lib/mongo_mutex/mutex.rb, line 7
def initialize(collection, lock_id, locker_id, options = {})
  raise ArgumentError, "String lock id required" unless lock_id.is_a?(String)
  raise ArgumentError, "String locker id required" unless locker_id.is_a?(String)
  @collection = collection
  @lock_id = lock_id
  @locker_id = locker_id
  options = options.dup
  @lock_check_period = options.delete(:lock_check_period) || 5
  @lock_retention_timeout = options.delete(:lock_retention_timeout) || 600
  @clock = options.delete(:clock) || Time
  @logger = options.delete(:logger)
  @lock_operations = options.delete(:lock_operations) || MongoOperations.new
  raise ArgumentError, "Unsupported options #{options.keys}" unless options.empty?
end

Public Instance Methods

lock() click to toggle source
# File lib/mongo_mutex/mutex.rb, line 45
def lock
  until try_lock
    sleep @lock_check_period
  end
  self
end
locked?() click to toggle source
# File lib/mongo_mutex/mutex.rb, line 40
def locked?
  lock_info = @lock_operations.lock_info(@collection, @lock_id)
  lock_info && lock_info[LOCKED_BY] && !expired?(lock_info[LOCKED_AT])
end
synchronize() { || ... } click to toggle source
# File lib/mongo_mutex/mutex.rb, line 59
def synchronize(&block)
  lock
  begin
    yield
  ensure
    unlock
  end
end
try_lock() click to toggle source
# File lib/mongo_mutex/mutex.rb, line 22
def try_lock
  previous = @lock_operations.try_lock(@collection, @lock_id, @locker_id, @clock.now, @lock_retention_timeout)
  if previous && (locked_by = previous[LOCKED_BY])
    if expired?(previous[LOCKED_AT])
      @logger.warn "Ignoring old #{@lock_id} lock by #{locked_by} since #{previous[LOCKED_AT]} was too long ago" if @logger
    else
      raise ThreadError, "mutex already locked by #{locked_by} at #{previous[LOCKED_AT]}"
    end
  end
  true
rescue Mongo::Error::OperationFailure => error
  if error.message.include?(DUPLICATE_KEY_ERROR)
    return false
  else
    raise
  end
end
unlock() click to toggle source
# File lib/mongo_mutex/mutex.rb, line 52
def unlock
  unless @lock_operations.unlock(@collection, @lock_id, @locker_id, @clock.now, @lock_retention_timeout)
    raise ThreadError, 'lock is either not locked or locked by someone else'
  end
  self
end

Private Instance Methods

expired?(time) click to toggle source
# File lib/mongo_mutex/mutex.rb, line 73
def expired?(time)
  !time || time < @clock.now - @lock_retention_timeout
end