sidekiq-unique-jobs 4.0.0 → 4.0.7

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -1
  3. data/.travis.yml +1 -2
  4. data/Appraisals +1 -1
  5. data/CHANGELOG.md +44 -1
  6. data/Gemfile +1 -2
  7. data/README.md +49 -51
  8. data/circle.yml +3 -1
  9. data/gemfiles/sidekiq_2.17.gemfile +7 -5
  10. data/gemfiles/sidekiq_3.0.gemfile +6 -4
  11. data/gemfiles/sidekiq_3.1.gemfile +6 -4
  12. data/gemfiles/sidekiq_3.2.gemfile +6 -4
  13. data/gemfiles/sidekiq_3.3.gemfile +6 -4
  14. data/gemfiles/sidekiq_develop.gemfile +6 -4
  15. data/lib/sidekiq-unique-jobs.rb +3 -6
  16. data/lib/sidekiq_unique_jobs/config.rb +1 -6
  17. data/lib/sidekiq_unique_jobs/constants.rb +17 -0
  18. data/lib/sidekiq_unique_jobs/core_ext.rb +28 -23
  19. data/lib/sidekiq_unique_jobs/lock.rb +1 -1
  20. data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +13 -0
  21. data/lib/sidekiq_unique_jobs/lock/until_executed.rb +17 -3
  22. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +4 -0
  23. data/lib/sidekiq_unique_jobs/lock/until_timeout.rb +9 -2
  24. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +17 -5
  25. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +14 -5
  26. data/lib/sidekiq_unique_jobs/server/middleware.rb +3 -40
  27. data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +29 -2
  28. data/lib/sidekiq_unique_jobs/testing/sidekiq_overrides.rb +6 -2
  29. data/lib/sidekiq_unique_jobs/timeout_calculator.rb +42 -0
  30. data/lib/sidekiq_unique_jobs/unique_args.rb +31 -29
  31. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  32. data/redis/synchronize.lua +1 -1
  33. data/sidekiq-unique-jobs.gemspec +1 -2
  34. data/spec/{workers/unique_worker.rb → jobs/another_unique_job.rb} +3 -3
  35. data/spec/{workers/queue_worker.rb → jobs/custom_queue_job.rb} +1 -1
  36. data/spec/jobs/custom_queue_job_with_filter_method.rb +7 -0
  37. data/spec/{workers/queue_worker_with_filter_proc.rb → jobs/custom_queue_job_with_filter_proc.rb} +2 -3
  38. data/spec/jobs/expiring_job.rb +4 -0
  39. data/spec/{workers → jobs}/inline_worker.rb +1 -1
  40. data/spec/jobs/just_a_worker.rb +8 -0
  41. data/spec/jobs/main_job.rb +8 -0
  42. data/spec/{workers/my_worker.rb → jobs/my_job.rb} +2 -3
  43. data/spec/jobs/my_unique_job.rb +7 -0
  44. data/spec/{workers → jobs}/plain_class.rb +0 -0
  45. data/spec/{workers → jobs}/test_class.rb +0 -0
  46. data/spec/{workers → jobs}/unique_job_with_filter_method.rb +2 -2
  47. data/spec/{workers/unique_on_all_queues_worker.rb → jobs/unique_on_all_queues_job.rb} +3 -3
  48. data/spec/jobs/until_and_while_executing_job.rb +8 -0
  49. data/spec/{workers/another_unique_worker.rb → jobs/until_executed_job.rb} +6 -2
  50. data/spec/jobs/until_executing_job.rb +8 -0
  51. data/spec/jobs/until_global_timeout_job.rb +8 -0
  52. data/spec/{workers/inline_expiration_worker.rb → jobs/until_timeout_job.rb} +2 -2
  53. data/spec/{workers/after_unlock_worker.rb → jobs/while_executing_job.rb} +2 -3
  54. data/spec/lib/sidekiq_unique_jobs/client/middleware_spec.rb +60 -44
  55. data/spec/lib/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +39 -0
  56. data/spec/lib/sidekiq_unique_jobs/lock/until_executed_spec.rb +40 -0
  57. data/spec/lib/sidekiq_unique_jobs/lock/while_executing_spec.rb +15 -4
  58. data/spec/lib/sidekiq_unique_jobs/options_with_fallback_spec.rb +25 -0
  59. data/spec/lib/sidekiq_unique_jobs/scripts_spec.rb +3 -4
  60. data/spec/lib/sidekiq_unique_jobs/server/middleware_spec.rb +51 -68
  61. data/spec/lib/sidekiq_unique_jobs/sidekiq_testing_enabled_spec.rb +75 -79
  62. data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb +2 -2
  63. data/spec/lib/sidekiq_unique_jobs/{lock/time_calculator_spec.rb → timeout_calculator_spec.rb} +10 -11
  64. data/spec/lib/sidekiq_unique_jobs/unique_args_spec.rb +28 -45
  65. data/spec/spec_helper.rb +23 -15
  66. data/spec/support/unique_macros.rb +20 -1
  67. metadata +30 -42
  68. data/lib/sidekiq_unique_jobs/lock/time_calculator.rb +0 -44
  69. data/spec/workers/after_yield_worker.rb +0 -17
  70. data/spec/workers/before_yield_worker.rb +0 -9
  71. data/spec/workers/expiring_worker.rb +0 -4
  72. data/spec/workers/inline_unlock_order_worker.rb +0 -8
  73. data/spec/workers/just_a_worker.rb +0 -8
  74. data/spec/workers/main_job.rb +0 -8
  75. data/spec/workers/my_unique_worker.rb +0 -8
  76. data/spec/workers/queue_worker_with_filter_method.rb +0 -7
  77. data/spec/workers/run_lock_with_retries_worker.rb +0 -12
  78. data/spec/workers/run_lock_worker.rb +0 -7
  79. data/spec/workers/while_executing_worker.rb +0 -13
@@ -34,11 +34,15 @@ module Sidekiq
34
34
  end
35
35
  jobs.clear
36
36
  end
37
+
38
+ def execute_job(worker, args)
39
+ worker.perform(*args)
40
+ end unless respond_to?(:execute_job)
37
41
  end
38
42
 
39
43
  module Overrides
40
44
  def self.included(base)
41
- base.extend Sidekiq::Worker::Overrides::ClassMethods
45
+ base.extend Testing
42
46
  base.class_eval do
43
47
  class << self
44
48
  alias_method :clear_all_orig, :clear_all
@@ -47,7 +51,7 @@ module Sidekiq
47
51
  end
48
52
  end
49
53
 
50
- module ClassMethods
54
+ module Testing
51
55
  def clear_all_ext
52
56
  Sidekiq.redis do |c|
53
57
  unique_keys = c.keys("#{SidekiqUniqueJobs.config.unique_prefix}:*")
@@ -0,0 +1,42 @@
1
+ module SidekiqUniqueJobs
2
+ class TimeoutCalculator
3
+ def self.for_item(item)
4
+ new(item)
5
+ end
6
+
7
+ def initialize(item)
8
+ @item = item
9
+ end
10
+
11
+ def seconds
12
+ time_until_scheduled + unique_expiration
13
+ end
14
+
15
+ def time_until_scheduled
16
+ scheduled = item[AT_KEY]
17
+ return 0 unless scheduled
18
+ (Time.at(scheduled) - Time.now.utc).to_i
19
+ end
20
+
21
+ def unique_expiration
22
+ @unique_expiration ||=
23
+ (
24
+ worker_class_unique_expiration ||
25
+ SidekiqUniqueJobs.config.default_expiration
26
+ ).to_i
27
+ end
28
+
29
+ def worker_class_unique_expiration
30
+ return unless worker_class.respond_to?(:get_sidekiq_options)
31
+ worker_class.get_sidekiq_options[UNIQUE_TIMEOUT_KEY]
32
+ end
33
+
34
+ def worker_class
35
+ @worker_class ||= SidekiqUniqueJobs.worker_class_constantize(item[CLASS_KEY])
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :item
41
+ end
42
+ end
@@ -1,26 +1,28 @@
1
+ require 'digest'
1
2
  require 'sidekiq_unique_jobs/normalizer'
2
3
 
3
4
  module SidekiqUniqueJobs
4
5
  # This class exists to be testable and the entire api should be considered private
5
6
  # rubocop:disable ClassLength
6
7
  class UniqueArgs
8
+ CLASS_NAME = 'SidekiqUniqueJobs::UniqueArgs'.freeze
7
9
  extend Forwardable
8
10
  include Normalizer
9
11
 
10
12
  def_delegators :SidekiqUniqueJobs, :config, :worker_class_constantize
11
- def_delegators :'Sidekiq.logger', :logger, :debug, :warn, :error, :fatal
13
+ def_delegators :Sidekiq, :logger
12
14
 
13
15
  def self.digest(item)
14
16
  new(item).unique_digest
15
17
  end
16
18
 
17
19
  def initialize(job)
18
- Sidekiq::Logging.with_context(self.class.name) do
20
+ Sidekiq::Logging.with_context(CLASS_NAME) do
19
21
  @item = job
20
- @worker_class ||= worker_class_constantize(@item['class'.freeze])
21
- @item['unique_prefix'.freeze] ||= unique_prefix
22
- @item['unique_args'.freeze] ||= unique_args(@item['args'.freeze])
23
- @item['unique_digest'.freeze] ||= unique_digest
22
+ @worker_class ||= worker_class_constantize(@item[CLASS_KEY])
23
+ @item[UNIQUE_PREFIX_KEY] ||= unique_prefix
24
+ @item[UNIQUE_ARGS_KEY] ||= unique_args(@item[ARGS_KEY])
25
+ @item[UNIQUE_DIGEST_KEY] ||= unique_digest
24
26
  end
25
27
  end
26
28
 
@@ -28,22 +30,24 @@ module SidekiqUniqueJobs
28
30
  @unique_digest ||= begin
29
31
  digest = Digest::MD5.hexdigest(Sidekiq.dump_json(digestable_hash))
30
32
  digest = "#{unique_prefix}:#{digest}"
31
- debug { "#{__method__} : #{digestable_hash} into #{digest}" }
33
+ logger.debug { "#{__method__} : #{digestable_hash} into #{digest}" }
32
34
  digest
33
35
  end
34
36
  end
35
37
 
36
38
  def unique_prefix
37
39
  return config.unique_prefix unless sidekiq_worker_class?
38
- @worker_class.get_sidekiq_options['unique_prefix'.freeze] || config.unique_prefix
40
+ @worker_class.get_sidekiq_options[UNIQUE_PREFIX_KEY] || config.unique_prefix
39
41
  end
40
42
 
41
43
  def digestable_hash
42
- hash = @item.slice('class', 'queue', 'unique_args')
44
+ hash = @item.slice(CLASS_KEY, QUEUE_KEY, UNIQUE_ARGS_KEY)
43
45
 
44
46
  if unique_on_all_queues?
45
- debug { "uniqueness specified across all queues (deleting queue: #{@item['queue']} from hash)" }
46
- hash.delete('queue')
47
+ logger.debug do
48
+ "uniqueness specified across all queues (deleting queue: #{@item[QUEUE_KEY]} from hash)"
49
+ end
50
+ hash.delete(QUEUE_KEY)
47
51
  end
48
52
  hash
49
53
  end
@@ -52,7 +56,7 @@ module SidekiqUniqueJobs
52
56
  if unique_args_enabled?
53
57
  filtered_args(args)
54
58
  else
55
- debug { "#{__method__} : unique arguments disabled" }
59
+ logger.debug { "#{__method__} : unique arguments disabled" }
56
60
  args
57
61
  end
58
62
  rescue NameError
@@ -62,26 +66,19 @@ module SidekiqUniqueJobs
62
66
 
63
67
  def unique_on_all_queues?
64
68
  return unless sidekiq_worker_class?
65
- return unless unique_args_enabled?
66
- @worker_class.get_sidekiq_options['unique_on_all_queues'.freeze]
69
+ @item[UNIQUE_ON_ALL_QUEUES_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ON_ALL_QUEUES_KEY]
67
70
  end
68
71
 
69
72
  def unique_args_enabled?
70
- unique_args_enabled_in_worker? ||
71
- config.unique_args_enabled
72
- end
73
-
74
- def unique_args_enabled_in_worker?
75
73
  return unless sidekiq_worker_class?
76
- @worker_class.get_sidekiq_options['unique_args_enabled'.freeze] ||
77
- @worker_class.get_sidekiq_options['unique_args'.freeze]
74
+ unique_args_method # && !unique_args_method.is_a?(Boolean)
78
75
  end
79
76
 
80
77
  def sidekiq_worker_class?
81
78
  if @worker_class.respond_to?(:get_sidekiq_options)
82
79
  true
83
80
  else
84
- debug { "#{@worker_class} does not respond to :get_sidekiq_options" }
81
+ logger.debug { "#{@worker_class} does not respond to :get_sidekiq_options" }
85
82
  nil
86
83
  end
87
84
  end
@@ -91,7 +88,7 @@ module SidekiqUniqueJobs
91
88
  def filtered_args(args)
92
89
  return args if args.empty?
93
90
  json_args = Normalizer.jsonify(args)
94
- debug { "#filtered_args #{args} => #{json_args}" }
91
+ logger.debug { "#filtered_args #{args} => #{json_args}" }
95
92
 
96
93
  case unique_args_method
97
94
  when Proc
@@ -99,20 +96,24 @@ module SidekiqUniqueJobs
99
96
  when Symbol
100
97
  filter_by_symbol(json_args)
101
98
  else
102
- debug { 'arguments not filtered (the combined arguments count towards uniqueness)' }
99
+ logger.debug { 'arguments not filtered (the combined arguments count towards uniqueness)' }
103
100
  json_args
104
101
  end
105
102
  end
106
103
 
107
104
  def filter_by_proc(args)
105
+ if unique_args_method.nil?
106
+ warn { "#{__method__} : Proc was nil, returning args as is #{args} -> #{filter_args}" }
107
+ return args
108
+ end
108
109
  filter_args = unique_args_method.call(args)
109
- debug { "#{__method__} : #{args} -> #{filter_args}" }
110
+ logger.debug { "#{__method__} : #{args} -> #{filter_args}" }
110
111
  filter_args
111
112
  end
112
113
 
113
114
  def filter_by_symbol(args)
114
115
  unless @worker_class.respond_to?(unique_args_method)
115
- warn do
116
+ logger.warn do
116
117
  "#{__method__} : #{unique_args_method}) not defined in #{@worker_class} " \
117
118
  "returning #{args} unchanged"
118
119
  end
@@ -120,13 +121,14 @@ module SidekiqUniqueJobs
120
121
  end
121
122
 
122
123
  filter_args = @worker_class.send(unique_args_method, args)
123
- debug { "#{__method__} : #{unique_args_method}(#{args}) => #{filter_args}" }
124
+ logger.debug { "#{__method__} : #{unique_args_method}(#{args}) => #{filter_args}" }
124
125
  filter_args
125
126
  end
126
127
 
127
128
  def unique_args_method
128
- @unique_args_method ||=
129
- @worker_class.get_sidekiq_options['unique_args'.freeze] if sidekiq_worker_class?
129
+ @unique_args_method ||= @worker_class.get_sidekiq_options[UNIQUE_ARGS_KEY] if sidekiq_worker_class?
130
+ @unique_args_method ||= :unique_args if @worker_class.respond_to?(:unique_args)
131
+ @unique_args_method ||= Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
130
132
  end
131
133
  end
132
134
  end
@@ -1,3 +1,3 @@
1
1
  module SidekiqUniqueJobs
2
- VERSION = '4.0.0'
2
+ VERSION = '4.0.7'
3
3
  end
@@ -7,7 +7,7 @@ end
7
7
 
8
8
  local stored_time = redis.pcall('get', unique_key)
9
9
  if stored_time and stored_time < time then
10
- if redis.call('set', unique_key, time + 60, 'nx', 'ex') then
10
+ if redis.pcall('set', unique_key, time + 60, 'xx', 'ex', 60) then
11
11
  return 1
12
12
  end
13
13
  end
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
19
19
  gem.add_development_dependency 'rspec', '~> 3.1.0'
20
20
  gem.add_development_dependency 'rake'
21
21
  gem.add_development_dependency 'rspec-sidekiq'
22
- gem.add_development_dependency 'activesupport', '>= 3'
23
22
  gem.add_development_dependency 'rubocop'
24
- gem.add_development_dependency 'simplecov'
23
+ gem.add_development_dependency 'timecop'
25
24
  end
@@ -1,7 +1,7 @@
1
- class UniqueWorker
1
+ class AnotherUniqueJob
2
2
  include Sidekiq::Worker
3
- sidekiq_options queue: :working, retry: 1, backtrace: 10
4
- sidekiq_options unique: true, unique_lock: :until_executed
3
+ sidekiq_options queue: :working, retry: 1, backtrace: 10,
4
+ unique: :until_executed
5
5
 
6
6
  sidekiq_retries_exhausted do |msg|
7
7
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -1,4 +1,4 @@
1
- class QueueWorker
1
+ class CustomQueueJob
2
2
  include Sidekiq::Worker
3
3
  sidekiq_options queue: :customqueue
4
4
  def perform(_)
@@ -0,0 +1,7 @@
1
+ class CustomQueueJobWithFilterMethod < CustomQueueJob
2
+ sidekiq_options unique: :until_executed, unique_args: :args_filter
3
+
4
+ def self.args_filter(*args)
5
+ args.first
6
+ end
7
+ end
@@ -1,8 +1,7 @@
1
- class QueueWorkerWithFilterProc < QueueWorker
1
+ class CustomQueueJobWithFilterProc < CustomQueueJob
2
2
  # slightly contrived example of munging args to the
3
3
  # worker and removing a random bit.
4
- sidekiq_options unique: true,
5
- unique_lock: :until_timeout,
4
+ sidekiq_options unique: :until_timeout,
6
5
  unique_args: (lambda do |*args|
7
6
  options = args.extract_options!
8
7
  options.delete(:random)
@@ -0,0 +1,4 @@
1
+ class ExpiringJob
2
+ include Sidekiq::Worker
3
+ sidekiq_options unique: :until_executed, unique_expiration: 10 * 60
4
+ end
@@ -1,6 +1,6 @@
1
1
  class InlineWorker
2
2
  include Sidekiq::Worker
3
- sidekiq_options unique: true
3
+ sidekiq_options unique: :while_executing
4
4
 
5
5
  def perform(x)
6
6
  TestClass.run(x)
@@ -0,0 +1,8 @@
1
+ class JustAWorker
2
+ include Sidekiq::Worker
3
+
4
+ sidekiq_options unique: :until_executed, queue: 'testqueue'
5
+
6
+ def perform
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class MainJob
2
+ include Sidekiq::Worker
3
+ sidekiq_options queue: :customqueue, unique: :until_executed,
4
+ log_duplicate_payload: true
5
+
6
+ def perform(_)
7
+ end
8
+ end
@@ -1,7 +1,6 @@
1
- class MyWorker
1
+ class MyJob
2
2
  include Sidekiq::Worker
3
- sidekiq_options queue: :working, retry: 1, backtrace: 10
4
- sidekiq_options unique: false
3
+ sidekiq_options queue: :working, retry: 1, backtrace: 10, unique: false
5
4
 
6
5
  sidekiq_retries_exhausted do |msg|
7
6
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -0,0 +1,7 @@
1
+ class MyUniqueJob
2
+ include Sidekiq::Worker
3
+ sidekiq_options queue: :customqueue, retry: true, unique: :until_executed,
4
+ unique_expiration: 7_200, retry_count: 10
5
+ def perform(_)
6
+ end
7
+ end
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  class UniqueJobWithFilterMethod
2
2
  include Sidekiq::Worker
3
- sidekiq_options queue: :customqueue, retry: 1, backtrace: 10
4
- sidekiq_options unique: true, unique_args: :filtered_args
3
+ sidekiq_options queue: :customqueue, retry: 1, backtrace: 10,
4
+ unique: :while_executing, unique_args: :filtered_args
5
5
 
6
6
  sidekiq_retries_exhausted do |msg|
7
7
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -1,7 +1,7 @@
1
- class UniqueOnAllQueuesWorker
1
+ class UniqueOnAllQueuesJob
2
2
  include Sidekiq::Worker
3
- sidekiq_options queue: :working, retry: 1, backtrace: 10
4
- sidekiq_options unique: true, unique_on_all_queues: true, unique_lock: :until_executed
3
+ sidekiq_options queue: :working, retry: 1, backtrace: 10,
4
+ unique: :until_executed, unique_on_all_queues: true
5
5
 
6
6
  sidekiq_retries_exhausted do |msg|
7
7
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -0,0 +1,8 @@
1
+ class UntilAndWhileExecuting
2
+ include Sidekiq::Worker
3
+
4
+ sidekiq_options queue: :working, unique: :until_and_while_executing
5
+
6
+ def perform
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
- class AnotherUniqueWorker
1
+ class UntilExecutedJob
2
2
  include Sidekiq::Worker
3
3
  sidekiq_options queue: :working, retry: 1, backtrace: 10
4
- sidekiq_options unique: true, unique_lock: :until_executed
4
+ sidekiq_options unique: :until_executed
5
5
 
6
6
  sidekiq_retries_exhausted do |msg|
7
7
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -10,4 +10,8 @@ class AnotherUniqueWorker
10
10
  def perform(*)
11
11
  # NO-OP
12
12
  end
13
+
14
+ def after_unlock
15
+ fail 'HELL'
16
+ end
13
17
  end
@@ -0,0 +1,8 @@
1
+ class UntilExecutingJob
2
+ include Sidekiq::Worker
3
+
4
+ sidekiq_options queue: :working, unique: :until_executing
5
+
6
+ def perform
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class UntilGlobalTimeoutJob
2
+ include Sidekiq::Worker
3
+ sidekiq_options unique: :until_timeout
4
+
5
+ def perform(x)
6
+ TestClass.run(x)
7
+ end
8
+ end
@@ -1,6 +1,6 @@
1
- class InlineExpirationWorker
1
+ class UntilTimeoutJob
2
2
  include Sidekiq::Worker
3
- sidekiq_options unique: true, unique_lock: :until_timeout,
3
+ sidekiq_options unique: :until_timeout,
4
4
  unique_expiration: 10 * 60
5
5
  def perform(x)
6
6
  TestClass.run(x)
@@ -1,7 +1,6 @@
1
- class AfterUnlockWorker
1
+ class WhileExecutingJob
2
2
  include Sidekiq::Worker
3
- sidekiq_options queue: :working, retry: 1, backtrace: 10
4
- sidekiq_options unique: true, unique_lock: :until_executed
3
+ sidekiq_options queue: :working, retry: 1, backtrace: 10, unique: :while_executing
5
4
 
6
5
  sidekiq_retries_exhausted do |msg|
7
6
  Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'celluloid/current'
3
2
  require 'sidekiq/worker'
4
3
  require 'sidekiq-unique-jobs'
5
4
  require 'sidekiq/scheduled'
@@ -13,36 +12,50 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
13
12
  before do
14
13
  Sidekiq.redis = REDIS
15
14
  Sidekiq.redis(&:flushdb)
16
- QueueWorker.sidekiq_options unique: nil, unique_expiration: nil
17
15
  end
18
16
 
19
17
  describe 'when a job is already scheduled' do
20
- context '#new_unique_for' do
21
- it 'rejects new scheduled jobs with the same argument' do
22
- MyUniqueWorker.perform_in(3600, 1)
23
- expect(MyUniqueWorker.perform_in(3600, 1)).to eq(nil)
18
+ it 'rejects new scheduled jobs with the same argument' do
19
+ MyUniqueJob.perform_in(3600, 1)
20
+ expect(MyUniqueJob.perform_in(3600, 1)).to eq(nil)
21
+ end
22
+
23
+ it 'will run a job in real time with the same arguments' do
24
+ WhileExecutingJob.perform_in(3600, 1)
25
+ expect(WhileExecutingJob.perform_async(1)).not_to eq(nil)
26
+ end
27
+
28
+ it 'schedules new jobs when arguments differ' do
29
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x|
30
+ MainJob.perform_in(x, x)
24
31
  end
25
32
 
26
- it 'will run a job in real time with the same arguments' do
27
- WhileExecutingWorker.perform_in(3600, 1)
28
- expect(WhileExecutingWorker.perform_async(1)).not_to eq(nil)
33
+ Sidekiq.redis do |c|
34
+ count = c.zcount('schedule', -1, Time.now.to_f + 2 * 60)
35
+ expect(count).to eq(20)
29
36
  end
37
+ end
30
38
 
31
- it 'schedules new jobs when arguments differ' do
32
- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x|
33
- MainJob.perform_in(x.seconds.from_now, x)
39
+ it 'schedules allows jobs to be scheduled ' do
40
+ class ShitClass
41
+ def do_it(_arg)
42
+ # whatever
34
43
  end
44
+ end
35
45
 
36
- Sidekiq.redis do |c|
37
- count = c.zcount('schedule', -1, Time.now.to_f + 2 * 60)
38
- expect(count).to eq(20)
39
- end
46
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x|
47
+ ShitClass.delay_for(x, unique: :while_executing).do_it(1)
48
+ end
49
+
50
+ Sidekiq.redis do |c|
51
+ count = c.zcount('schedule', -1, Time.now.to_f + 2 * 60)
52
+ expect(count).to eq(20)
40
53
  end
41
54
  end
42
55
  end
43
56
 
44
57
  it 'does not push duplicate messages when configured for unique only' do
45
- item = { 'class' => MyUniqueWorker, 'queue' => 'customqueue', 'args' => [1, 2] }
58
+ item = { 'class' => MyUniqueJob, 'queue' => 'customqueue', 'args' => [1, 2] }
46
59
  10.times { Sidekiq::Client.push(item) }
47
60
  Sidekiq.redis do |c|
48
61
  expect(c.llen('queue:customqueue')).to eq(1)
@@ -50,8 +63,8 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
50
63
  end
51
64
 
52
65
  it 'does push duplicate messages to different queues' do
53
- Sidekiq::Client.push('class' => MyUniqueWorker, 'queue' => 'customqueue', 'args' => [1, 2])
54
- Sidekiq::Client.push('class' => MyUniqueWorker, 'queue' => 'customqueue2', 'args' => [1, 2])
66
+ Sidekiq::Client.push('class' => MyUniqueJob, 'queue' => 'customqueue', 'args' => [1, 2])
67
+ Sidekiq::Client.push('class' => MyUniqueJob, 'queue' => 'customqueue2', 'args' => [1, 2])
55
68
  Sidekiq.redis do |c|
56
69
  expect(c.llen('queue:customqueue')).to eq 1
57
70
  expect(c.llen('queue:customqueue2')).to eq 1
@@ -59,14 +72,14 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
59
72
  end
60
73
 
61
74
  it 'does not queue duplicates when when calling delay' do
62
- 10.times { PlainClass.delay(unique_lock: :until_executed, unique: true, queue: 'customqueue').run(1) }
75
+ 10.times { PlainClass.delay(unique: :until_executed, queue: 'customqueue').run(1) }
63
76
  Sidekiq.redis do |c|
64
77
  expect(c.llen('queue:customqueue')).to eq(1)
65
78
  end
66
79
  end
67
80
 
68
81
  it 'does not schedule duplicates when calling perform_in' do
69
- 10.times { MyUniqueWorker.perform_in(60, [1, 2]) }
82
+ 10.times { MyUniqueJob.perform_in(60, [1, 2]) }
70
83
  Sidekiq.redis do |c|
71
84
  expect(c.zcount('schedule', -1, Time.now.to_f + 2 * 60))
72
85
  .to eq(1)
@@ -74,8 +87,8 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
74
87
  end
75
88
 
76
89
  it 'enqueues previously scheduled job' do
77
- jid = WhileExecutingWorker.perform_in(60 * 60, 1, 2)
78
- item = { 'class' => WhileExecutingWorker, 'queue' => 'customqueue', 'args' => [1, 2], 'jid' => jid }
90
+ jid = WhileExecutingJob.perform_in(60 * 60, 1, 2)
91
+ item = { 'class' => WhileExecutingJob, 'queue' => 'customqueue', 'args' => [1, 2], 'jid' => jid }
79
92
 
80
93
  # time passes and the job is pulled off the schedule:
81
94
  Sidekiq::Client.push(item)
@@ -86,18 +99,20 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
86
99
  end
87
100
 
88
101
  it 'sets an expiration when provided by sidekiq options' do
89
- item = { 'class' => ExpiringWorker, 'queue' => 'customqueue', 'args' => [1, 2] }
102
+ item = { 'class' => ExpiringJob, 'queue' => 'customqueue', 'args' => [1, 2] }
90
103
  Sidekiq::Client.push(item)
91
104
 
92
105
  Sidekiq.redis do |c|
93
106
  expect(c.llen('queue:customqueue')).to eq(1)
94
107
  expect(c.ttl(digest_for(item)))
95
- .to eq(ExpiringWorker.get_sidekiq_options['unique_expiration'])
108
+ .to eq(ExpiringJob.get_sidekiq_options['unique_expiration'])
96
109
  end
97
110
  end
98
111
 
99
112
  it 'does push duplicate messages when not configured for unique only' do
100
- 10.times { Sidekiq::Client.push('class' => QueueWorker, 'queue' => 'customqueue', 'args' => [1, 2]) }
113
+ 10.times do
114
+ Sidekiq::Client.push('class' => CustomQueueJob, 'queue' => 'customqueue', 'args' => [1, 2])
115
+ end
101
116
 
102
117
  Sidekiq.redis do |c|
103
118
  expect(c.llen('queue:customqueue')).to eq(10)
@@ -105,16 +120,13 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
105
120
  end
106
121
 
107
122
  describe 'when unique_args is defined' do
108
- before(:all) { SidekiqUniqueJobs.config.unique_args_enabled = true }
109
- after(:all) { SidekiqUniqueJobs.config.unique_args_enabled = false }
110
-
111
123
  it 'does not push duplicate messages based on args filter method' do
112
- expect(QueueWorkerWithFilterMethod).to respond_to(:args_filter)
113
- expect(QueueWorkerWithFilterMethod.get_sidekiq_options['unique_args']).to eq :args_filter
124
+ expect(CustomQueueJobWithFilterMethod).to respond_to(:args_filter)
125
+ expect(CustomQueueJobWithFilterMethod.get_sidekiq_options['unique_args']).to eq :args_filter
114
126
 
115
127
  (0..10).each do |i|
116
128
  Sidekiq::Client.push(
117
- 'class' => QueueWorkerWithFilterMethod,
129
+ 'class' => CustomQueueJobWithFilterMethod,
118
130
  'queue' => 'customqueue',
119
131
  'args' => [1, i]
120
132
  )
@@ -126,11 +138,11 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
126
138
  end
127
139
 
128
140
  it 'does not push duplicate messages based on args filter proc' do
129
- expect(QueueWorkerWithFilterProc.get_sidekiq_options['unique_args']).to be_a(Proc)
141
+ expect(CustomQueueJobWithFilterProc.get_sidekiq_options['unique_args']).to be_a(Proc)
130
142
 
131
143
  100.times do
132
144
  Sidekiq::Client.push(
133
- 'class' => QueueWorkerWithFilterProc,
145
+ 'class' => CustomQueueJobWithFilterProc,
134
146
  'queue' => 'customqueue',
135
147
  'args' => [1, { random: rand, name: 'foobar' }]
136
148
  )
@@ -143,7 +155,7 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
143
155
 
144
156
  describe 'when unique_on_all_queues is set' do
145
157
  it 'does not push duplicate messages on different queues' do
146
- item = { 'class' => UniqueOnAllQueuesWorker, 'args' => [1, 2] }
158
+ item = { 'class' => UniqueOnAllQueuesJob, 'args' => [1, 2] }
147
159
  Sidekiq::Client.push(item.merge('queue' => 'customqueue'))
148
160
  Sidekiq::Client.push(item.merge('queue' => 'customqueue2'))
149
161
  Sidekiq.redis do |c|
@@ -158,9 +170,9 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
158
170
  # jobs are set around the same time as the scheduled job itself feel free to improve.
159
171
  it 'expires the digest when a scheduled job is scheduled at' do
160
172
  expected_expires_at =
161
- (Time.at(15.minutes.from_now) - Time.now.utc) + SidekiqUniqueJobs.config.default_expiration
162
- jid = MyUniqueWorker.perform_in(expected_expires_at, 'mike')
163
- item = { 'class' => MyUniqueWorker,
173
+ (Time.at(Time.now.to_i + 15 * 60) - Time.now.utc) + SidekiqUniqueJobs.config.default_expiration
174
+ jid = MyUniqueJob.perform_in(expected_expires_at, 'mike')
175
+ item = { 'class' => MyUniqueJob,
164
176
  'queue' => 'customqueue',
165
177
  'args' => ['mike'],
166
178
  'at' => expected_expires_at }
@@ -172,24 +184,28 @@ RSpec.describe SidekiqUniqueJobs::Client::Middleware do
172
184
 
173
185
  it 'logs duplicate payload when config turned on' do
174
186
  expect(Sidekiq.logger).to receive(:warn).with(/^payload is not unique/)
175
- UniqueWorker.sidekiq_options log_duplicate_payload: true
176
- 2.times { Sidekiq::Client.push('class' => UniqueWorker, 'queue' => 'customqueue', 'args' => [1, 2]) }
187
+ UntilExecutedJob.sidekiq_options log_duplicate_payload: true
188
+ 2.times do
189
+ Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2])
190
+ end
177
191
  Sidekiq.redis do |c|
178
192
  expect(c.llen('queue:customqueue')).to eq 1
179
193
  end
180
- UniqueWorker.sidekiq_options log_duplicate_payload: true
194
+ UntilExecutedJob.sidekiq_options log_duplicate_payload: true
181
195
  end
182
196
 
183
197
  it 'does not log duplicate payload when config turned off' do
184
198
  expect(Sidekiq.logger).to_not receive(:warn).with(/^payload is not unique/)
185
199
 
186
- UniqueWorker.sidekiq_options log_duplicate_payload: false
200
+ UntilExecutedJob.sidekiq_options log_duplicate_payload: false
187
201
 
188
- 2.times { Sidekiq::Client.push('class' => UniqueWorker, 'queue' => 'customqueue', 'args' => [1, 2]) }
202
+ 2.times do
203
+ Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2])
204
+ end
189
205
  Sidekiq.redis do |c|
190
206
  expect(c.llen('queue:customqueue')).to eq 1
191
207
  end
192
- UniqueWorker.sidekiq_options log_duplicate_payload: true
208
+ UntilExecutedJob.sidekiq_options log_duplicate_payload: true
193
209
  end
194
210
  end
195
211
  end