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_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_error(message, extra_args = {}) ⇒ Object


60
61
62
# File 'app/services/concerns/exclusive_lease_guard.rb', line 60

def log_error(message, extra_args = {})
  Gitlab::AppLogger.error(message)
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_error("Cannot obtain an exclusive lease for #{self.class.name}. There must be another instance already in execution.")
    return
  end

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