module DBLock::Locking

Public Instance Methods

with_lock(name, timeout = 0) { || ... } click to toggle source
# File lib/db_lock/locking.rb, line 5
def with_lock(name, timeout = 0)
  timeout = timeout.to_f # catches nil
  timeout = 0 if timeout.negative?

  raise ArgumentError, "Invalid lock name: #{name.inspect}" if name.empty?
  raise AlreadyLocked, 'Already lock in progress' if locked?

  name = generate_lock_name(name)

  if Adapter.lock(name, timeout)
    @locked = true
    yield
  else
    raise AlreadyLocked, "Unable to obtain lock '#{name}' within #{timeout} seconds" unless locked?
  end
ensure
  Adapter.release(name) if locked?
  @locked = false
end

Private Instance Methods

generate_lock_name(name) click to toggle source
# File lib/db_lock/locking.rb, line 31
def generate_lock_name(name)
  name = "#{rails_app_name}.#{Rails.env}#{name}" if name[0] == '.' && defined? Rails
  # reduce lock names of > 64 chars in size
  # MySQL 5.7 only supports 64 chars max, there might be similar limitations elsewhere
  name = "#{name.chars.first(15).join}-#{Digest::MD5.hexdigest(name)}-#{name.chars.last(15).join}" if name.length > 64
  name
end
locked?() click to toggle source
# File lib/db_lock/locking.rb, line 27
def locked?
  @locked ||= false
end
rails_app_name() click to toggle source
# File lib/db_lock/locking.rb, line 39
def rails_app_name
  if Gem::Version.new(Rails.version) >= Gem::Version.new('6.0.0')
    Rails.application.class.module_parent_name
  else
    Rails.application.class.parent_name
  end
end