class SidekiqUniqueJobs::Lock::BaseLock

@author Mikael Henriksson <mikael@zoolutions.se>
@abstract
Abstract base class for locks

def self.validate_options(options = {})

Returns:
  • (void) -

Parameters:
  • options (Hash) -- the sidekiq_options given to the worker
def self.validate_options(options = {})
  Validator.validate(options)
end

def call_strategy

def call_strategy
  @attempt += 1
  client_strategy.call { lock if replace? }
end

def callback_safely

def callback_safely
  callback&.call
  item[JID]
rescue StandardError
  log_warn("unlocked successfully but the #after_unlock callback failed!")
  raise
end

def client_strategy

def client_strategy
  @client_strategy ||=
    OnConflict.find_strategy(lock_config.on_client_conflict).new(item, redis_pool)
end

def delete

Deletes the job from redis if it is locked.
def delete
  locksmith.delete # Soft delete (don't forcefully remove when expiration is set)
end

def delete!

This is good for jobs when a previous lock was not unlocked
Forcefully deletes the job from redis.
def delete!
  locksmith.delete! # Force delete the lock
end

def execute

Raises:
  • (NotImplementedError) - needs to be implemented in child class
def execute
  raise NotImplementedError, "##{__method__} needs to be implemented in #{self.class}"
end

def initialize(item, callback, redis_pool = nil)

Parameters:
  • redis_pool (Sidekiq::RedisConnection, ConnectionPool) -- the redis connection
  • callback (Proc) -- the callback to use after unlock
  • item (Hash) -- the Sidekiq job hash
def initialize(item, callback, redis_pool = nil)
  @item       = item
  @callback   = callback
  @redis_pool = redis_pool
  @attempt    = 0
  prepare_item # Used to ease testing
  @lock_config = LockConfig.new(item)
end

def lock(&block)

Other tags:
    Yield: - to the caller when given a block

Returns:
  • (String, nil) - the locked jid when properly locked, else nil.

Other tags:
    Note: - Will call a conflict strategy if lock can't be achieved.
def lock(&block)
  return call_strategy unless (locked_token = locksmith.lock(&block))
  locked_token
end

def locked?

Returns:
  • (false) - when this jid has not locked the job
  • (true) - when this jid has locked the job
def locked?
  locksmith.locked?
end

def locksmith

Returns:
  • (SidekiqUniqueJobs::Locksmith) - the locksmith for this sidekiq job

Other tags:
    Api: - private
def locksmith
  @locksmith ||= SidekiqUniqueJobs::Locksmith.new(item, redis_pool)
end

def prepare_item

def prepare_item
  return if item.key?(LOCK_DIGEST)
  # The below should only be done to ease testing
  # in production this will be done by the middleware
  SidekiqUniqueJobs::Job.prepare(item)
end

def replace?

def replace?
  client_strategy.replace? && attempt < 2
end

def server_strategy

def server_strategy
  @server_strategy ||=
    OnConflict.find_strategy(lock_config.on_server_conflict).new(item, redis_pool)
end

def unlock

Returns:
  • (false) - when unsuccessful
  • (String) - sidekiq job id when successful
def unlock
  locksmith.unlock # Only signal to release the lock
end

def unlock_with_callback

def unlock_with_callback
  return log_warn("might need to be unlocked manually") unless unlock
  callback_safely
  item[JID]
end