Module: ExclusiveLeaseGuard

Overview

Concern that helps with getting an exclusive lease for running a block of code.

‘#try_obtain_lease` takes a block which will be run if it was able to obtain the lease. Implement `#lease_timeout` to configure the timeout for the exclusive lease.

Optionally override ‘#lease_key` to set the lease key, it defaults to the class name with underscores.

Optionally override ‘#lease_release?` to prevent the job to be re-executed more often than LEASE_TIMEOUT.

Instance Method Summary collapse

Instance Method Details

#exclusive_leaseObject



35
36
37
# File 'app/services/concerns/exclusive_lease_guard.rb', line 35

def exclusive_lease
  @lease ||= Gitlab::ExclusiveLease.new(lease_key, timeout: lease_timeout)
end

#lease_keyObject



39
40
41
# File 'app/services/concerns/exclusive_lease_guard.rb', line 39

def lease_key
  @lease_key ||= self.class.name.underscore
end

#lease_release?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'app/services/concerns/exclusive_lease_guard.rb', line 48

def lease_release?
  true
end

#lease_taken_log_levelObject



76
77
78
# File 'app/services/concerns/exclusive_lease_guard.rb', line 76

def lease_taken_log_level
  :error
end

#lease_taken_messageObject



72
73
74
# File 'app/services/concerns/exclusive_lease_guard.rb', line 72

def lease_taken_message
  "Cannot obtain an exclusive lease. There must be another instance already in execution."
end

#lease_timeoutObject

Raises:

  • (NotImplementedError)


43
44
45
46
# File 'app/services/concerns/exclusive_lease_guard.rb', line 43

def lease_timeout
  raise NotImplementedError,
    "#{self.class.name} does not implement #{__method__}"
end

#log_lease_takenObject



60
61
62
63
64
65
66
67
68
69
70
# File 'app/services/concerns/exclusive_lease_guard.rb', line 60

def log_lease_taken
  logger = Gitlab::AppJsonLogger
  args = { message: lease_taken_message, lease_key: lease_key, class_name: self.class.name, lease_timeout: lease_timeout }

  case lease_taken_log_level
  when :debug then logger.debug(args)
  when :info  then logger.info(args)
  when :warn  then logger.warn(args)
  else             logger.error(args)
  end
end

#release_lease(uuid) ⇒ Object



52
53
54
# File 'app/services/concerns/exclusive_lease_guard.rb', line 52

def release_lease(uuid)
  Gitlab::ExclusiveLease.cancel(lease_key, uuid)
end

#renew_lease!Object



56
57
58
# File 'app/services/concerns/exclusive_lease_guard.rb', line 56

def renew_lease!
  exclusive_lease.renew
end

#try_obtain_leaseObject



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'app/services/concerns/exclusive_lease_guard.rb', line 20

def try_obtain_lease
  lease = exclusive_lease.try_obtain

  unless lease
    log_lease_taken
    return
  end

  begin
    yield lease
  ensure
    release_lease(lease) if lease_release?
  end
end