activejob-uniqueness 0.1.2 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff1cfb19bc51b7eb8f4040f700650c51a47376e1ec96c84ae72b764227911f0c
4
- data.tar.gz: 3813cf68d80e7d56d828e15f179c677e49fe2f171780e25c0a6990b7b93eed76
3
+ metadata.gz: cd76f286ed7e6482860247e9b98b754dc1b73a381fcd2579d73e469da95d0200
4
+ data.tar.gz: 866f0949c68745c168217cbc70b10c65799f70aa372902dbd145781726217acd
5
5
  SHA512:
6
- metadata.gz: b616c4460d8bffe1be31226c3d18d9d3a7197fd714d680ddd636b154934ff648fb5dface28b0099b59ac865a91a5a0cec85a8230ba8d442bda6f831535405b94
7
- data.tar.gz: 938eb49268486827b8b946934838af755f7f449fc75e84f2cde8538e49af7e786edc13583a715ad86b2203a58867e324e8e580cc611d522e512ae7ed235ddae1
6
+ metadata.gz: 5cb9299a82cc40a9fca3df73c771cf553ead9393b11eca505afea5e55fe3023722db67d509528d0886db66e64569ba1caea04622ebde3ca365df1d768f04d2f4
7
+ data.tar.gz: 205d78f3c41721bce16c16d991204423fe5429b23c1d6fad48eb1a4ac7f775057f7e15192e8d1c32c97fc0c2c4af60a1584d6a666c253df71e1acce9ba02e5fa
data/CHANGELOG.md CHANGED
@@ -1,14 +1,119 @@
1
- ## Changes Between 0.1.1 and 0.1.2
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
2
3
 
3
- Release lock for Sidekiq adapter when all Sidekiq attempts were unsuccessful or job is deleted manually from Sidekiq::Web
4
- [PR](https://github.com/veeqo/activejob-uniqueness/pull/5) by @vbyno
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
- ## Changes Between 0.1.0 and 0.1.1
6
+ ## [Unreleased](https://github.com/veeqo/activejob-uniqueness/compare/v0.4.0...HEAD)
7
7
 
8
- Fixed NoMethodError on `Rails.application.eager_load!` in Rails initializer
9
- ```
10
- NoMethodError: undefined method `unique' for MyJob:Class
11
- ```
12
- [PR](https://github.com/veeqo/activejob-uniqueness/pull/4)
13
8
 
14
- ## Original Release: 0.1.0
9
+ ## [0.4.0](https://github.com/veeqo/activejob-uniqueness/compare/v0.3.2...v0.4.0) - 2024-12-07
10
+
11
+ ### Added
12
+
13
+ - [#86](https://github.com/veeqo/activejob-uniqueness/pull/86) Add Rails 8.0 rc1 support by[@sharshenov](https://github.com/sharshenov)
14
+ - [#78](https://github.com/veeqo/activejob-uniqueness/pull/78) Add on_redis_connection_error config to adjust to new redlock behaviour by[@nduitz](https://github.com/nduitz)
15
+
16
+ ### Changed
17
+ - [#82](https://github.com/veeqo/activejob-uniqueness/pull/82) Optimize bulk unlocking [@sharshenov](https://github.com/sharshenov)
18
+
19
+ ## [0.3.2](https://github.com/veeqo/activejob-uniqueness/compare/v0.3.1...v0.3.2) - 2024-08-16
20
+
21
+ ### Added
22
+ - [#80](https://github.com/veeqo/activejob-uniqueness/pull/80) Add rails 7.2 support by [@viralpraxis](https://github.com/viralpraxis)
23
+
24
+ ### Changed
25
+ - [#74](https://github.com/veeqo/activejob-uniqueness/pull/74) Fix log subscriber by [@shahidkhaliq](https://github.com/shahidkhaliq)
26
+
27
+ ## [0.3.1](https://github.com/veeqo/activejob-uniqueness/compare/v0.3.0...v0.3.1) - 2023-10-30
28
+
29
+ ### Fixed
30
+
31
+ - [#67](https://github.com/veeqo/activejob-uniqueness/pull/67) Random redis errors on delete_lock by [@laurafeier](https://github.com/laurafeier)
32
+
33
+ ## [0.3.0](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.5...v0.3.0) - 2023-10-20
34
+
35
+ ### Added
36
+ - [#66](https://github.com/veeqo/activejob-uniqueness/pull/66) Activejob 7.1 support by [@laurafeier](https://github.com/laurafeier)
37
+
38
+ ### Changed
39
+ - [#57](https://github.com/veeqo/activejob-uniqueness/pull/57) Upgrade to Redlock 2 & use redis-client by [@bmulholland](https://github.com/bmulholland)
40
+
41
+ ### Removed
42
+ - Support fo Redlock v1 is removed. Switching to `RedisClient` is [a breaking change of Redlock v2](https://github.com/leandromoreira/redlock-rb/blob/main/CHANGELOG.md#200---2023-02-09).
43
+
44
+ ## [0.2.5](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.4...v0.2.5) - 2023-02-01
45
+
46
+ ### Added
47
+ - [#45](https://github.com/veeqo/activejob-uniqueness/pull/45) Add Dependabot for GitHub Actions by [@petergoldstein](https://github.com/petergoldstein)
48
+ - [#51](https://github.com/veeqo/activejob-uniqueness/pull/51) Add support for Sidekiq 7 by [@dwightwatson](https://github.com/dwightwatson)
49
+ - [#52](https://github.com/veeqo/activejob-uniqueness/pull/52) Add Ruby 3.2.0 to the CI matrix by [@petergoldstein](https://github.com/petergoldstein)
50
+
51
+ ### Changed
52
+ - [#46](https://github.com/veeqo/activejob-uniqueness/pull/46) Fix a method name typo in CHANGELOG by [@y-yagi](https://github.com/y-yagi)
53
+
54
+ ## [0.2.4](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.3...v0.2.4) - 2022-06-22
55
+
56
+ ### Added
57
+ - [#43](https://github.com/veeqo/activejob-uniqueness/pull/43) Run rubocop on Github Actions
58
+ - [#44](https://github.com/veeqo/activejob-uniqueness/pull/44) Add ActiveJob::Uniqueness.reset_manager! method to reset lock manager by [@akostadinov](https://github.com/akostadinov)
59
+
60
+ ### Changed
61
+ - [#42](https://github.com/veeqo/activejob-uniqueness/pull/42) Actualize rubies and gems for tests
62
+
63
+ ## [0.2.3](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.2...v0.2.3) - 2022-02-28
64
+
65
+ ### Added
66
+ - [#36](https://github.com/veeqo/activejob-uniqueness/pull/36) Support ActiveJob/Rails 7.0
67
+ - [#37](https://github.com/veeqo/activejob-uniqueness/pull/37) Add Ruby 3.1 to CI by [@petergoldstein](https://github.com/petergoldstein)
68
+
69
+ ## [0.2.2](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.1...v0.2.2) - 2021-10-22
70
+
71
+ ### Added
72
+ - [#32](https://github.com/veeqo/activejob-uniqueness/pull/32) Add ability to set a custom runtime lock key for `:until_and_while_executing` strategy
73
+
74
+ ## [0.2.1](https://github.com/veeqo/activejob-uniqueness/compare/v0.2.0...v0.2.1) - 2021-08-24
75
+
76
+ ### Added
77
+ - [#30](https://github.com/veeqo/activejob-uniqueness/pull/30) Add Sidekiq::JobRecord support (reported by [@dwightwatson](https://github.com/dwightwatson))
78
+
79
+ ## [0.2.0](https://github.com/veeqo/activejob-uniqueness/compare/v0.1.4...v0.2.0) - 2021-05-09
80
+
81
+ ### Added
82
+ - [#22](https://github.com/veeqo/activejob-uniqueness/pull/22) Test with ruby 3.0.1
83
+
84
+ ### Changed
85
+ - [#20](https://github.com/veeqo/activejob-uniqueness/pull/20) **Breaking** Sidekiq patch is not applied automatically anymore
86
+ - [#21](https://github.com/veeqo/activejob-uniqueness/pull/21) Migrate from Travis to Github Actions
87
+ - [#24](https://github.com/veeqo/activejob-uniqueness/pull/24) The default value for `retry_count` of redlock is now 0
88
+ - Require ruby 2.5+
89
+
90
+ ## [0.1.4](https://github.com/veeqo/activejob-uniqueness/compare/v0.1.3...v0.1.4) - 2020-09-22
91
+
92
+ ### Fixed
93
+ - [#11](https://github.com/veeqo/activejob-uniqueness/pull/11) Fix deprecation warnings for ruby 2.7 by [@DanAndreasson](https://github.com/DanAndreasson)
94
+ - [#13](https://github.com/veeqo/activejob-uniqueness/pull/13) Fix deprecation warnings for ruby 2.7
95
+
96
+ ## [0.1.3](https://github.com/veeqo/activejob-uniqueness/compare/v0.1.2...v0.1.3) - 2020-08-17
97
+
98
+ ### Fixed
99
+ - [#7](https://github.com/veeqo/activejob-uniqueness/pull/7) Fix deprecation warnings for ruby 2.7 by [@tonobo](https://github.com/tonobo)
100
+
101
+ ### Changed
102
+ - [#8](https://github.com/veeqo/activejob-uniqueness/pull/8) Use appraisal gem to control gem versions of tests matrix
103
+ - [#9](https://github.com/veeqo/activejob-uniqueness/pull/9) Refactor of Sidekiq API patch. Fixes [#6](https://github.com/veeqo/activejob-uniqueness/issues/6) Rails boot error for version 0.1.2
104
+ - [#10](https://github.com/veeqo/activejob-uniqueness/pull/10) Refactor changelog to comply with Keep a Changelog
105
+
106
+ ## [0.1.2](https://github.com/veeqo/activejob-uniqueness/compare/v0.1.1...v0.1.2) - 2020-07-30
107
+
108
+ ### Added
109
+ - [#5](https://github.com/veeqo/activejob-uniqueness/pull/5) Release lock for Sidekiq adapter by [@vbyno](https://github.com/vbyno)
110
+
111
+ ## [0.1.1](https://github.com/veeqo/activejob-uniqueness/compare/v0.1.0...v0.1.1) - 2020-07-23
112
+
113
+ ### Fixed
114
+ - [#4](https://github.com/veeqo/activejob-uniqueness/pull/4) Fix `NoMethodError` on `Rails.application.eager_load!` in Rails initializer
115
+
116
+ ## [0.1.0](https://github.com/veeqo/activejob-uniqueness/releases/tag/v0.1.0) - 2020-07-05
117
+
118
+ ### Added
119
+ - Job uniqueness for ActiveJob
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Job uniqueness for ActiveJob
2
- [![Build Status](https://travis-ci.com/veeqo/activejob-uniqueness.svg?branch=master)](https://travis-ci.com/veeqo/activejob-uniqueness) [![Gem Version](https://badge.fury.io/rb/activejob-uniqueness.svg)](https://badge.fury.io/rb/activejob-uniqueness)
2
+ [![Build Status](https://github.com/veeqo/activejob-uniqueness/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/veeqo/activejob-uniqueness/actions/workflows/main.yml) [![Gem Version](https://badge.fury.io/rb/activejob-uniqueness.svg)](https://badge.fury.io/rb/activejob-uniqueness)
3
3
 
4
4
  The gem allows to protect job uniqueness with next strategies:
5
5
 
@@ -8,10 +8,16 @@ The gem allows to protect job uniqueness with next strategies:
8
8
  | `until_executing` | when **pushed** to the queue | when **processing starts** |
9
9
  | `until_executed` | when **pushed** to the queue | when the job is **processed successfully** |
10
10
  | `until_expired` | when **pushed** to the queue | when the lock is **expired** |
11
- | `until_and_while_executing` | when **pushed** to the queue | when **processing starts**<br>a runtime lock is acquired to **prevent simultaneous jobs** |
11
+ | `until_and_while_executing` | when **pushed** to the queue | when **processing starts**<br>a runtime lock is acquired to **prevent simultaneous jobs**<br>*has extra options: `runtime_lock_ttl`, `on_runtime_conflict`* |
12
12
  | `while_executing` | when **processing starts** | when the job is **processed**<br>with any result including an error |
13
13
 
14
- Inspired by [SidekiqUniqueJobs](https://github.com/mhenrixon/sidekiq-unique-jobs), uses [Redlock](https://github.com/leandromoreira/redlock-rb) under the hood, sponsored by [Veeqo](https://www.veeqo.com/).
14
+ Inspired by [SidekiqUniqueJobs](https://github.com/mhenrixon/sidekiq-unique-jobs), uses [Redlock](https://github.com/leandromoreira/redlock-rb) under the hood.
15
+
16
+ <p align="center">
17
+ <a href="https://www.veeqo.com/" title="Sponsored by Veeqo">
18
+ <img src="https://static.veeqo.com/assets/sponsored_by_veeqo.png" width="360" />
19
+ </a>
20
+ </p>
15
21
 
16
22
  ## Installation
17
23
 
@@ -21,6 +27,11 @@ Add the `activejob-uniqueness` gem to your Gemfile.
21
27
  gem 'activejob-uniqueness'
22
28
  ```
23
29
 
30
+ If you want jobs unlocking for Sidekiq Web UI, require the patch explicitly. [**Queues cleanup becomes slower!**](#sidekiq-api-support)
31
+ ```ruby
32
+ gem 'activejob-uniqueness', require: 'active_job/uniqueness/sidekiq_patch'
33
+ ```
34
+
24
35
  And run `bundle install` command.
25
36
 
26
37
  ## Configuration
@@ -32,29 +43,115 @@ To override the defaults, create an initializer `config/initializers/active_job_
32
43
  rails generate active_job:uniqueness:install
33
44
  ```
34
45
 
46
+ This gem relies on `redlock` for it's Redis connection, that means **it will not inherit global configuration of `Sidekiq`**. To configure the connection, you can use `config.redlock_servers`, for example to disable SSL verification for Redis/Key-Value cloud providers:
47
+
48
+ ```ruby
49
+ ActiveJob::Uniqueness.configure do |config|
50
+ config.redlock_servers = [
51
+ RedisClient.new(
52
+ url: ENV['REDIS_URL'],
53
+ ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
54
+ )
55
+ ]
56
+ end
57
+ ```
58
+
35
59
  ## Usage
36
60
 
37
- Define uniqueness strategy for your job via `unique` class method:
61
+
62
+ ### Make the job to be unique
38
63
 
39
64
  ```ruby
40
65
  class MyJob < ActiveJob::Base
66
+ # new jobs with the same args will raise error until existing one is executed
41
67
  unique :until_executed
42
68
 
43
- # Custom expiration:
44
- # unique :until_executed, lock_ttl: 3.hours
69
+ def perform(args)
70
+ # work
71
+ end
72
+ end
73
+ ```
45
74
 
46
- # Do not raise error on non unique jobs enqueuing:
47
- # unique :until_executed, on_conflict: :log
75
+ ### Tune uniqueness settings per job
48
76
 
49
- # Handle conflict by custom Proc:
50
- # unique :until_executed, on_conflict: ->(job) { job.logger.info 'Oops' }
77
+ ```ruby
78
+ class MyJob < ActiveJob::Base
79
+ # new jobs with the same args will be logged within 3 hours or until existing one is being executing
80
+ unique :until_executing, lock_ttl: 3.hours, on_conflict: :log
51
81
 
52
- # The :until_and_while_executing strategy supports extra attributes for a runtime lock:
53
- # unique :until_and_while_executing runtime_lock_ttl: 10.minutes, on_runtime_conflict: :log
82
+ def perform(args)
83
+ # work
84
+ end
54
85
  end
55
86
  ```
56
87
 
57
- ActiveJob::Uniqueness allows to manually unlock jobs:
88
+ You can set defaults globally with [the configuration](#configuration)
89
+
90
+ ### Control lock conflicts
91
+
92
+ ```ruby
93
+ class MyJob < ActiveJob::Base
94
+ # Proc gets the job instance including its arguments
95
+ unique :until_executing, on_conflict: ->(job) { job.logger.info "Oops: #{job.arguments}" }
96
+
97
+ def perform(args)
98
+ # work
99
+ end
100
+ end
101
+ ```
102
+
103
+ ### Control redis connection errors
104
+
105
+ ```ruby
106
+ class MyJob < ActiveJob::Base
107
+ # Proc gets the job instance including its arguments, and as keyword arguments the resource(lock key) `resource` and the original error `error`
108
+ unique :until_executing, on_redis_connection_error: ->(job, resource: _, error: _) { job.logger.info "Oops: #{job.arguments}" }
109
+
110
+ def perform(args)
111
+ # work
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Control lock key arguments
117
+
118
+ ```ruby
119
+ class MyJob < ActiveJob::Base
120
+ unique :until_executed
121
+
122
+ def perform(foo, bar, baz)
123
+ # work
124
+ end
125
+
126
+ def lock_key_arguments
127
+ arguments.first(2) # baz is ignored
128
+ end
129
+ end
130
+ ```
131
+
132
+ ### Control the lock key
133
+
134
+ ```ruby
135
+ class MyJob < ActiveJob::Base
136
+ unique :until_executed
137
+
138
+ def perform(foo, bar, baz)
139
+ # work
140
+ end
141
+
142
+ def lock_key
143
+ 'qux' # completely custom lock key
144
+ end
145
+
146
+ def runtime_lock_key
147
+ 'quux' # completely custom runtime lock key for :until_and_while_executing
148
+ end
149
+ end
150
+ ```
151
+
152
+ ### Unlock jobs manually
153
+
154
+ The selected strategy automatically unlocks jobs, but in some cases (e.g. the queue is purged) it is handy to unlock jobs manually.
58
155
 
59
156
  ```ruby
60
157
  # Remove the lock for particular arguments:
@@ -91,7 +188,30 @@ ActiveJob::Uniqueness instruments `ActiveSupport::Notifications` with next event
91
188
 
92
189
  And then writes to `ActiveJob::Base.logger`.
93
190
 
94
- ### ActiveJob prior to version `6.1` will always log `Enqueued MyJob (Job ID) ...` even if the callback chain was halted. [Details](https://github.com/rails/rails/pull/37830)
191
+ **ActiveJob prior to version `6.1` will always log `Enqueued MyJob (Job ID) ...` even if the callback chain is halted. [Details](https://github.com/rails/rails/pull/37830)**
192
+
193
+ ## Testing
194
+
195
+ Run redis server (in separate console):
196
+ ```
197
+ docker run --rm -p 6379:6379 redis
198
+ ```
199
+
200
+ Run tests with:
201
+
202
+ ```sh
203
+ bundle
204
+ rake
205
+ ```
206
+
207
+ ## Sidekiq API support
208
+
209
+ ActiveJob::Uniqueness supports Sidekiq API to unset job locks on queues cleanup (e.g. via Sidekiq Web UI). Starting Sidekiq 5.1 job death also triggers locks cleanup.
210
+ Take into account that **[big queues cleanup becomes much slower](https://github.com/veeqo/activejob-uniqueness/issues/16)** because each job is being unlocked individually. In order to activate Sidekiq API patch require it explicitly in your Gemfile:
211
+
212
+ ```ruby
213
+ gem 'activejob-uniqueness', require: 'active_job/uniqueness/sidekiq_patch'
214
+ ```
95
215
 
96
216
  ## Contributing
97
217
 
@@ -100,3 +220,9 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/veeqo/
100
220
  ## License
101
221
 
102
222
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
223
+
224
+ ## About [Veeqo](https://www.veeqo.com)
225
+
226
+ At Veeqo, our team of Engineers is on a mission to create a world-class Inventory and Shipping platform, built to the highest standards in best coding practices. We are a growing team, looking for other passionate developers to [join us](https://veeqo-ltd.breezy.hr/) on our journey. If you're looking for a career working for one of the most exciting tech companies in ecommerce, we want to hear from you.
227
+
228
+ [Veeqo developers blog](https://devs.veeqo.com)
@@ -16,7 +16,7 @@ module ActiveJob
16
16
  # end
17
17
  # end
18
18
  #
19
- module Patch
19
+ module ActiveJobPatch
20
20
  extend ActiveSupport::Concern
21
21
 
22
22
  class_methods do
@@ -27,6 +27,7 @@ module ActiveJob
27
27
  def unique(strategy, options = {})
28
28
  validate_on_conflict_action!(options[:on_conflict])
29
29
  validate_on_conflict_action!(options[:on_runtime_conflict])
30
+ validate_on_redis_connection_error!(options[:on_redis_connection_error])
30
31
 
31
32
  self.lock_strategy_class = ActiveJob::Uniqueness::Strategies.lookup(strategy)
32
33
  self.lock_options = options
@@ -40,7 +41,9 @@ module ActiveJob
40
41
 
41
42
  private
42
43
 
43
- delegate :validate_on_conflict_action!, to: :'ActiveJob::Uniqueness.config'
44
+ delegate :validate_on_conflict_action!,
45
+ :validate_on_redis_connection_error!,
46
+ to: :'ActiveJob::Uniqueness.config'
44
47
  end
45
48
 
46
49
  included do
@@ -55,7 +58,7 @@ module ActiveJob
55
58
  end
56
59
 
57
60
  def lock_strategy
58
- @lock_strategy ||= lock_strategy_class.new(lock_options.merge(lock_key: lock_key, job: self))
61
+ @lock_strategy ||= lock_strategy_class.new(job: self)
59
62
  end
60
63
 
61
64
  # Override in your job class if you want to customize arguments set for a digest.
@@ -64,21 +67,16 @@ module ActiveJob
64
67
  end
65
68
 
66
69
  # Override lock_key method in your job class if you want to build completely custom lock key.
67
- delegate :lock_key, to: :lock_key_generator
70
+ delegate :lock_key, :runtime_lock_key, to: :lock_key_generator
68
71
 
69
72
  def lock_key_generator
70
- ActiveJob::Uniqueness::LockKey.new job_class_name: self.class.name,
71
- arguments: lock_key_arguments
73
+ @lock_key_generator ||= ActiveJob::Uniqueness::LockKey.new job_class_name: self.class.name,
74
+ arguments: lock_key_arguments
72
75
  end
73
76
  end
74
77
 
75
78
  ActiveSupport.on_load(:active_job) do
76
- ActiveJob::Base.include ActiveJob::Uniqueness::Patch
77
-
78
- if ::ActiveJob.const_defined?(:Railtie) &&
79
- ActiveJob::Railtie.config.active_job.queue_adapter.to_sym == :sidekiq
80
- require_relative 'patch/sidekiq'
81
- end
79
+ ActiveJob::Base.include ActiveJob::Uniqueness::ActiveJobPatch
82
80
  end
83
81
  end
84
82
  end
@@ -11,14 +11,19 @@ module ActiveJob
11
11
  class Configuration
12
12
  include ActiveSupport::Configurable
13
13
 
14
- config_accessor(:lock_ttl) { 1.day }
14
+ config_accessor(:lock_ttl) { 86_400 } # 1.day
15
15
  config_accessor(:lock_prefix) { 'activejob_uniqueness' }
16
16
  config_accessor(:on_conflict) { :raise }
17
- config_accessor(:digest_method) { OpenSSL::Digest::MD5 }
17
+ config_accessor(:on_redis_connection_error) { :raise }
18
18
  config_accessor(:redlock_servers) { [ENV.fetch('REDIS_URL', 'redis://localhost:6379')] }
19
- config_accessor(:redlock_options) { {} }
19
+ config_accessor(:redlock_options) { { retry_count: 0 } }
20
20
  config_accessor(:lock_strategies) { {} }
21
21
 
22
+ config_accessor(:digest_method) do
23
+ require 'openssl'
24
+ OpenSSL::Digest::MD5
25
+ end
26
+
22
27
  def on_conflict=(action)
23
28
  validate_on_conflict_action!(action)
24
29
 
@@ -30,6 +35,18 @@ module ActiveJob
30
35
 
31
36
  raise ActiveJob::Uniqueness::InvalidOnConflictAction, "Unexpected '#{action}' action on conflict"
32
37
  end
38
+
39
+ def on_redis_connection_error=(action)
40
+ validate_on_redis_connection_error!(action)
41
+
42
+ config.on_redis_connection_error = action
43
+ end
44
+
45
+ def validate_on_redis_connection_error!(action)
46
+ return if action.nil? || action == :raise || action.respond_to?(:call)
47
+
48
+ raise ActiveJob::Uniqueness::InvalidOnConflictAction, "Unexpected '#{action}' action on_redis_connection_error"
49
+ end
33
50
  end
34
51
  end
35
52
  end
@@ -28,11 +28,19 @@ module ActiveJob
28
28
  ].join(':')
29
29
  end
30
30
 
31
+ # used only by :until_and_while_executing strategy
32
+ def runtime_lock_key
33
+ [
34
+ lock_key,
35
+ 'runtime'
36
+ ].join(':')
37
+ end
38
+
31
39
  def wildcard_key
32
40
  [
33
41
  lock_prefix,
34
42
  normalized_job_class_name,
35
- arguments.any? ? arguments_key_part + '*' : '*'
43
+ arguments.any? ? "#{arguments_key_part}*" : '*'
36
44
  ].compact.join(':')
37
45
  end
38
46
 
@@ -9,24 +9,40 @@ module ActiveJob
9
9
  # Unlocks a resource by resource only.
10
10
  def delete_lock(resource)
11
11
  @servers.each do |server|
12
- server.instance_variable_get(:'@redis').with do |conn|
13
- conn.del resource
12
+ synced_redis_connection(server) do |conn|
13
+ conn.call('DEL', resource)
14
14
  end
15
15
  end
16
16
 
17
17
  true
18
18
  end
19
19
 
20
+ DELETE_LOCKS_SCAN_COUNT = 1000
21
+
20
22
  # Unlocks multiple resources by key wildcard.
21
23
  def delete_locks(wildcard)
22
24
  @servers.each do |server|
23
- server.instance_variable_get(:'@redis').with do |conn|
24
- conn.scan_each(match: wildcard).each { |key| conn.del key }
25
+ synced_redis_connection(server) do |conn|
26
+ cursor = 0
27
+ while cursor != '0'
28
+ cursor, keys = conn.call('SCAN', cursor, 'MATCH', wildcard, 'COUNT', DELETE_LOCKS_SCAN_COUNT)
29
+ conn.call('UNLINK', *keys) unless keys.empty?
30
+ end
25
31
  end
26
32
  end
27
33
 
28
34
  true
29
35
  end
36
+
37
+ private
38
+
39
+ def synced_redis_connection(server, &block)
40
+ if server.respond_to?(:synchronize)
41
+ server.synchronize(&block)
42
+ else
43
+ server.instance_variable_get(:@redis).with(&block)
44
+ end
45
+ end
30
46
  end
31
47
  end
32
48
  end