sidekiq-unique-jobs 8.0.9 → 8.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -2
  3. data/README.md +56 -43
  4. data/lib/sidekiq_unique_jobs/cli.rb +2 -2
  5. data/lib/sidekiq_unique_jobs/config.rb +51 -32
  6. data/lib/sidekiq_unique_jobs/digests.rb +1 -1
  7. data/lib/sidekiq_unique_jobs/exceptions.rb +2 -2
  8. data/lib/sidekiq_unique_jobs/lock/base_lock.rb +1 -1
  9. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +1 -1
  10. data/lib/sidekiq_unique_jobs/lock.rb +1 -1
  11. data/lib/sidekiq_unique_jobs/lock_args.rb +3 -3
  12. data/lib/sidekiq_unique_jobs/lock_digest.rb +6 -1
  13. data/lib/sidekiq_unique_jobs/lock_ttl.rb +28 -6
  14. data/lib/sidekiq_unique_jobs/locksmith.rb +13 -8
  15. data/lib/sidekiq_unique_jobs/logging.rb +2 -2
  16. data/lib/sidekiq_unique_jobs/lua/delete.lua +6 -5
  17. data/lib/sidekiq_unique_jobs/lua/lock.lua +16 -7
  18. data/lib/sidekiq_unique_jobs/lua/queue.lua +9 -8
  19. data/lib/sidekiq_unique_jobs/lua/shared/_delete_from_queue.lua +10 -10
  20. data/lib/sidekiq_unique_jobs/lua/shared/_delete_from_sorted_set.lua +20 -10
  21. data/lib/sidekiq_unique_jobs/lua/unlock.lua +10 -9
  22. data/lib/sidekiq_unique_jobs/on_conflict/reject.rb +10 -1
  23. data/lib/sidekiq_unique_jobs/on_conflict/replace.rb +3 -3
  24. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +1 -1
  25. data/lib/sidekiq_unique_jobs/on_conflict.rb +2 -2
  26. data/lib/sidekiq_unique_jobs/orphans/manager.rb +3 -3
  27. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +4 -5
  28. data/lib/sidekiq_unique_jobs/reflections.rb +3 -3
  29. data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +2 -2
  30. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +4 -4
  31. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +1 -1
  32. data/lib/sidekiq_unique_jobs/testing.rb +2 -2
  33. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  34. data/lib/sidekiq_unique_jobs/web/helpers.rb +29 -1
  35. data/lib/sidekiq_unique_jobs/web.rb +38 -30
  36. metadata +5 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de442ce815fcfc00992295bd4160cfcf122815282e652cccca8c73ce1e62b351
4
- data.tar.gz: f01d32c217f81f41abf34666c43acdddcb8148e6f7ca0df8146d408f9ed14f8e
3
+ metadata.gz: 752654a036faee8511674b89a3a50ac370f497c29499e3f1fd4dd466b3c5d344
4
+ data.tar.gz: 40fbc25bd5639f248d6b34817e820d6b7f096a559ed3e0059d28570137b86274
5
5
  SHA512:
6
- metadata.gz: aec1ab15a3a3c1959bc137aaad674fa9e0854ca354b2226c352901f4d7d7c9cc6c8ef8d805b3b1ad680672eebca52a332de916a5e10d5f4d8b7b439bb677c7c0
7
- data.tar.gz: 9af5d9ce6dda38757fb33aa33d86c337cd40751fc55bad37ad5c3f98cb04225209953843b7ec137e9295b8da2c2a40a640c7735f1d623c17851621b577b7a03e
6
+ metadata.gz: cfe83dfbe84eaac52440e1178acf19abfe08bcf4e65c7dc8c9013c315f5e19c57a68c104ded980997c8b5f88400e90175a60858eaede00295327917062a26035
7
+ data.tar.gz: 128852982336a1d363eebf9f597fb30209369e4ce4376bfefe630fdd56c2bd426be724921b4d6493ccb1406ad65ba1fae37c8085efbdb4fb37e2c2cdd660f9a1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/HEAD)
4
+
5
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.10...HEAD)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - tweak changelog for 8.0.9 [\#836](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/836) ([Earlopain](https://github.com/Earlopain))
10
+ - Add digest scores for faster deletes in sorted sets [\#835](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/835) ([ezekg](https://github.com/ezekg))
11
+
12
+ ## [v8.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.10) (2024-02-22)
13
+
14
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v7.1.33...v8.0.10)
15
+
16
+ **Closed issues:**
17
+
18
+ - until\_and\_while\_executing and lock\_ttl: jobs silently dropped [\#788](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/788)
19
+ - Slow evalsha causing timeouts [\#668](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/668)
20
+
21
+ ## [v7.1.33](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v7.1.33) (2024-02-12)
22
+
23
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.9...v7.1.33)
24
+
25
+ ## [v8.0.9](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.9) (2024-02-12)
26
+
27
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.8...v8.0.9)
28
+
29
+ **Fixed bugs:**
30
+
31
+ - fix\(rce\): prevent remot code execution [\#833](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/833) ([mhenrixon](https://github.com/mhenrixon))
32
+
3
33
  ## [v8.0.8](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.8) (2024-02-12)
4
34
 
5
35
  [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.7...v8.0.8)
@@ -41,7 +71,7 @@
41
71
 
42
72
  ## [v8.0.6](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.6) (2024-01-24)
43
73
 
44
- [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.5...v8.0.6)
74
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v7.1.32...v8.0.6)
45
75
 
46
76
  **Implemented enhancements:**
47
77
 
@@ -51,7 +81,6 @@
51
81
  **Closed issues:**
52
82
 
53
83
  - should respond to `has_valid_sidekiq_options?` [\#822](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/822)
54
- - Reaper manager registration is subject to race conditions [\#801](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/801)
55
84
  - `while_executing` with `on_conflict: :reschedule` Reschedule job after job execution [\#800](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/800)
56
85
  - Large retry queue causes reaper to run too slow [\#759](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/759)
57
86
 
@@ -59,6 +88,14 @@
59
88
 
60
89
  - fix: skip unless reaper was registered [\#820](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/820) ([mhenrixon](https://github.com/mhenrixon))
61
90
 
91
+ ## [v7.1.32](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v7.1.32) (2023-11-11)
92
+
93
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.5...v7.1.32)
94
+
95
+ **Closed issues:**
96
+
97
+ - Reaper manager registration is subject to race conditions [\#801](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/801)
98
+
62
99
  ## [v8.0.5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.5) (2023-11-11)
63
100
 
64
101
  [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.4...v8.0.5)
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Support Me
6
6
 
7
- Want to show me some ❤️ for the hard work I do on this gem? You can use the following PayPal link: [https://paypal.me/mhenrixon1](https://paypal.me/mhenrixon1). Any amount is welcome and let me tell you it feels good to be appreciated. Even a dollar makes me super excited about all of this.
7
+ Want to show me some ❤️ for the hard work I do on this gem? You can use the following PayPal link: [https://paypal.me/mhenrixon2](https://paypal.me/mhenrixon2). Any amount is welcome and let me tell you it feels good to be appreciated. Even a dollar makes me super excited about all of this.
8
8
 
9
9
  <!-- MarkdownTOC -->
10
10
 
@@ -59,6 +59,7 @@ Want to show me some ❤️ for the hard work I do on this gem? You can use the
59
59
  - [sidekiq-global_id](#sidekiq-global_id)
60
60
  - [sidekiq-status](#sidekiq-status)
61
61
  - [Global Configuration](#global-configuration)
62
+ - [digest_algorithm](#digest_algorithm)
62
63
  - [debug_lua](#debug_lua)
63
64
  - [lock_timeout](#lock_timeout)
64
65
  - [lock_ttl](#lock_ttl)
@@ -88,7 +89,7 @@ Want to show me some ❤️ for the hard work I do on this gem? You can use the
88
89
 
89
90
  ## Introduction
90
91
 
91
- This gem adds unique constraints to sidekiq jobs. The uniqueness is achieved by creating a set of keys in redis based off of `queue`, `class`, `args` (in the sidekiq job hash).
92
+ This gem adds unique constraints to Sidekiq jobs. The uniqueness is achieved by creating a set of keys in redis based off of `queue`, `class`, `args` (in the Sidekiq job hash).
92
93
 
93
94
  By default, only one lock for a given hash can be acquired. What happens when a lock can't be acquired is governed by a chosen [Conflict Strategy](#conflict-strategy) strategy. Unless a conflict strategy is chosen (?)
94
95
 
@@ -108,7 +109,7 @@ Here are links to some of the old versions
108
109
  Add this line to your application's Gemfile:
109
110
 
110
111
  ```ruby
111
- gem 'sidekiq-unique-jobs'
112
+ gem "sidekiq-unique-jobs"
112
113
  ```
113
114
 
114
115
  And then execute:
@@ -153,7 +154,7 @@ end
153
154
 
154
155
  ### Your first worker
155
156
 
156
- The lock type most likely to be is `:until_executed`. This type of lock creates a lock from when `UntilExecutedWorker.perform_async` is called until right after `UntilExecutedWorker.new.perform` has been called.
157
+ The lock type most likely to be used is `:until_executed`. This type of lock creates a lock from when `UntilExecutedWorker.perform_async` is called until right after `UntilExecutedWorker.new.perform` has been called.
157
158
 
158
159
  ```ruby
159
160
  # frozen_string_literal: true
@@ -184,7 +185,7 @@ You can read more about the worker configuration in [Worker Configuration](#work
184
185
  - [ActiveJob officially not supported][48]
185
186
  - [redis-namespace officially not supported][49]
186
187
 
187
- See [Sidekiq requirements][24] for detailed requirements of Sidekiq itself (be sure to check the right sidekiq version).
188
+ See [Sidekiq requirements][24] for detailed requirements of Sidekiq itself (be sure to check the right `sidekiq` version).
188
189
 
189
190
  ## Locks
190
191
 
@@ -347,7 +348,7 @@ Please not that if you try to override a default lock, an `ArgumentError` will b
347
348
 
348
349
  ## Conflict Strategy
349
350
 
350
- Decides how we handle conflict. We can either `reject` the job to the dead queue or `reschedule` it. Both are useful for jobs that absolutely need to run and have been configured to use the lock `WhileExecuting` that is used only by the sidekiq server process.
351
+ Decides how we handle conflict. We can either `reject` the job to the dead queue or `reschedule` it. Both are useful for jobs that absolutely need to run and have been configured to use the lock `WhileExecuting` that is used only by the Sidekiq server process.
351
352
 
352
353
  Furthermore, `log` can be be used with the lock `UntilExecuted` and `UntilExpired`. Now we write a log entry saying the job could not be pushed because it is a duplicate of another job with the same arguments.
353
354
 
@@ -401,7 +402,7 @@ always scheduled in the future. Currently only attempting to retry one time.
401
402
  sidekiq_options on_conflict: :reschedule
402
403
  ```
403
404
 
404
- This strategy is intended to be used with `WhileExecuting` and will delay the job to be tried again in 5 seconds. This will mess up the sidekiq stats but will prevent exceptions from being logged and confuse your sysadmins.
405
+ This strategy is intended to be used with `WhileExecuting` and will delay the job to be tried again in 5 seconds (this delay can be configured via `sidekiq_options schedule_in: {seconds}`). This will mess up the Sidekiq stats but will prevent exceptions from being logged and confuse your sysadmins.
405
406
 
406
407
  ### Custom Strategies
407
408
 
@@ -440,12 +441,12 @@ Please not that if you try to override a default lock, an `ArgumentError` will b
440
441
 
441
442
  ### 3 Cleanup Dead Locks
442
443
 
443
- For sidekiq versions < 5.1 a `sidekiq_retries_exhausted` block is required per worker class. This is deprecated in Sidekiq 6.0
444
+ For `sidekiq` versions < 5.1 a `sidekiq_retries_exhausted` block is required per worker class. This is deprecated in Sidekiq 6.0
444
445
 
445
446
  ```ruby
446
447
  class MyWorker
447
448
  sidekiq_retries_exhausted do |msg, _ex|
448
- digest = msg['lock_digest']
449
+ digest = msg["lock_digest"]
449
450
  SidekiqUniqueJobs::Digests.new.delete_by_digest(digest) if digest
450
451
  end
451
452
  end
@@ -456,7 +457,7 @@ Starting in v5.1, Sidekiq can also fire a global callback when a job dies: In ve
456
457
  ```ruby
457
458
  Sidekiq.configure_server do |config|
458
459
  config.death_handlers << ->(job, _ex) do
459
- digest = job['lock_digest']
460
+ digest = job["lock_digest"]
460
461
  SidekiqUniqueJobs::Digests.new.delete_by_digest(digest) if digest
461
462
  end
462
463
  end
@@ -472,11 +473,11 @@ To use the web extension you need to require it in your routes.
472
473
 
473
474
  ```ruby
474
475
  #app/config/routes.rb
475
- require 'sidekiq_unique_jobs/web'
476
- mount Sidekiq::Web, at: '/sidekiq'
476
+ require "sidekiq_unique_jobs/web"
477
+ mount Sidekiq::Web, at: "/sidekiq"
477
478
  ```
478
479
 
479
- There is no need to `require 'sidekiq/web'` since `sidekiq_unique_jobs/web`
480
+ There is no need to `require "sidekiq/web"` since `sidekiq_unique_jobs/web`
480
481
  already does this.
481
482
 
482
483
  To filter/search for keys we can use the wildcard `*`. If we have a unique digest `'uniquejobs:9e9b5ce5d423d3ea470977004b50ff84` we can search for it by enter `*ff84` and it should return all digests that end with `ff84`.
@@ -490,10 +491,10 @@ To setup reflections for logging or metrics, use the following API:
490
491
  ```ruby
491
492
 
492
493
  def extract_log_from_job(message, job_hash)
493
- worker = job_hash['class']
494
- args = job_hash['args']
495
- lock_args = job_hash['lock_args']
496
- queue = job_hash['queue']
494
+ worker = job_hash["class"]
495
+ args = job_hash["args"]
496
+ lock_args = job_hash["lock_args"]
497
+ queue = job_hash["queue"]
497
498
  {
498
499
  message: message,
499
500
  worker: worker,
@@ -505,7 +506,7 @@ end
505
506
 
506
507
  SidekiqUniqueJobs.reflect do |on|
507
508
  on.lock_failed do |job_hash|
508
- message = extract_log_from_job('Lock Failed', job_hash)
509
+ message = extract_log_from_job("Lock Failed", job_hash)
509
510
  Sidekiq.logger.warn(message)
510
511
  end
511
512
  end
@@ -555,7 +556,7 @@ Also mostly useful for reporting purposes. The job was successfully unlocked.
555
556
 
556
557
  #### unknown_sidekiq_worker
557
558
 
558
- The reason this happens is that the server couldn't find a valid sidekiq worker class. Most likely, that worker isn't intended to be processed by this sidekiq server instance.
559
+ The reason this happens is that the server couldn't find a valid Sidekiq worker class. Most likely, that worker isn't intended to be processed by this Sidekiq server instance.
559
560
 
560
561
  ### Show Locks
561
562
 
@@ -603,7 +604,7 @@ assert_raise(InvalidWorker){ SidekiqUniqueJobs.validate_worker!(BadWorker.get_si
603
604
 
604
605
  ### Uniqueness
605
606
 
606
- This has been probably the most confusing part of this gem. People get really confused with how unreliable the unique jobs have been. I there for decided to do what Mike is doing for sidekiq enterprise. Read the section about unique jobs: [Enterprise unique jobs][](?)
607
+ This has been probably the most confusing part of this gem. People get really confused with how unreliable the unique jobs have been. I therefore decided to do what Mike is doing for Sidekiq Enterprise. Read the section about unique jobs: [Enterprise unique jobs][](?)
607
608
 
608
609
  ```ruby
609
610
  SidekiqUniqueJobs.configure do |config|
@@ -612,7 +613,7 @@ SidekiqUniqueJobs.configure do |config|
612
613
  end
613
614
  ```
614
615
 
615
- If you truly wanted to test the sidekiq client push you could do something like below. Note that it will only work for the jobs that lock when the client pushes the job to redis (UntilExecuted, UntilAndWhileExecuting and UntilExpired).
616
+ If you truly wanted to test the `sidekiq` client push you could do something like below. Note that it will only work for the jobs that lock when the client pushes the job to redis (UntilExecuted, UntilAndWhileExecuting and UntilExpired).
616
617
 
617
618
  ```ruby
618
619
  require "sidekiq_unique_jobs/testing"
@@ -624,7 +625,7 @@ RSpec.describe Workers::CoolOne do
624
625
 
625
626
  # ... your tests that don't test uniqueness
626
627
 
627
- context 'when Sidekiq::Testing.disabled?' do
628
+ context "when Sidekiq::Testing.disabled?" do
628
629
  before do
629
630
  Sidekiq::Testing.disable!
630
631
  Sidekiq.redis(&:flushdb)
@@ -634,7 +635,7 @@ RSpec.describe Workers::CoolOne do
634
635
  Sidekiq.redis(&:flushdb)
635
636
  end
636
637
 
637
- it 'prevents duplicate jobs from being scheduled' do
638
+ it "prevents duplicate jobs from being scheduled" do
638
639
  SidekiqUniqueJobs.use_config(enabled: true) do
639
640
  expect(described_class.perform_in(3600, 1)).not_to eq(nil)
640
641
  expect(described_class.perform_async(1)).to eq(nil)
@@ -734,17 +735,29 @@ Configure SidekiqUniqueJobs in an initializer or the sidekiq initializer on appl
734
735
 
735
736
  ```ruby
736
737
  SidekiqUniqueJobs.configure do |config|
737
- config.logger = Sidekiq.logger # default, change at your own discretion
738
- config.logger_enabled = true # default, disable for test environments
739
- config.debug_lua = false # Turn on when debugging
740
- config.lock_info = false # Turn on when debugging
741
- config.lock_ttl = 600 # Expire locks after 10 minutes
742
- config.lock_timeout = nil # turn off lock timeout
743
- config.max_history = 0 # Turn on when debugging
744
- config.reaper = :ruby # :ruby, :lua or :none/nil
745
- config.reaper_count = 1000 # Stop reaping after this many keys
746
- config.reaper_interval = 600 # Reap orphans every 10 minutes
747
- config.reaper_timeout = 150 # Timeout reaper after 2.5 minutes
738
+ config.logger = Sidekiq.logger # default, change at your own discretion
739
+ config.logger_enabled = true # default, disable for test environments
740
+ config.debug_lua = false # Turn on when debugging
741
+ config.lock_info = false # Turn on when debugging
742
+ config.lock_ttl = 600 # Expire locks after 10 minutes
743
+ config.lock_timeout = nil # turn off lock timeout
744
+ config.max_history = 0 # Turn on when debugging
745
+ config.reaper = :ruby # :ruby, :lua or :none/nil
746
+ config.reaper_count = 1000 # Stop reaping after this many keys
747
+ config.reaper_interval = 600 # Reap orphans every 10 minutes
748
+ config.reaper_timeout = 150 # Timeout reaper after 2.5 minutes
749
+ config.digest_algorithm = :modern # Timeout reaper after 2.5 minutes
750
+ end
751
+ ```
752
+ #### digest_algorithm
753
+
754
+ For backwards compatibility this one is set to `:legacy` by the default. If you happen to run into issues with FIPS being enabled on your redis server you might want to set this to `:modern`.
755
+
756
+ See: https://github.com/mhenrixon/sidekiq-unique-jobs/issues/848 for explanation
757
+
758
+ ```ruby
759
+ SidekiqUniqueJobs.configure do |config|
760
+ config.digest_algorithm = :modern # Timeout reaper after 2.5 minutes
748
761
  end
749
762
  ```
750
763
 
@@ -762,7 +775,7 @@ Turning on debug_lua will allow the lua scripts to output debug information abou
762
775
  SidekiqUniqueJobs.config.lock_timeout #=> 0
763
776
  ```
764
777
 
765
- Set a global lock_timeout to use for all jobs that don't otherwise specify a lock_timeout.
778
+ Set a global lock_timeout (in seconds) to use for all jobs that don't otherwise specify a lock_timeout.
766
779
 
767
780
  Lock timeout decides how long to wait for acquiring the lock. A value of nil means to wait indefinitely for a lock resource to become available.
768
781
 
@@ -772,7 +785,7 @@ Lock timeout decides how long to wait for acquiring the lock. A value of nil mea
772
785
  SidekiqUniqueJobs.config.lock_ttl #=> nil
773
786
  ```
774
787
 
775
- Set a global lock_ttl to use for all jobs that don't otherwise specify a lock_ttl.
788
+ Set a global lock_ttl (in seconds) to use for all jobs that don't otherwise specify a lock_ttl.
776
789
 
777
790
  Lock TTL decides how long to wait at most before considering a lock to be expired and making it possible to reuse that lock.
778
791
 
@@ -808,7 +821,7 @@ This is a log that can be accessed by a lock to see what happened for that lock.
808
821
  SidekiqUniqueJobs.config.reaper #=> :ruby
809
822
  ```
810
823
 
811
- If using the orphans cleanup process it is critical to be aware of the following. The `:ruby` job is much slower but the `:lua` job locks redis while executing. While doing intense processing it is best to avoid locking redis with a lua script. There for the batch size (controlled by the `reaper_count` setting) needs to be reduced.
824
+ If using the orphans cleanup process it is critical to be aware of the following. The `:ruby` job is much slower but the `:lua` job locks redis while executing. While doing intense processing it is best to avoid locking redis with a lua script. Therefore the batch size (controlled by the `reaper_count` setting) needs to be reduced.
812
825
 
813
826
  In my benchmarks deleting 1000 orphaned locks with lua performs around 65% faster than deleting 1000 keys in ruby.
814
827
 
@@ -913,13 +926,13 @@ This is mainly intended for `Worker.set(queue: :another).perform_async`.
913
926
  class Worker
914
927
  include Sidekiq::Worker
915
928
 
916
- sidekiq_options unique_across_queues: true, queue: 'default'
929
+ sidekiq_options unique_across_queues: true, queue: "default"
917
930
 
918
931
  def perform(args); end
919
932
  end
920
933
  ```
921
934
 
922
- Now if you push override the queue with `Worker.set(queue: 'another').perform_async(1)` it will still be considered unique when compared to `Worker.perform_async(1)` (that was actually pushed to the queue `default`).
935
+ Now if you push override the queue with `Worker.set(queue: "another").perform_async(1)` it will still be considered unique when compared to `Worker.perform_async(1)` (that was actually pushed to the queue `default`).
923
936
 
924
937
  #### unique_across_workers
925
938
 
@@ -929,7 +942,7 @@ This configuration option is slightly misleading. It doesn't disregard the worke
929
942
  class WorkerOne
930
943
  include Sidekiq::Worker
931
944
 
932
- sidekiq_options unique_across_workers: true, queue: 'default'
945
+ sidekiq_options unique_across_workers: true, queue: "default"
933
946
 
934
947
  def perform(args); end
935
948
  end
@@ -937,14 +950,14 @@ end
937
950
  class WorkerTwo
938
951
  include Sidekiq::Worker
939
952
 
940
- sidekiq_options unique_across_workers: true, queue: 'default'
953
+ sidekiq_options unique_across_workers: true, queue: "default"
941
954
 
942
955
  def perform(args); end
943
956
  end
944
957
 
945
958
 
946
959
  WorkerOne.perform_async(1)
947
- # => 'the jobs unique id'
960
+ # => "the jobs unique id"
948
961
 
949
962
  WorkerTwo.perform_async(1)
950
963
  # => nil because WorkerOne just stole the lock
@@ -1036,7 +1049,7 @@ There is a [![Join the chat at https://gitter.im/mhenrixon/sidekiq-unique-jobs](
1036
1049
 
1037
1050
  1. Fork it
1038
1051
  1. Create your feature branch (`git checkout -b my-new-feature`)
1039
- 1. Commit your changes (`git commit -am 'Add some feature'`)
1052
+ 1. Commit your changes (`git commit -am "Add some feature"`)
1040
1053
  1. Push to the branch (`git push origin my-new-feature`)
1041
1054
  1. Create new Pull Request
1042
1055
 
@@ -12,7 +12,7 @@ module SidekiqUniqueJobs
12
12
  # :nodoc:
13
13
  # rubocop:disable Style/OptionalBooleanParameter
14
14
  def self.banner(command, _namespace = nil, _subcommand = false) # rubocop:disable Style/OptionalBooleanParameter
15
- "jobs #{@package_name} #{command.usage}" # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
15
+ "jobs #{@package_name} #{command.usage}" # rubocop:disable ThreadSafety/ClassInstanceVariable
16
16
  end
17
17
  # rubocop:enable Style/OptionalBooleanParameter
18
18
 
@@ -51,7 +51,7 @@ module SidekiqUniqueJobs
51
51
  console_class.start
52
52
  end
53
53
 
54
- no_commands do # rubocop:disable Metrics/BlockLength
54
+ no_commands do
55
55
  # :nodoc:
56
56
  def digests
57
57
  @digests ||= SidekiqUniqueJobs::Digests.new
@@ -2,32 +2,34 @@
2
2
 
3
3
  module SidekiqUniqueJobs
4
4
  # ThreadSafe config exists to be able to document the config class without errors
5
- ThreadSafeConfig = Concurrent::MutableStruct.new("ThreadSafeConfig",
6
- :lock_timeout,
7
- :lock_ttl,
8
- :enabled,
9
- :lock_prefix,
10
- :logger,
11
- :logger_enabled,
12
- :locks,
13
- :strategies,
14
- :debug_lua,
15
- :max_history,
16
- :reaper,
17
- :reaper_count,
18
- :reaper_interval,
19
- :reaper_timeout,
20
- :reaper_resurrector_interval,
21
- :reaper_resurrector_enabled,
22
- :lock_info,
23
- :raise_on_config_error,
24
- :current_redis_version)
5
+ ThreadSafeConfig = Concurrent::MutableStruct.new(
6
+ "ThreadSafeConfig",
7
+ :lock_timeout,
8
+ :lock_ttl,
9
+ :enabled,
10
+ :lock_prefix,
11
+ :logger,
12
+ :logger_enabled,
13
+ :locks,
14
+ :strategies,
15
+ :debug_lua,
16
+ :max_history,
17
+ :reaper,
18
+ :reaper_count,
19
+ :reaper_interval,
20
+ :reaper_timeout,
21
+ :reaper_resurrector_interval,
22
+ :reaper_resurrector_enabled,
23
+ :lock_info,
24
+ :raise_on_config_error,
25
+ :current_redis_version,
26
+ :digest_algorithm,
27
+ )
25
28
 
26
29
  #
27
30
  # Shared class for dealing with gem configuration
28
31
  #
29
32
  # @author Mauro Berlanda <mauro.berlanda@gmail.com>
30
- # rubocop:disable Metrics/ClassLength
31
33
  class Config < ThreadSafeConfig
32
34
  #
33
35
  # @return [Hash<Symbol, SidekiqUniqueJobs::Lock::BaseLock] all available queued locks
@@ -118,11 +120,9 @@ module SidekiqUniqueJobs
118
120
  #
119
121
  # @return [3600] check if reaper is dead each 3600 seconds
120
122
  REAPER_RESURRECTOR_INTERVAL = 3600
121
-
122
123
  #
123
124
  # @return [false] enable reaper resurrector
124
125
  REAPER_RESURRECTOR_ENABLED = false
125
-
126
126
  #
127
127
  # @return [false] while useful it also adds overhead so disable lock_info by default
128
128
  USE_LOCK_INFO = false
@@ -132,6 +132,9 @@ module SidekiqUniqueJobs
132
132
  #
133
133
  # @return [0.0.0] default redis version is only to avoid NoMethodError on nil
134
134
  REDIS_VERSION = "0.0.0"
135
+ #
136
+ # @return [:legacy] default digest algorithm :modern or :legacy
137
+ DIGEST_ALGORITHM = :legacy
135
138
 
136
139
  #
137
140
  # Returns a default configuration
@@ -177,7 +180,7 @@ module SidekiqUniqueJobs
177
180
  #
178
181
  # @return [SidekiqUniqueJobs::Config] a default configuration
179
182
  #
180
- def self.default # rubocop:disable Metrics/MethodLength
183
+ def self.default
181
184
  new(
182
185
  LOCK_TIMEOUT,
183
186
  LOCK_TTL,
@@ -198,6 +201,7 @@ module SidekiqUniqueJobs
198
201
  USE_LOCK_INFO,
199
202
  RAISE_ON_CONFIG_ERROR,
200
203
  REDIS_VERSION,
204
+ DIGEST_ALGORITHM,
201
205
  )
202
206
  end
203
207
 
@@ -210,8 +214,8 @@ module SidekiqUniqueJobs
210
214
  # @return [<type>] <description>
211
215
  #
212
216
  def default_lock_ttl=(obj)
213
- warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated." \
214
- " Please use `#{class_name}#lock_ttl=` instead."
217
+ warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
218
+ "Please use `#{class_name}#lock_ttl=` instead."
215
219
  self.lock_ttl = obj
216
220
  end
217
221
 
@@ -224,8 +228,8 @@ module SidekiqUniqueJobs
224
228
  # @return [Integer]
225
229
  #
226
230
  def default_lock_timeout=(obj)
227
- warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated." \
228
- " Please use `#{class_name}#lock_timeout=` instead."
231
+ warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
232
+ "Please use `#{class_name}#lock_timeout=` instead."
229
233
  self.lock_timeout = obj
230
234
  end
231
235
 
@@ -236,8 +240,8 @@ module SidekiqUniqueJobs
236
240
  # @return [nil, Integer] configured value or nil
237
241
  #
238
242
  def default_lock_ttl
239
- warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated." \
240
- " Please use `#{class_name}#lock_ttl` instead."
243
+ warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
244
+ "Please use `#{class_name}#lock_ttl` instead."
241
245
  lock_ttl
242
246
  end
243
247
 
@@ -249,8 +253,8 @@ module SidekiqUniqueJobs
249
253
  # @return [nil, Integer] configured value or nil
250
254
  #
251
255
  def default_lock_timeout
252
- warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated." \
253
- " Please use `#{class_name}#lock_timeout` instead."
256
+ warn "[DEPRECATION] `#{class_name}##{__method__}` is deprecated. " \
257
+ "Please use `#{class_name}#lock_timeout` instead."
254
258
  lock_timeout
255
259
  end
256
260
 
@@ -304,6 +308,21 @@ module SidekiqUniqueJobs
304
308
  self.strategies = new_strategies
305
309
  end
306
310
 
311
+ #
312
+ # Sets digest_algorithm to either :modern or :legacy
313
+ #
314
+ # @param [Symbol] value
315
+ #
316
+ # @return [Symbol] the new value
317
+ #
318
+ def digest_algorithm=(value)
319
+ unless [:modern, :legacy].include?(value)
320
+ raise ArgumentError, "Invalid digest algorithm: #{value} (should be :modern or :legacy)"
321
+ end
322
+
323
+ super
324
+ end
325
+
307
326
  #
308
327
  # The current version of redis
309
328
  #
@@ -18,7 +18,7 @@ module SidekiqUniqueJobs
18
18
  EMPTY_KEYS_SEGMENT = ["", "", "", ""].freeze
19
19
 
20
20
  def initialize(digests_key = DIGESTS)
21
- super(digests_key)
21
+ super
22
22
  end
23
23
 
24
24
  #
@@ -80,8 +80,8 @@ module SidekiqUniqueJobs
80
80
 
81
81
  super(
82
82
  "#{job_class}##{lock_args_method} takes #{num_args} arguments, received #{given.inspect}" \
83
- "\n\n" \
84
- " #{source_location.join(':')}"
83
+ "\n\n " \
84
+ "#{source_location.join(':')}"
85
85
  )
86
86
  end
87
87
  end
@@ -147,7 +147,7 @@ module SidekiqUniqueJobs
147
147
  server_strategy
148
148
  else
149
149
  raise SidekiqUniqueJobs::InvalidArgument,
150
- "#origin needs to be either `:server` or `:client`"
150
+ "#origin needs to be either `:server` or `:client`"
151
151
  end
152
152
  end
153
153
 
@@ -23,7 +23,7 @@ module SidekiqUniqueJobs
23
23
  # @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
24
24
  #
25
25
  def initialize(item, callback, redis_pool = nil)
26
- super(item, callback, redis_pool)
26
+ super
27
27
  append_unique_key_suffix
28
28
  end
29
29
 
@@ -6,7 +6,7 @@ module SidekiqUniqueJobs
6
6
  #
7
7
  # @author Mikael Henriksson <mikael@mhenrixon.com>
8
8
  #
9
- class Lock # rubocop:disable Metrics/ClassLength
9
+ class Lock
10
10
  # includes "SidekiqUniqueJobs::Connection"
11
11
  # @!parse include SidekiqUniqueJobs::Connection
12
12
  include SidekiqUniqueJobs::Connection
@@ -91,9 +91,9 @@ module SidekiqUniqueJobs
91
91
  job_class.send(lock_args_method, args)
92
92
  rescue ArgumentError
93
93
  raise SidekiqUniqueJobs::InvalidUniqueArguments,
94
- given: args,
95
- job_class: job_class,
96
- lock_args_method: lock_args_method
94
+ given: args,
95
+ job_class: job_class,
96
+ lock_args_method: lock_args_method
97
97
  end
98
98
 
99
99
  # The method to use for filtering unique arguments
@@ -51,7 +51,12 @@ module SidekiqUniqueJobs
51
51
  # Creates a namespaced unique digest based on the {#digestable_hash} and the {#lock_prefix}
52
52
  # @return [String] a unique digest
53
53
  def create_digest
54
- digest = OpenSSL::Digest::MD5.hexdigest(dump_json(digestable_hash.sort))
54
+ digest = if SidekiqUniqueJobs.config.digest_algorithm == :legacy
55
+ OpenSSL::Digest::MD5.hexdigest(dump_json(digestable_hash.sort))
56
+ else
57
+ OpenSSL::Digest.new("SHA3-256", dump_json(digestable_hash.sort)).hexdigest
58
+ end
59
+
55
60
  "#{lock_prefix}:#{digest}"
56
61
  end
57
62