Class: SidekiqUniqueJobs::Locksmith

Inherits:
Object
  • Object
show all
Includes:
Connection
Defined in:
lib/sidekiq_unique_jobs/locksmith.rb

Overview

Lock manager class that handles all the various locks

Constant Summary collapse

API_VERSION =

rubocop:disable ClassLength

'1'
EXPIRES_IN =
10

Instance Method Summary collapse

Methods included from Connection

#redis

Constructor Details

#initialize(item, redis_pool = nil) ⇒ Locksmith

Returns a new instance of Locksmith.

Parameters:

  • item (Hash)

    a Sidekiq job hash

  • redis_pool (Sidekiq::RedisConnection, ConnectionPool) (defaults to: nil)

    the redis connection

Options Hash (item):

  • :lock_expiration (Integer)

    the configured expiration

  • :jid (String)

    the sidekiq job id

  • :unique_digest (String)

    the unique digest (See: UniqueArgs#unique_digest)



18
19
20
21
22
23
24
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 18

def initialize(item, redis_pool = nil)
  @concurrency   = 1 # removed in a0cff5bc42edbe7190d6ede7e7f845074d2d7af6
  @expiration    = item[LOCK_EXPIRATION_KEY]
  @jid           = item[JID_KEY]
  @unique_digest = item[UNIQUE_DIGEST_KEY]
  @redis_pool    = redis_pool
end

Instance Method Details

#available_countInteger

The number of available resourced for this lock

Returns:

  • (Integer)

    the number of available resources



45
46
47
48
49
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 45

def available_count
  return concurrency unless exists?

  redis(redis_pool) { |conn| conn.llen(available_key) }
end

#createString

Creates the necessary keys in redis to attempt a lock

Returns:

  • (String)

    the Sidekiq job_id



28
29
30
31
32
33
34
35
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 28

def create
  Scripts.call(
    :create,
    redis_pool,
    keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
    argv: [jid, expiration, API_VERSION, concurrency],
  )
end

#deleteObject

Deletes the lock unless it has an expiration set



52
53
54
55
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 52

def delete
  return if expiration
  delete!
end

#delete!Object

Deletes the lock regardless of if it has an expiration set



58
59
60
61
62
63
64
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 58

def delete!
  Scripts.call(
    :delete,
    redis_pool,
    keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
  )
end

#exists?true, false

Checks if the exists key is created in redis

Returns:

  • (true, false)


39
40
41
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 39

def exists?
  redis(redis_pool) { |conn| conn.exists(exists_key) }
end

#lock(timeout = nil) { ... } ⇒ Object Also known as: wait

Create a lock for the item

Parameters:

  • timeout (Integer) (defaults to: nil)

    the number of seconds to wait for a lock. nil means wait indefinitely

Yields:

  • the block to execute if a lock is successful

Returns:

  • the Sidekiq job_id (jid)



71
72
73
74
75
76
77
78
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 71

def lock(timeout = nil, &block)
  create

  grab_token(timeout) do |token|
    touch_grabbed_token(token)
    return_token_or_block_value(token, &block)
  end
end

#locked?(token = nil) ⇒ true, false

Removes the lock keys from Redis

Parameters:

  • token (String) (defaults to: nil)

    the unique token to check for a lock. nil will default to the jid provided in the initializer

Returns:

  • (true, false)


93
94
95
96
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 93

def locked?(token = nil)
  token ||= jid
  redis(redis_pool) { |conn| conn.hexists(grabbed_key, token) }
end

#signal(token = nil) ⇒ Integer

Signal that the token should be released

Parameters:

  • token (String) (defaults to: nil)

    the unique token to check for a lockk. nil will default to the jid provided in the initializer.

Returns:

  • (Integer)

    the number of available lock resources



102
103
104
105
106
107
108
109
110
111
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 102

def signal(token = nil)
  token ||= jid

  Scripts.call(
    :signal,
    redis_pool,
    keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
    argv: [token, expiration],
  )
end

#unlockfalse, String

Removes the lock keys from Redis

Returns:

  • (false)

    unless locked?

  • (String)

    Sidekiq job_id (jid) if successful



84
85
86
87
# File 'lib/sidekiq_unique_jobs/locksmith.rb', line 84

def unlock
  return false unless locked?
  signal(jid)
end