sidekiq-unique-jobs 6.0.0.rc6 → 6.0.0.rc7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq-unique-jobs might be problematic. Click here for more details.

Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +6 -7
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  4. data/.reek.yml +17 -48
  5. data/.rubocop.yml +3 -0
  6. data/.yardopts +7 -0
  7. data/CHANGELOG.md +2 -0
  8. data/README.md +65 -23
  9. data/assets/unique_digests_1.png +0 -0
  10. data/assets/unique_digests_2.png +0 -0
  11. data/examples/another_unique_job.rb +4 -2
  12. data/examples/custom_queue_job_with_filter_method.rb +1 -1
  13. data/examples/custom_queue_job_with_filter_proc.rb +1 -1
  14. data/examples/expiring_job.rb +1 -1
  15. data/examples/inline_worker.rb +1 -1
  16. data/examples/just_a_worker.rb +1 -1
  17. data/examples/long_running_job.rb +4 -2
  18. data/examples/main_job.rb +3 -2
  19. data/examples/my_unique_job.rb +4 -5
  20. data/examples/my_unique_job_with_filter_method.rb +3 -3
  21. data/examples/my_unique_job_with_filter_proc.rb +3 -3
  22. data/examples/notify_worker.rb +2 -2
  23. data/examples/simple_worker.rb +2 -2
  24. data/examples/unique_across_workers_job.rb +1 -1
  25. data/examples/unique_job_on_conflict_raise.rb +14 -0
  26. data/examples/unique_job_on_conflict_reject.rb +14 -0
  27. data/examples/unique_job_on_conflict_reschedule.rb +14 -0
  28. data/examples/unique_job_with_conditional_parameter.rb +3 -3
  29. data/examples/unique_job_with_filter_method.rb +5 -2
  30. data/examples/unique_job_with_nil_unique_args.rb +3 -3
  31. data/examples/unique_job_with_no_unique_args_method.rb +3 -3
  32. data/examples/unique_job_withthout_unique_args_parameter.rb +3 -3
  33. data/examples/unique_on_all_queues_job.rb +1 -1
  34. data/examples/until_and_while_executing_job.rb +4 -1
  35. data/examples/until_executed_2_job.rb +5 -5
  36. data/examples/until_executed_job.rb +5 -5
  37. data/examples/until_executing_job.rb +1 -1
  38. data/examples/until_expired_job.rb +1 -1
  39. data/examples/until_global_expired_job.rb +1 -1
  40. data/examples/while_executing_job.rb +2 -2
  41. data/examples/while_executing_reject_job.rb +2 -2
  42. data/examples/without_argument_job.rb +1 -1
  43. data/lib/sidekiq_unique_jobs.rb +30 -0
  44. data/lib/sidekiq_unique_jobs/client/middleware.rb +12 -1
  45. data/lib/sidekiq_unique_jobs/connection.rb +5 -1
  46. data/lib/sidekiq_unique_jobs/constants.rb +3 -0
  47. data/lib/sidekiq_unique_jobs/digests.rb +111 -0
  48. data/lib/sidekiq_unique_jobs/exceptions.rb +15 -16
  49. data/lib/sidekiq_unique_jobs/lock/base_lock.rb +44 -3
  50. data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +13 -3
  51. data/lib/sidekiq_unique_jobs/lock/until_executed.rb +8 -1
  52. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +8 -1
  53. data/lib/sidekiq_unique_jobs/lock/until_expired.rb +14 -2
  54. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +19 -5
  55. data/lib/sidekiq_unique_jobs/lock/while_executing_reject.rb +16 -63
  56. data/lib/sidekiq_unique_jobs/locksmith.rb +36 -13
  57. data/lib/sidekiq_unique_jobs/logging.rb +24 -1
  58. data/lib/sidekiq_unique_jobs/normalizer.rb +6 -0
  59. data/lib/sidekiq_unique_jobs/on_conflict.rb +24 -0
  60. data/lib/sidekiq_unique_jobs/on_conflict/log.rb +20 -0
  61. data/lib/sidekiq_unique_jobs/on_conflict/null_strategy.rb +16 -0
  62. data/lib/sidekiq_unique_jobs/on_conflict/raise.rb +17 -0
  63. data/lib/sidekiq_unique_jobs/on_conflict/reject.rb +72 -0
  64. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +24 -0
  65. data/lib/sidekiq_unique_jobs/on_conflict/strategy.rb +28 -0
  66. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +19 -4
  67. data/lib/sidekiq_unique_jobs/scripts.rb +31 -0
  68. data/lib/sidekiq_unique_jobs/server/middleware.rb +10 -0
  69. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +15 -1
  70. data/lib/sidekiq_unique_jobs/timeout/calculator.rb +17 -4
  71. data/lib/sidekiq_unique_jobs/unique_args.rb +47 -5
  72. data/lib/sidekiq_unique_jobs/unlockable.rb +10 -0
  73. data/lib/sidekiq_unique_jobs/util.rb +12 -7
  74. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  75. data/lib/sidekiq_unique_jobs/web.rb +51 -0
  76. data/lib/sidekiq_unique_jobs/web/helpers.rb +37 -0
  77. data/lib/sidekiq_unique_jobs/web/views/unique_digest.erb +28 -0
  78. data/lib/sidekiq_unique_jobs/web/views/unique_digests.erb +42 -0
  79. data/redis/create.lua +4 -2
  80. data/redis/delete.lua +3 -1
  81. data/redis/delete_by_digest.lua +22 -0
  82. data/redis/signal.lua +3 -1
  83. data/sidekiq-unique-jobs.gemspec +2 -0
  84. metadata +49 -3
  85. data/lib/sidekiq_unique_jobs/lock/while_executing_requeue.rb +0 -21
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module OnConflict
5
+ # Abstract conflict strategy class
6
+ #
7
+ # @abstract
8
+ # @author Mikael Henriksson <mikael@zoolutions.se>
9
+ class Strategy
10
+ include SidekiqUniqueJobs::Logging
11
+
12
+ # The sidekiq job hash
13
+ # @return [Hash] the Sidekiq job hash
14
+ attr_reader :item
15
+
16
+ # @param [Hash] item the Sidekiq job hash
17
+ def initialize(item)
18
+ @item = item
19
+ end
20
+
21
+ # Use strategy on conflict
22
+ # @raise [NotImplementedError] needs to be implemented in child class
23
+ def call
24
+ fail NotImplementedError, 'needs to be implemented in child class'
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SidekiqUniqueJobs
4
- # Shared logic for dealing with options
5
- # This class requires 3 things to be defined in the class including it
4
+ # Module containing methods shared between client and server middleware
5
+ #
6
+ # Requires the following methods to be defined in the including class
6
7
  # 1. item (required)
7
8
  # 2. options (can be nil)
8
9
  # 3. worker_class (required, can be anything)
10
+ # @author Mikael Henriksson <mikael@zoolutions.se>
9
11
  module OptionsWithFallback
10
12
  LOCKS = {
11
13
  until_and_while_executing: SidekiqUniqueJobs::Lock::UntilAndWhileExecuting,
@@ -21,32 +23,45 @@ module SidekiqUniqueJobs
21
23
  base.send(:include, SidekiqUniqueJobs::SidekiqWorkerMethods)
22
24
  end
23
25
 
26
+ # Check if unique has been enabled
27
+ # @return [true, false] indicate if the gem has been enabled
24
28
  def unique_enabled?
25
29
  SidekiqUniqueJobs.config.enabled && lock_type
26
30
  end
27
31
 
32
+ # Check if unique has been disabled
28
33
  def unique_disabled?
29
34
  !unique_enabled?
30
35
  end
31
36
 
37
+ # Check if we should log duplicate payloads
32
38
  def log_duplicate_payload?
33
39
  options[LOG_DUPLICATE_KEY] || item[LOG_DUPLICATE_KEY]
34
40
  end
35
41
 
42
+ # Check if we should log duplicate payloads
43
+ # @return [SidekiqUniqueJobs::Lock::BaseLock] an instance of a child class
36
44
  def lock
37
45
  @lock ||= lock_class.new(item, after_unlock_hook, @redis_pool)
38
46
  end
39
47
 
48
+ # Check if we should log duplicate payloads
49
+ # @return [SidekiqUniqueJobs::Lock::BaseLock] an instance of a child class
40
50
  def lock_class
41
51
  @lock_class ||= begin
42
52
  LOCKS.fetch(lock_type.to_sym) do
43
- fail UnknownLock, "No implementation for `unique: :#{lock_type}`"
53
+ fail UnknownLock, "No implementation for `lock: :#{lock_type}`"
44
54
  end
45
55
  end
46
56
  end
47
57
 
58
+ # @return [Symbol]
48
59
  def lock_type
49
- @lock_type ||= options[UNIQUE_KEY] || item[UNIQUE_KEY]
60
+ @lock_type ||= options[LOCK_KEY] || item[LOCK_KEY] || unique_type
61
+ end
62
+
63
+ def unique_type
64
+ options[UNIQUE_KEY] || item[UNIQUE_KEY]
50
65
  end
51
66
 
52
67
  def options
@@ -5,6 +5,9 @@ require 'digest/sha1'
5
5
  require 'concurrent/map'
6
6
 
7
7
  module SidekiqUniqueJobs
8
+ # Interface to dealing with .lua files
9
+ #
10
+ # @author Mikael Henriksson <mikael@zoolutions.se>
8
11
  module Scripts
9
12
  LUA_PATHNAME ||= Pathname.new(__FILE__).dirname.join('../../redis').freeze
10
13
  SCRIPT_SHAS ||= Concurrent::Map.new
@@ -13,6 +16,14 @@ module SidekiqUniqueJobs
13
16
 
14
17
  module_function
15
18
 
19
+ # Call a lua script with the provided file_name
20
+ # @param [Symbol] file_name the name of the lua script
21
+ # @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
22
+ # @param [Hash] options arguments to pass to the script file
23
+ # @option options [Array] :keys the array of keys to pass to the script
24
+ # @option options [Array] :argv the array of arguments to pass to the script
25
+ # @note this method is recursive if we need to load a lua script
26
+ # that wasn't previously loaded.
16
27
  def call(file_name, redis_pool, options = {})
17
28
  execute_script(file_name, redis_pool, options)
18
29
  rescue Redis::CommandError => ex
@@ -21,6 +32,12 @@ module SidekiqUniqueJobs
21
32
  end
22
33
  end
23
34
 
35
+ # Execute the script file
36
+ # @param [Symbol] file_name the name of the lua script
37
+ # @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
38
+ # @param [Hash] options arguments to pass to the script file
39
+ # @option options [Array] :keys the array of keys to pass to the script
40
+ # @option options [Array] :argv the array of arguments to pass to the script
24
41
  def execute_script(file_name, redis_pool, options = {})
25
42
  redis(redis_pool) do |conn|
26
43
  sha = script_sha(conn, file_name)
@@ -28,6 +45,10 @@ module SidekiqUniqueJobs
28
45
  end
29
46
  end
30
47
 
48
+ # Return sha of already loaded lua script or load it and return the sha
49
+ # @param [Sidekiq::RedisConnection] conn the redis connection
50
+ # @param [Symbol] file_name the name of the lua script
51
+ # @return [String] sha of the script file
31
52
  def script_sha(conn, file_name)
32
53
  if (sha = SCRIPT_SHAS.get(file_name))
33
54
  return sha
@@ -38,6 +59,10 @@ module SidekiqUniqueJobs
38
59
  sha
39
60
  end
40
61
 
62
+ # Return sha of already loaded lua script or load it and return the sha
63
+ # @param [Redis::CommandError] ex exception to handle
64
+ # @param [Symbol] file_name the name of the lua script
65
+ # @raise [ScriptError] when the error isn't handled
41
66
  def handle_error(ex, file_name)
42
67
  if ex.message == 'NOSCRIPT No matching script. Please use EVAL.'
43
68
  SCRIPT_SHAS.delete(file_name)
@@ -47,10 +72,16 @@ module SidekiqUniqueJobs
47
72
  raise ScriptError, file_name: file_name, source_exception: ex
48
73
  end
49
74
 
75
+ # Reads the lua file from disk
76
+ # @param [Symbol] file_name the name of the lua script
77
+ # @return [String] the content of the lua file
50
78
  def script_source(file_name)
51
79
  script_path(file_name).read
52
80
  end
53
81
 
82
+ # Construct a Pathname to a lua script
83
+ # @param [Symbol] file_name the name of the lua script
84
+ # @return [Pathname] the full path to the gems lua script
54
85
  def script_path(file_name)
55
86
  LUA_PATHNAME.join("#{file_name}.lua")
56
87
  end
@@ -2,9 +2,19 @@
2
2
 
3
3
  module SidekiqUniqueJobs
4
4
  module Server
5
+ # The unique sidekiq middleware for the server processor
6
+ #
7
+ # @author Mikael Henriksson <mikael@zoolutions.se>
5
8
  class Middleware
6
9
  include OptionsWithFallback
7
10
 
11
+ # Runs the server middleware
12
+ # Used from Sidekiq::Processor#process
13
+ # @param [Sidekiq::Worker] worker_class
14
+ # @param [Hash] item a sidekiq job hash
15
+ # @param [String] queue name of the queue
16
+ # @yield when uniqueness is disabled
17
+ # @yield when the lock class executes successfully
8
18
  def call(worker_class, item, queue)
9
19
  @worker_class = worker_class
10
20
  @item = item
@@ -1,24 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SidekiqUniqueJobs
4
+ # Module with convenience methods for the Sidekiq::Worker class
5
+ #
6
+ # @author Mikael Henriksson <mikael@zoolutions.se>
4
7
  module SidekiqWorkerMethods
8
+ # Avoids duplicating worker_class.respond_to? in multiple places
9
+ # @return [true, false]
5
10
  def worker_method_defined?(method_sym)
6
11
  worker_class.respond_to?(method_sym)
7
12
  end
8
13
 
14
+ # Wraps #get_sidekiq_options to always work with a hash
15
+ # @return [Hash] of the worker class sidekiq options
9
16
  def worker_options
10
17
  return {} unless sidekiq_worker_class?
11
18
  worker_class.get_sidekiq_options.stringify_keys
12
19
  end
13
20
 
21
+ # Tests that the
22
+ # @return [true] if worker_class responds to get_sidekiq_options
23
+ # @return [false] if worker_class does not respond to get_sidekiq_options
14
24
  def sidekiq_worker_class?
15
25
  worker_method_defined?(:get_sidekiq_options)
16
26
  end
17
27
 
28
+ # The Sidekiq::Worker implementation
29
+ # @return [Sidekiq::Worker]
18
30
  def worker_class
19
31
  @_worker_class ||= worker_class_constantize # rubocop:disable Naming/MemoizedInstanceVariableName
20
32
  end
21
33
 
34
+ # The hook to call after a successful unlock
35
+ # @return [Proc]
22
36
  def after_unlock_hook
23
37
  -> { worker_class.after_unlock if worker_method_defined?(:after_unlock) }
24
38
  end
@@ -26,7 +40,7 @@ module SidekiqUniqueJobs
26
40
  # Attempt to constantize a string worker_class argument, always
27
41
  # failing back to the original argument when the constant can't be found
28
42
  #
29
- # raises an error for other errors
43
+ # @return [Sidekiq::Worker]
30
44
  def worker_class_constantize(klazz = @worker_class)
31
45
  return klazz unless klazz.is_a?(String)
32
46
  Object.const_get(klazz)
@@ -2,28 +2,39 @@
2
2
 
3
3
  module SidekiqUniqueJobs
4
4
  module Timeout
5
+ # Calculates timeout and expiration
6
+ #
7
+ # @author Mikael Henriksson <mikael@zoolutions.se>
5
8
  class Calculator
6
9
  include SidekiqUniqueJobs::SidekiqWorkerMethods
10
+
11
+ # @attr [Hash] item the Sidekiq job hash
7
12
  attr_reader :item
8
13
 
14
+ # @param [Hash] item the Sidekiq job hash
15
+ # @option item [Integer, nil] :lock_expiration the configured lock expiration
16
+ # @option item [Integer, nil] :lock_timeout the configured lock timeout
17
+ # @option item [String] :class the class of the sidekiq worker
18
+ # @option item [Float] :at the unix time the job is scheduled at
9
19
  def initialize(item)
10
20
  @item = item
11
21
  @worker_class = item[CLASS_KEY]
12
22
  end
13
23
 
24
+ # The time until a job is scheduled
25
+ # @return [Integer] the number of seconds until job is scheduled
14
26
  def time_until_scheduled
15
27
  return 0 unless scheduled_at
16
28
  scheduled_at.to_i - Time.now.utc.to_i
17
29
  end
18
30
 
31
+ # The time a job is scheduled
32
+ # @return [Float] the exact unix time the job is scheduled at
19
33
  def scheduled_at
20
34
  @scheduled_at ||= item[AT_KEY]
21
35
  end
22
36
 
23
- def seconds
24
- raise NotImplementedError, "##{__method__} needs to be implemented in #{self.class}"
25
- end
26
-
37
+ # The configured lock_expiration
27
38
  def lock_expiration
28
39
  @lock_expiration ||= begin
29
40
  expiration = item[LOCK_EXPIRATION_KEY]
@@ -32,6 +43,7 @@ module SidekiqUniqueJobs
32
43
  end
33
44
  end
34
45
 
46
+ # The configured lock_timeout
35
47
  def lock_timeout
36
48
  @lock_timeout = begin
37
49
  timeout = default_worker_options[LOCK_TIMEOUT_KEY]
@@ -41,6 +53,7 @@ module SidekiqUniqueJobs
41
53
  end
42
54
  end
43
55
 
56
+ # The default lock_timeout of this gem
44
57
  def default_lock_timeout
45
58
  SidekiqUniqueJobs.config.default_lock_timeout
46
59
  end
@@ -4,17 +4,25 @@ require 'digest'
4
4
  require 'sidekiq_unique_jobs/normalizer'
5
5
 
6
6
  module SidekiqUniqueJobs
7
- # This class exists to be testable and the entire api should be considered private
7
+ # Handles uniqueness of sidekiq arguments
8
+ #
9
+ # @author Mikael Henriksson <mikael@zoolutions.se>
8
10
  class UniqueArgs
9
11
  include SidekiqUniqueJobs::Logging
10
12
  include SidekiqUniqueJobs::SidekiqWorkerMethods
11
13
 
14
+ # Convenience method for returning a digest
15
+ # @param [Hash] item a Sidekiq job hash
16
+ # @return [String] a unique digest
12
17
  def self.digest(item)
13
18
  new(item).unique_digest
14
19
  end
15
20
 
21
+ # The sidekiq job hash
22
+ # @return [Hash] the Sidekiq job hash
16
23
  attr_reader :item
17
24
 
25
+ # @param [Hash] item a Sidekiq job hash
18
26
  def initialize(item)
19
27
  @item = item
20
28
  @worker_class = item[CLASS_KEY]
@@ -22,52 +30,73 @@ module SidekiqUniqueJobs
22
30
  add_uniqueness_to_item
23
31
  end
24
32
 
33
+ # Appends the keys unique_prefix, unique_args and {#unique_digest} to the sidekiq job hash {#item}
34
+ # @return [void]
25
35
  def add_uniqueness_to_item
26
36
  item[UNIQUE_PREFIX_KEY] ||= unique_prefix
27
37
  item[UNIQUE_ARGS_KEY] = unique_args(item[ARGS_KEY])
28
38
  item[UNIQUE_DIGEST_KEY] = unique_digest
29
39
  end
30
40
 
41
+ # Memoized unique_digest
42
+ # @return [String] a unique digest
31
43
  def unique_digest
32
44
  @unique_digest ||= create_digest
33
45
  end
34
46
 
47
+ # Creates a namespaced unique digest based on the {#digestable_hash} and the {#unique_prefix}
48
+ # @return [String] a unique digest
35
49
  def create_digest
36
50
  digest = Digest::MD5.hexdigest(Sidekiq.dump_json(digestable_hash))
37
51
  "#{unique_prefix}:#{digest}"
38
52
  end
39
53
 
54
+ # A prefix to use as namespace for the {#unique_digest}
55
+ # @return [String] a unique digest
40
56
  def unique_prefix
41
57
  worker_options[UNIQUE_PREFIX_KEY] || SidekiqUniqueJobs.config.unique_prefix
42
58
  end
43
59
 
60
+ # Filter a hash to use for digest
61
+ # @return [Hash] to use for digest
44
62
  def digestable_hash
45
63
  @item.slice(CLASS_KEY, QUEUE_KEY, UNIQUE_ARGS_KEY).tap do |hash|
46
- hash.delete(QUEUE_KEY) if unique_on_all_queues?
64
+ hash.delete(QUEUE_KEY) if unique_across_queues?
47
65
  hash.delete(CLASS_KEY) if unique_across_workers?
48
66
  end
49
67
  end
50
68
 
69
+ # The unique arguments to use for creating a lock
70
+ # @return [Array] the arguments filters by the {#filtered_args} method if {#unique_args_enabled?}
51
71
  def unique_args(args)
52
72
  return filtered_args(args) if unique_args_enabled?
53
73
  args
54
74
  end
55
75
 
56
- def unique_on_all_queues?
76
+ # Checks if we should disregard the queue when creating the unique digest
77
+ # @return [true, false]
78
+ def unique_across_queues?
57
79
  item[UNIQUE_ACROSS_QUEUES_KEY] || worker_options[UNIQUE_ACROSS_QUEUES_KEY] ||
58
80
  item[UNIQUE_ON_ALL_QUEUES_KEY] || worker_options[UNIQUE_ON_ALL_QUEUES_KEY] # TODO: Remove in v 6.1
59
81
  end
60
82
 
83
+ # Checks if we should disregard the worker when creating the unique digest
84
+ # @return [true, false]
61
85
  def unique_across_workers?
62
86
  item[UNIQUE_ACROSS_WORKERS_KEY] || worker_options[UNIQUE_ACROSS_WORKERS_KEY]
63
87
  end
64
88
 
89
+ # Checks if the worker class has been enabled for unique_args?
90
+ # @return [true, false]
65
91
  def unique_args_enabled?
66
92
  unique_args_method # && !unique_args_method.is_a?(Boolean)
67
93
  end
68
94
 
69
95
  # Filters unique arguments by proc or symbol
70
- # returns provided arguments for other configurations
96
+ # @param [Array] args the arguments passed to the sidekiq worker
97
+ # @return [Array] {#filter_by_proc} when {#unique_args_method} is a Proc
98
+ # @return [Array] {#filter_by_symbol} when {#unique_args_method} is a Symbol
99
+ # @return [Array] args unfiltered when neither of the above
71
100
  def filtered_args(args)
72
101
  return args if args.empty?
73
102
  json_args = Normalizer.jsonify(args)
@@ -83,10 +112,17 @@ module SidekiqUniqueJobs
83
112
  end
84
113
  end
85
114
 
115
+ # Filters unique arguments by proc configured in the sidekiq worker
116
+ # @param [Array] args the arguments passed to the sidekiq worker
117
+ # @return [Array] with the filtered arguments
86
118
  def filter_by_proc(args)
87
119
  unique_args_method.call(args)
88
120
  end
89
121
 
122
+ # Filters unique arguments by method configured in the sidekiq worker
123
+ # @param [Array] args the arguments passed to the sidekiq worker
124
+ # @return [Array] unfiltered unless {#worker_method_defined?}
125
+ # @return [Array] with the filtered arguments
90
126
  def filter_by_symbol(args)
91
127
  return args unless worker_method_defined?(unique_args_method)
92
128
 
@@ -96,10 +132,16 @@ module SidekiqUniqueJobs
96
132
  args
97
133
  end
98
134
 
135
+ # The method to use for filtering unique arguments
99
136
  def unique_args_method
100
137
  @unique_args_method ||= worker_options[UNIQUE_ARGS_KEY]
101
138
  @unique_args_method ||= :unique_args if worker_method_defined?(:unique_args)
102
- @unique_args_method ||= Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
139
+ @unique_args_method ||= default_unique_args_method
140
+ end
141
+
142
+ # The global worker options defined in Sidekiq directly
143
+ def default_unique_args_method
144
+ Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
103
145
  end
104
146
  end
105
147
  end
@@ -1,14 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SidekiqUniqueJobs
4
+ # Utility module to help manage unique keys in redis.
5
+ # Useful for deleting keys that for whatever reason wasn't deleted
6
+ #
7
+ # @author Mikael Henriksson <mikael@zoolutions.se>
4
8
  module Unlockable
5
9
  module_function
6
10
 
11
+ # Unlocks a job.
12
+ # @param [Hash] item a Sidekiq job hash
7
13
  def unlock(item)
8
14
  SidekiqUniqueJobs::UniqueArgs.digest(item)
9
15
  SidekiqUniqueJobs::Locksmith.new(item).unlock
10
16
  end
11
17
 
18
+ # Deletes a lock regardless of if it was locked or not.
19
+ #
20
+ # This is good for situations when a job is locked by another item
21
+ # @param [Hash] item a Sidekiq job hash
12
22
  def delete(item)
13
23
  SidekiqUniqueJobs::UniqueArgs.digest(item)
14
24
  SidekiqUniqueJobs::Locksmith.new(item).delete!