Skip to content
Snippets Groups Projects
Commit cda0b7e1 authored by Jacob Vosmaer's avatar Jacob Vosmaer
Browse files

Rename ExpiringLock to ExclusiveLease

parent acd9bc02
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -246,7 +246,7 @@ class ApplicationController < ActionController::Base
 
def ldap_security_check
if current_user && current_user.requires_ldap_check?
return unless Gitlab::LDAP::Access.try_lock_user(user)
return unless Gitlab::LDAP::Access.try_lock_user(current_user)
 
unless Gitlab::LDAP::Access.allowed?(current_user)
sign_out current_user
Loading
Loading
require 'securerandom'
module Gitlab
# This class implements an 'exclusive lease'. We call it a 'lease'
# because it has a set expiry time. We call it 'exclusive' because only
# one caller may obtain a lease for a given key at a time. The
# implementation is intended to work across GitLab processes and across
# servers. It is a 'cheap' alternative to using SQL queries and updates:
# you do not need to change the SQL schema to start using
# ExclusiveLease.
class ExclusiveLease
def initialize(key, timeout)
@key, @timeout = key, timeout
end
# Try to obtain the lease. Return true on succes,
# false if the lease is already taken.
def try_obtain
!!redis.set(redis_key, redis_value, nx: true, ex: @timeout)
end
private
def redis
# Maybe someday we want to use a connection pool...
@redis ||= Redis.new(url: Gitlab::RedisConfig.url)
end
def redis_key
"gitlab:exclusive_lease:#{@key}"
end
def redis_value
@redis_value ||= SecureRandom.hex(10)
end
end
end
module Gitlab
# This class implements a distributed self-expiring lock.
#
# [2] pry(main)> l = Gitlab::ExpiringLock.new('foobar', 5)
# => #<Gitlab::ExpiringLock:0x007ffb9d7cb7f8 @key="foobar", @timeout=5>
# [3] pry(main)> l.try_lock
# => true
# [4] pry(main)> l.try_lock # Only the first try_lock succeeds
# => false
# [5] pry(main)> l.locked?
# => true
# [6] pry(main)> sleep 5
# => 5
# [7] pry(main)> l.locked? # After the timeout the lock is released
# => false
#
class ExpiringLock
def initialize(key, timeout)
@key, @timeout = key, timeout
end
# Try to obtain the lock. Return true on succes,
# false if the lock is already taken.
def try_lock
# INCR does not change the key TTL
if redis.incr(redis_key) == 1
# We won the race to insert the key into Redis
redis.expire(redis_key, @timeout)
true
else
# Somebody else won the race
false
end
end
# Check if somebody somewhere locked this key
def locked?
!!redis.get(redis_key)
end
private
def redis
# Maybe someday we want to use a connection pool...
@redis ||= Redis.new(url: Gitlab::RedisConfig.url)
end
def redis_key
"gitlab:expiring_lock:#{@key}"
end
end
end
Loading
Loading
@@ -10,7 +10,7 @@ module Gitlab
LOCK_TIMEOUT = 600
 
def self.try_lock_user(user)
Gitlab::ExpiringLock.new("user_ldap_check:#{user.id}", LOCK_TIMEOUT).try_lock
Gitlab::ExclusiveLease.new("user_ldap_check:#{user.id}", LOCK_TIMEOUT).try_obtain
end
 
def self.open(user, &block)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment