class SidekiqUniqueJobs::Lock

Class Lock provides access to information about a lock

@author Mikael Henriksson <mikael@mhenrixon.com>

Attributes

key[R]

@!attribute [r] key

@return [String] the entity redis key

Public Class Methods

create(digest, job_id, lock_info = {}) click to toggle source

Initialize a locked lock

@param [String] digest a unique digest @param [String] job_id a sidekiq JID @param [Hash] lock_info information about the lock

@return [Lock] a newly lock that has been locked

# File lib/sidekiq_unique_jobs/lock.rb, line 36
def self.create(digest, job_id, lock_info = {})
  lock = new(digest, time: Timing.now_f)
  lock.lock(job_id, lock_info)
  lock
end
new(key, time: nil) click to toggle source

Initialize a new lock

@param [String, Key] key either a digest or an instance of a {Key} @param [Timstamp, Float] time nil optional timestamp to initiate this lock with

# File lib/sidekiq_unique_jobs/lock.rb, line 48
def initialize(key, time: nil)
  @key        = get_key(key)
  @created_at = time.is_a?(Float) ? time : time.to_f
end

Public Instance Methods

all_jids() click to toggle source

Returns all job_id's for this lock

@note a JID can be present in 3 different places

@return [Array<String>] an array with JIDs

# File lib/sidekiq_unique_jobs/lock.rb, line 152
def all_jids
  (queued_jids + primed_jids + locked_jids).uniq
end
changelog() click to toggle source

A sorted set with changelog entries

@see Changelog for more information

@return [Changelog]

# File lib/sidekiq_unique_jobs/lock.rb, line 259
def changelog
  @changelog ||= Changelog.new
end
changelogs() click to toggle source

Returns all matching changelog entries for this lock

@return [Array<Hash>] an array with changelogs

# File lib/sidekiq_unique_jobs/lock.rb, line 194
def changelogs
  changelog.entries(pattern: "*#{key.digest}*")
end
created_at() click to toggle source

Returns either the time the lock was initialized with or

the first changelog entry's timestamp

@return [Float] a floaty timestamp represantation

# File lib/sidekiq_unique_jobs/lock.rb, line 140
def created_at
  @created_at ||= changelogs.first&.[]("time")
end
del() click to toggle source

Deletes all the redis keys for this lock

@return [Integer] the number of keys deleted in redis

# File lib/sidekiq_unique_jobs/lock.rb, line 124
def del
  redis do |conn|
    conn.multi do
      conn.zrem(DIGESTS, key.digest)
      conn.del(key.digest, key.queued, key.primed, key.locked, key.info)
    end
  end
end
digest() click to toggle source

The digest key

@note Used for exists checks to avoid enqueuing

the same lock twice

@return [Redis::String] a string representation of the key

# File lib/sidekiq_unique_jobs/lock.rb, line 207
def digest
  @digest ||= Redis::String.new(key.digest)
end
info() click to toggle source

Information about the lock

@return [Redis::Hash] with lock information

# File lib/sidekiq_unique_jobs/lock.rb, line 247
def info
  @info ||= LockInfo.new(key.info)
end
inspect() click to toggle source

@see to_s

# File lib/sidekiq_unique_jobs/lock.rb, line 285
def inspect
  to_s
end
lock(job_id, lock_info = {}) click to toggle source

Locks a job_id

@note intended only for testing purposes

@param [String] job_id a sidekiq JID @param [Hash] lock_info information about the lock

@return [void]

# File lib/sidekiq_unique_jobs/lock.rb, line 63
def lock(job_id, lock_info = {})
  redis do |conn|
    conn.multi do
      conn.set(key.digest, job_id)
      conn.hset(key.locked, job_id, now_f)
      info.set(lock_info)
      conn.zadd(key.digests, now_f, key.digest)
      conn.zadd(key.changelog, now_f, changelog_json(job_id, "queue.lua", "Queued"))
      conn.zadd(key.changelog, now_f, changelog_json(job_id, "lock.lua", "Locked"))
    end
  end
end
locked() click to toggle source

The locked hash

@return [Redis::Hash] for locked JIDs

# File lib/sidekiq_unique_jobs/lock.rb, line 237
def locked
  @locked ||= Redis::Hash.new(key.locked)
end
locked_jids(with_values: false) click to toggle source

Returns a collection of locked job_id's

@param [true, false] with_values false provide the timestamp for the lock

@return [Hash<String, Float>] when given `with_values: true` @return [Array<String>] when given `with_values: false`

# File lib/sidekiq_unique_jobs/lock.rb, line 164
def locked_jids(with_values: false)
  locked.entries(with_values: with_values)
end
prime(job_id) click to toggle source

Create the :PRIMED key

@note intended only for testing purposes

@param [String] job_id a sidekiq JID

@return [void]

# File lib/sidekiq_unique_jobs/lock.rb, line 100
def prime(job_id)
  redis do |conn|
    conn.lpush(key.primed, job_id)
  end
end
primed() click to toggle source

The primed list

@return [Redis::List] for primed JIDs

# File lib/sidekiq_unique_jobs/lock.rb, line 227
def primed
  @primed ||= Redis::List.new(key.primed)
end
primed_jids() click to toggle source

Returns the primed JIDs

@return [Array<String>] an array with primed job_ids

# File lib/sidekiq_unique_jobs/lock.rb, line 184
def primed_jids
  primed.entries
end
queue(job_id) click to toggle source

Create the :QUEUED key

@note intended only for testing purposes

@param [String] job_id a sidekiq JID

@return [void]

# File lib/sidekiq_unique_jobs/lock.rb, line 85
def queue(job_id)
  redis do |conn|
    conn.lpush(key.queued, job_id)
  end
end
queued() click to toggle source

The queued list

@return [Redis::List] for queued JIDs

# File lib/sidekiq_unique_jobs/lock.rb, line 217
def queued
  @queued ||= Redis::List.new(key.queued)
end
queued_jids() click to toggle source

Returns the queued JIDs

@return [Array<String>] an array with queued job_ids

# File lib/sidekiq_unique_jobs/lock.rb, line 174
def queued_jids
  queued.entries
end
to_s() click to toggle source

A nicely formatted string with information about this lock

@return [String]

# File lib/sidekiq_unique_jobs/lock.rb, line 269
    def to_s
      <<~MESSAGE
        Lock status for #{key}

                  value: #{digest.value}
                   info: #{info.value}
            queued_jids: #{queued_jids}
            primed_jids: #{primed_jids}
            locked_jids: #{locked_jids}
             changelogs: #{changelogs}
      MESSAGE
    end
unlock(job_id) click to toggle source

Unlock a specific job_id

@param [String] job_id a sidekiq JID

@return [true] when job_id was removed @return [false] when job_id wasn't locked

# File lib/sidekiq_unique_jobs/lock.rb, line 114
def unlock(job_id)
  locked.del(job_id)
end

Private Instance Methods

changelog_json(job_id, script, message) click to toggle source

Generate a changelog entry for the given arguments

@param [String] job_id a sidekiq JID @param [String] script the name of the script generating this entry @param [String] message a descriptive message for later review

@return [String] a JSON string matching the Lua script structure

# File lib/sidekiq_unique_jobs/lock.rb, line 315
def changelog_json(job_id, script, message)
  dump_json(
    digest: key.digest,
    job_id: job_id,
    script: script,
    message: message,
    time: now_f,
  )
end
get_key(key) click to toggle source

Ensure the key is a {Key}

@param [String, Key] key

@return [Key]

# File lib/sidekiq_unique_jobs/lock.rb, line 298
def get_key(key)
  if key.is_a?(SidekiqUniqueJobs::Key)
    key
  else
    SidekiqUniqueJobs::Key.new(key)
  end
end