sidekiq-unique-jobs 5.0.2 → 5.0.11
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.
- checksums.yaml +5 -5
- data/.gitignore +8 -0
- data/.rubocop.yml +20 -13
- data/.simplecov +1 -1
- data/.travis.yml +30 -20
- data/Appraisals +10 -2
- data/CHANGELOG.md +33 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +13 -12
- data/LICENSE.txt +21 -0
- data/README.md +48 -4
- data/Rakefile +0 -1
- data/bin/bench +1 -1
- data/lib/sidekiq/simulator.rb +4 -10
- data/lib/sidekiq-unique-jobs.rb +16 -6
- data/lib/sidekiq_unique_jobs/cli.rb +14 -12
- data/lib/sidekiq_unique_jobs/client/middleware.rb +2 -0
- data/lib/sidekiq_unique_jobs/config.rb +2 -0
- data/lib/sidekiq_unique_jobs/constants.rb +20 -17
- data/lib/sidekiq_unique_jobs/core_ext.rb +18 -0
- data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +2 -0
- data/lib/sidekiq_unique_jobs/lock/until_executed.rb +4 -5
- data/lib/sidekiq_unique_jobs/lock/until_executing.rb +2 -0
- data/lib/sidekiq_unique_jobs/lock/until_timeout.rb +2 -0
- data/lib/sidekiq_unique_jobs/lock/while_executing.rb +10 -9
- data/lib/sidekiq_unique_jobs/lock.rb +2 -0
- data/lib/sidekiq_unique_jobs/middleware.rb +2 -0
- data/lib/sidekiq_unique_jobs/normalizer.rb +3 -1
- data/lib/sidekiq_unique_jobs/options_with_fallback.rb +22 -3
- data/lib/sidekiq_unique_jobs/run_lock_failed.rb +2 -0
- data/lib/sidekiq_unique_jobs/script_mock.rb +16 -15
- data/lib/sidekiq_unique_jobs/scripts/acquire_lock.rb +2 -0
- data/lib/sidekiq_unique_jobs/scripts/release_lock.rb +2 -0
- data/lib/sidekiq_unique_jobs/scripts.rb +17 -12
- data/lib/sidekiq_unique_jobs/server/middleware.rb +2 -0
- data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +4 -14
- data/lib/sidekiq_unique_jobs/testing/sidekiq_overrides.rb +2 -0
- data/lib/sidekiq_unique_jobs/testing.rb +4 -2
- data/lib/sidekiq_unique_jobs/timeout_calculator.rb +2 -0
- data/lib/sidekiq_unique_jobs/unique_args.rb +27 -14
- data/lib/sidekiq_unique_jobs/unlockable.rb +6 -6
- data/lib/sidekiq_unique_jobs/util.rb +34 -14
- data/lib/sidekiq_unique_jobs/version.rb +3 -1
- data/redis/acquire_lock.lua +1 -1
- data/sidekiq-unique-jobs.gemspec +27 -23
- metadata +44 -212
- data/LICENSE +0 -13
- data/circle.yml +0 -41
- data/gemfiles/sidekiq_4.0.gemfile +0 -22
- data/gemfiles/sidekiq_4.1.gemfile +0 -22
- data/gemfiles/sidekiq_4.2.gemfile +0 -22
- data/gemfiles/sidekiq_5.0.gemfile +0 -22
- data/gemfiles/sidekiq_develop.gemfile +0 -22
- data/rails_example/.env +0 -12
- data/rails_example/.env.test +0 -12
- data/rails_example/.gitignore +0 -13
- data/rails_example/.rspec +0 -2
- data/rails_example/Gemfile +0 -38
- data/rails_example/Procfile +0 -2
- data/rails_example/README.rdoc +0 -28
- data/rails_example/Rakefile +0 -6
- data/rails_example/app/assets/images/.keep +0 -0
- data/rails_example/app/assets/javascripts/application.js +0 -16
- data/rails_example/app/assets/stylesheets/application.css +0 -15
- data/rails_example/app/channels/appearance_channel.rb +0 -17
- data/rails_example/app/channels/application_cable/channel.rb +0 -4
- data/rails_example/app/channels/application_cable/connection.rb +0 -9
- data/rails_example/app/channels/post_channel.rb +0 -5
- data/rails_example/app/controllers/application_controller.rb +0 -5
- data/rails_example/app/controllers/concerns/.keep +0 -0
- data/rails_example/app/controllers/work_controller.rb +0 -39
- data/rails_example/app/helpers/application_helper.rb +0 -2
- data/rails_example/app/mailers/.keep +0 -0
- data/rails_example/app/models/.keep +0 -0
- data/rails_example/app/models/application_record.rb +0 -3
- data/rails_example/app/models/concerns/.keep +0 -0
- data/rails_example/app/models/guest.rb +0 -18
- data/rails_example/app/models/post.rb +0 -2
- data/rails_example/app/views/layouts/application.html.erb +0 -15
- data/rails_example/app/workers/simple_worker.rb +0 -15
- data/rails_example/app/workers/slow_until_executing_worker.rb +0 -15
- data/rails_example/app/workers/spawn_simple_worker.rb +0 -10
- data/rails_example/app/workers/while_executing_worker.rb +0 -12
- data/rails_example/app/workers/without_args_worker.rb +0 -16
- data/rails_example/app/workers/without_argument_worker.rb +0 -12
- data/rails_example/bin/bundle +0 -3
- data/rails_example/bin/check_or_setup_db +0 -56
- data/rails_example/bin/docker-setup +0 -20
- data/rails_example/bin/rails +0 -4
- data/rails_example/bin/rake +0 -4
- data/rails_example/bin/setup +0 -34
- data/rails_example/bin/update +0 -29
- data/rails_example/cable.ru +0 -6
- data/rails_example/common-services.yml +0 -52
- data/rails_example/config/application.rb +0 -27
- data/rails_example/config/boot.rb +0 -3
- data/rails_example/config/cable.yml +0 -9
- data/rails_example/config/database.docker.yml +0 -12
- data/rails_example/config/database.yml +0 -19
- data/rails_example/config/environment.rb +0 -5
- data/rails_example/config/environments/development.rb +0 -54
- data/rails_example/config/environments/production.rb +0 -86
- data/rails_example/config/environments/test.rb +0 -42
- data/rails_example/config/initializers/application_controller_renderer.rb +0 -6
- data/rails_example/config/initializers/assets.rb +0 -11
- data/rails_example/config/initializers/backtrace_silencers.rb +0 -9
- data/rails_example/config/initializers/cookies_serializer.rb +0 -5
- data/rails_example/config/initializers/filter_parameter_logging.rb +0 -4
- data/rails_example/config/initializers/inflections.rb +0 -16
- data/rails_example/config/initializers/mime_types.rb +0 -4
- data/rails_example/config/initializers/new_framework_defaults.rb +0 -23
- data/rails_example/config/initializers/session_store.rb +0 -3
- data/rails_example/config/initializers/sidekiq.rb +0 -13
- data/rails_example/config/initializers/wrap_parameters.rb +0 -14
- data/rails_example/config/locales/en.yml +0 -23
- data/rails_example/config/puma.rb +0 -38
- data/rails_example/config/routes.rb +0 -8
- data/rails_example/config/secrets.yml +0 -22
- data/rails_example/config/sidekiq.yml +0 -6
- data/rails_example/config/spring.rb +0 -6
- data/rails_example/config.ru +0 -4
- data/rails_example/db/migrate/20160724111322_create_posts.rb +0 -12
- data/rails_example/db/schema.rb +0 -25
- data/rails_example/db/seeds.rb +0 -7
- data/rails_example/dev-entrypoint.sh +0 -55
- data/rails_example/dev.env +0 -12
- data/rails_example/docker/rails.Dockerfile +0 -27
- data/rails_example/docker-compose.yml +0 -71
- data/rails_example/lib/assets/.keep +0 -0
- data/rails_example/lib/tasks/.keep +0 -0
- data/rails_example/log/.keep +0 -0
- data/rails_example/public/404.html +0 -67
- data/rails_example/public/422.html +0 -67
- data/rails_example/public/500.html +0 -66
- data/rails_example/public/favicon.ico +0 -0
- data/rails_example/public/robots.txt +0 -5
- data/rails_example/simple.ru +0 -12
- data/rails_example/spec/controllers/work_controller_mock_spec.rb +0 -91
- data/rails_example/spec/controllers/work_controller_spec.rb +0 -77
- data/rails_example/spec/factories/posts.rb +0 -8
- data/rails_example/spec/models/post_spec.rb +0 -4
- data/rails_example/spec/rails_helper.rb +0 -20
- data/rails_example/spec/spec_helper.rb +0 -20
- data/rails_example/spec/support/sidekiq_meta.rb +0 -12
- data/rails_example/spec/workers/simple_worker_spec.rb +0 -4
- data/rails_example/vendor/assets/javascripts/.keep +0 -0
- data/rails_example/vendor/assets/stylesheets/.keep +0 -0
- data/spec/jobs/another_unique_job.rb +0 -13
- data/spec/jobs/custom_queue_job.rb +0 -5
- data/spec/jobs/custom_queue_job_with_filter_method.rb +0 -7
- data/spec/jobs/custom_queue_job_with_filter_proc.rb +0 -10
- data/spec/jobs/expiring_job.rb +0 -4
- data/spec/jobs/inline_worker.rb +0 -8
- data/spec/jobs/just_a_worker.rb +0 -7
- data/spec/jobs/long_running_job.rb +0 -6
- data/spec/jobs/main_job.rb +0 -7
- data/spec/jobs/my_job.rb +0 -12
- data/spec/jobs/my_unique_job.rb +0 -11
- data/spec/jobs/my_unique_job_with_filter_method.rb +0 -17
- data/spec/jobs/my_unique_job_with_filter_proc.rb +0 -15
- data/spec/jobs/notify_worker.rb +0 -10
- data/spec/jobs/plain_class.rb +0 -3
- data/spec/jobs/simple_worker.rb +0 -11
- data/spec/jobs/spawn_simple_worker.rb +0 -8
- data/spec/jobs/test_class.rb +0 -3
- data/spec/jobs/unique_job_with_conditional_parameter.rb +0 -14
- data/spec/jobs/unique_job_with_filter_method.rb +0 -18
- data/spec/jobs/unique_job_with_nil_unique_args.rb +0 -16
- data/spec/jobs/unique_job_with_no_unique_args_method.rb +0 -12
- data/spec/jobs/unique_job_withthout_unique_args_parameter.rb +0 -14
- data/spec/jobs/unique_on_all_queues_job.rb +0 -13
- data/spec/jobs/until_and_while_executing_job.rb +0 -7
- data/spec/jobs/until_executed_job.rb +0 -17
- data/spec/jobs/until_executing_job.rb +0 -7
- data/spec/jobs/until_global_timeout_job.rb +0 -8
- data/spec/jobs/until_timeout_job.rb +0 -8
- data/spec/jobs/while_executing_job.rb +0 -12
- data/spec/jobs/without_argument_job.rb +0 -9
- data/spec/lib/sidekiq_unique_jobs/cli_spec.rb +0 -183
- data/spec/lib/sidekiq_unique_jobs/client/middleware_spec.rb +0 -316
- data/spec/lib/sidekiq_unique_jobs/config_spec.rb +0 -84
- data/spec/lib/sidekiq_unique_jobs/core_ext_spec.rb +0 -25
- data/spec/lib/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +0 -42
- data/spec/lib/sidekiq_unique_jobs/lock/until_executed_spec.rb +0 -37
- data/spec/lib/sidekiq_unique_jobs/lock/until_timeout_spec.rb +0 -26
- data/spec/lib/sidekiq_unique_jobs/lock/while_executing_spec.rb +0 -86
- data/spec/lib/sidekiq_unique_jobs/normalizer_spec.rb +0 -21
- data/spec/lib/sidekiq_unique_jobs/options_with_fallback_spec.rb +0 -113
- data/spec/lib/sidekiq_unique_jobs/queue_lock_timeout_calculator_spec.rb +0 -47
- data/spec/lib/sidekiq_unique_jobs/run_lock_timeout_calculator_spec.rb +0 -36
- data/spec/lib/sidekiq_unique_jobs/script_mock_spec.rb +0 -88
- data/spec/lib/sidekiq_unique_jobs/scripts/acquire_lock_spec.rb +0 -50
- data/spec/lib/sidekiq_unique_jobs/scripts/release_lock_spec.rb +0 -41
- data/spec/lib/sidekiq_unique_jobs/scripts_spec.rb +0 -68
- data/spec/lib/sidekiq_unique_jobs/server/middleware_spec.rb +0 -78
- data/spec/lib/sidekiq_unique_jobs/sidekiq_testing_enabled_spec.rb +0 -164
- data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb +0 -75
- data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_jobs_spec.rb +0 -41
- data/spec/lib/sidekiq_unique_jobs/timeout_calculator_spec.rb +0 -70
- data/spec/lib/sidekiq_unique_jobs/unique_args_spec.rb +0 -257
- data/spec/lib/sidekiq_unique_jobs/unlockable_spec.rb +0 -37
- data/spec/lib/sidekiq_unique_jobs/util_spec.rb +0 -81
- data/spec/spec_helper.rb +0 -92
- data/spec/support/matchers/redis_matchers.rb +0 -29
- data/spec/support/ruby_meta.rb +0 -17
- data/spec/support/sidekiq_meta.rb +0 -30
- data/spec/support/unique_macros.rb +0 -71
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SidekiqUniqueJobs
|
2
4
|
module Lock
|
3
5
|
class UntilExecuted
|
4
|
-
OK ||= 'OK'
|
6
|
+
OK ||= 'OK'
|
5
7
|
|
6
8
|
include SidekiqUniqueJobs::Unlockable
|
7
9
|
|
@@ -36,9 +38,7 @@ module SidekiqUniqueJobs
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def lock(scope)
|
39
|
-
if scope.to_sym != :client
|
40
|
-
raise ArgumentError, "#{scope} middleware can't #{__method__} #{unique_key}"
|
41
|
-
end
|
41
|
+
raise ArgumentError, "#{scope} middleware can't #{__method__} #{unique_key}" if scope.to_sym != :client
|
42
42
|
|
43
43
|
Scripts::AcquireLock.execute(
|
44
44
|
redis_pool,
|
@@ -47,7 +47,6 @@ module SidekiqUniqueJobs
|
|
47
47
|
max_lock_time,
|
48
48
|
)
|
49
49
|
end
|
50
|
-
# rubocop:enable MethodLength
|
51
50
|
|
52
51
|
def unique_key
|
53
52
|
@unique_key ||= UniqueArgs.digest(item)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SidekiqUniqueJobs
|
2
4
|
module Lock
|
3
5
|
class WhileExecuting
|
@@ -7,22 +9,21 @@ module SidekiqUniqueJobs
|
|
7
9
|
|
8
10
|
def initialize(item, redis_pool = nil)
|
9
11
|
@item = item
|
10
|
-
@mutex = Mutex.new
|
11
12
|
@redis_pool = redis_pool
|
12
13
|
@unique_digest = "#{create_digest}:run"
|
14
|
+
@mutex = Mutex.new
|
13
15
|
end
|
14
16
|
|
15
17
|
def synchronize
|
16
|
-
@mutex.
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
@mutex.synchronize do
|
19
|
+
sleep 0.1 until locked?
|
20
|
+
yield
|
21
|
+
end
|
20
22
|
rescue Sidekiq::Shutdown
|
21
23
|
logger.fatal { "the unique_key: #{@unique_digest} needs to be unlocked manually" }
|
22
24
|
raise
|
23
25
|
ensure
|
24
|
-
SidekiqUniqueJobs.connection(@redis_pool) { |
|
25
|
-
@mutex.unlock
|
26
|
+
SidekiqUniqueJobs.connection(@redis_pool) { |conn| conn.del @unique_digest }
|
26
27
|
end
|
27
28
|
|
28
29
|
def locked?
|
@@ -42,8 +43,8 @@ module SidekiqUniqueJobs
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def create_digest
|
45
|
-
@
|
46
|
-
@
|
46
|
+
@create_digest ||= @item[UNIQUE_DIGEST_KEY]
|
47
|
+
@create_digest ||= SidekiqUniqueJobs::UniqueArgs.digest(@item)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SidekiqUniqueJobs
|
2
4
|
module OptionsWithFallback
|
3
5
|
def self.included(base)
|
4
|
-
base.
|
5
|
-
base.lock_cache ||= {}
|
6
|
+
base.send(:extend, SidekiqUniqueJobs::OptionsWithFallback::ClassMethods)
|
6
7
|
end
|
7
8
|
|
8
9
|
def unique_enabled?
|
@@ -22,7 +23,7 @@ module SidekiqUniqueJobs
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def lock_class
|
25
|
-
lock_cache[unique_lock.to_sym] ||= "SidekiqUniqueJobs::Lock::#{unique_lock.to_s.classify}"
|
26
|
+
lock_cache[unique_lock.to_sym] ||= Object.const_get("SidekiqUniqueJobs::Lock::#{unique_lock.to_s.classify}")
|
26
27
|
end
|
27
28
|
|
28
29
|
def unique_lock
|
@@ -45,11 +46,29 @@ module SidekiqUniqueJobs
|
|
45
46
|
hash[key]
|
46
47
|
end
|
47
48
|
|
49
|
+
def lock_cache
|
50
|
+
self.class.lock_cache
|
51
|
+
end
|
52
|
+
|
53
|
+
def lock_cache=(obj)
|
54
|
+
self.class.lock_cache = obj
|
55
|
+
end
|
56
|
+
|
48
57
|
def options
|
49
58
|
@options ||= worker_class.get_sidekiq_options if worker_class.respond_to?(:get_sidekiq_options)
|
50
59
|
@options ||= Sidekiq.default_worker_options
|
51
60
|
@options ||= {}
|
52
61
|
@options &&= @options.stringify_keys
|
53
62
|
end
|
63
|
+
|
64
|
+
module ClassMethods
|
65
|
+
def lock_cache
|
66
|
+
@lock_cache ||= {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def lock_cache=(obj)
|
70
|
+
@lock_cache = obj
|
71
|
+
end
|
72
|
+
end
|
54
73
|
end
|
55
74
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
2
4
|
require 'digest/sha1'
|
3
5
|
|
@@ -13,53 +15,52 @@ module SidekiqUniqueJobs
|
|
13
15
|
end
|
14
16
|
|
15
17
|
def acquire_lock(redis_pool, options = {})
|
16
|
-
connection(redis_pool) do |
|
18
|
+
connection(redis_pool) do |conn|
|
17
19
|
unique_key = options[:keys][0]
|
18
20
|
job_id = options[:argv][0]
|
19
21
|
expires = options[:argv][1].to_i
|
20
|
-
stored_jid =
|
22
|
+
stored_jid = conn.get(unique_key)
|
21
23
|
|
22
24
|
return (stored_jid == job_id) ? 1 : 0 if stored_jid
|
25
|
+
return 0 unless conn.set(unique_key, job_id, nx: true, ex: expires)
|
26
|
+
|
27
|
+
conn.hsetnx(SidekiqUniqueJobs::HASH_KEY, job_id, unique_key)
|
23
28
|
|
24
|
-
return 0 unless redis.set(unique_key, job_id, nx: true, ex: expires)
|
25
|
-
redis.hsetnx(SidekiqUniqueJobs::HASH_KEY, job_id, unique_key)
|
26
29
|
return 1
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def release_lock(redis_pool, options = {})
|
31
|
-
connection(redis_pool) do |
|
34
|
+
connection(redis_pool) do |conn|
|
32
35
|
unique_key = options[:keys][0]
|
33
36
|
job_id = options[:argv][0]
|
34
|
-
stored_jid =
|
37
|
+
stored_jid = conn.get(unique_key)
|
35
38
|
|
36
39
|
return -1 unless stored_jid
|
37
40
|
return 0 unless stored_jid == job_id || stored_jid == '2'
|
38
41
|
|
39
|
-
|
40
|
-
|
42
|
+
conn.del(unique_key)
|
43
|
+
conn.hdel(SidekiqUniqueJobs::HASH_KEY, job_id)
|
44
|
+
|
41
45
|
return 1
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
45
49
|
def synchronize(redis_pool, options = {})
|
46
|
-
connection(redis_pool) do |
|
50
|
+
connection(redis_pool) do |conn|
|
47
51
|
unique_key = options[:keys][0]
|
48
52
|
time = options[:argv][0].to_i
|
49
53
|
expires = options[:argv][1].to_f
|
50
54
|
|
51
|
-
return 1 if
|
55
|
+
return 1 if conn.set(unique_key, time + expires, nx: true, ex: expires)
|
52
56
|
|
53
|
-
stored_time =
|
57
|
+
stored_time = conn.get(unique_key)
|
54
58
|
if stored_time && stored_time < time
|
55
|
-
if
|
56
|
-
return 1
|
57
|
-
end
|
59
|
+
return 1 if conn.set(unique_key, time + expires, xx: true, ex: expires)
|
58
60
|
end
|
59
61
|
|
60
62
|
return 0
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
64
|
-
# rubocop:enable MethodLength
|
65
66
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
2
4
|
require 'digest/sha1'
|
3
5
|
require 'concurrent/map'
|
@@ -22,22 +24,25 @@ module SidekiqUniqueJobs
|
|
22
24
|
extend SingleForwardable
|
23
25
|
def_delegators :SidekiqUniqueJobs, :connection, :logger
|
24
26
|
|
25
|
-
def call(file_name, redis_pool, options = {})
|
26
|
-
|
27
|
-
if SCRIPT_SHAS[file_name].nil?
|
28
|
-
SCRIPT_SHAS[file_name] = redis.script(:load, script_source(file_name))
|
29
|
-
end
|
30
|
-
redis.evalsha(SCRIPT_SHAS[file_name], options)
|
31
|
-
end
|
27
|
+
def call(file_name, redis_pool, options = {})
|
28
|
+
internal_call(file_name, redis_pool, options)
|
32
29
|
rescue Redis::CommandError => ex
|
33
|
-
|
30
|
+
handle_error(ex, file_name, redis_pool, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def internal_call(file_name, redis_pool, options = {})
|
34
|
+
connection(redis_pool) do |conn|
|
35
|
+
SCRIPT_SHAS[file_name] = conn.script(:load, script_source(file_name)) if SCRIPT_SHAS[file_name].nil?
|
36
|
+
conn.evalsha(SCRIPT_SHAS[file_name], options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_error(exception, file_name, redis_pool, options = {})
|
41
|
+
if exception.message == 'NOSCRIPT No matching script. Please use EVAL.' # rubocop:disable Style/GuardClause
|
34
42
|
SCRIPT_SHAS.delete(file_name)
|
35
43
|
call(file_name, redis_pool, options)
|
36
|
-
raise
|
37
44
|
else
|
38
|
-
raise ScriptError,
|
39
|
-
"#{file_name}.lua\n\n#{ex.message}\n\n#{script_source(file_name)}" \
|
40
|
-
"#{ex.backtrace.join("\n")}"
|
45
|
+
raise ScriptError, "Problem compiling #{file_name}. Invalid LUA syntax?"
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sidekiq/api'
|
2
4
|
|
3
5
|
module Sidekiq
|
@@ -5,7 +7,6 @@ module Sidekiq
|
|
5
7
|
module UniqueExtension
|
6
8
|
def self.included(base)
|
7
9
|
base.class_eval do
|
8
|
-
include SidekiqUniqueJobs::Unlockable
|
9
10
|
alias_method :delete_orig, :delete
|
10
11
|
alias_method :delete, :delete_ext
|
11
12
|
alias_method :remove_job_orig, :remove_job
|
@@ -34,7 +35,6 @@ module Sidekiq
|
|
34
35
|
module UniqueExtension
|
35
36
|
def self.included(base)
|
36
37
|
base.class_eval do
|
37
|
-
include SidekiqUniqueJobs::Unlockable
|
38
38
|
alias_method :delete_orig, :delete
|
39
39
|
alias_method :delete, :delete_ext
|
40
40
|
end
|
@@ -43,13 +43,6 @@ module Sidekiq
|
|
43
43
|
def delete_ext
|
44
44
|
SidekiqUniqueJobs::Unlockable.unlock(item) if delete_orig
|
45
45
|
end
|
46
|
-
|
47
|
-
def remove_job_ext
|
48
|
-
remove_job_orig do |message|
|
49
|
-
SidekiqUniqueJobs::Unlockable.unlock(Sidekiq.load_json(message))
|
50
|
-
yield message
|
51
|
-
end
|
52
|
-
end
|
53
46
|
end
|
54
47
|
include UniqueExtension
|
55
48
|
end
|
@@ -58,15 +51,14 @@ module Sidekiq
|
|
58
51
|
module UniqueExtension
|
59
52
|
def self.included(base)
|
60
53
|
base.class_eval do
|
61
|
-
include SidekiqUniqueJobs::Unlockable
|
62
54
|
alias_method :delete_orig, :delete
|
63
55
|
alias_method :delete, :delete_ext
|
64
56
|
end
|
65
57
|
end
|
66
58
|
|
67
59
|
def delete_ext
|
68
|
-
SidekiqUniqueJobs::Unlockable.unlock(item)
|
69
60
|
delete_orig
|
61
|
+
SidekiqUniqueJobs::Unlockable.unlock(item)
|
70
62
|
end
|
71
63
|
end
|
72
64
|
|
@@ -77,7 +69,6 @@ module Sidekiq
|
|
77
69
|
module UniqueExtension
|
78
70
|
def self.included(base)
|
79
71
|
base.class_eval do
|
80
|
-
include SidekiqUniqueJobs::Unlockable
|
81
72
|
alias_method :clear_orig, :clear
|
82
73
|
alias_method :clear, :clear_ext
|
83
74
|
end
|
@@ -96,7 +87,6 @@ module Sidekiq
|
|
96
87
|
module UniqueExtension
|
97
88
|
def self.included(base)
|
98
89
|
base.class_eval do
|
99
|
-
include SidekiqUniqueJobs::Unlockable
|
100
90
|
if base.method_defined?(:clear)
|
101
91
|
alias_method :clear_orig, :clear
|
102
92
|
alias_method :clear, :clear_ext
|
@@ -115,7 +105,7 @@ module Sidekiq
|
|
115
105
|
end
|
116
106
|
|
117
107
|
def delete_by_value_ext(name, value)
|
118
|
-
SidekiqUniqueJobs::Unlockable.unlock(
|
108
|
+
SidekiqUniqueJobs::Unlockable.unlock(Sidekiq.load_json(value)) if delete_by_value_orig(name, value)
|
119
109
|
end
|
120
110
|
end
|
121
111
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sidekiq_unique_jobs/testing/sidekiq_overrides'
|
2
4
|
require 'sidekiq_unique_jobs/script_mock'
|
3
5
|
|
@@ -44,8 +46,8 @@ module SidekiqUniqueJobs
|
|
44
46
|
worker_class = SidekiqUniqueJobs.worker_class_constantize(worker_class)
|
45
47
|
|
46
48
|
if Sidekiq::Testing.inline?
|
47
|
-
|
48
|
-
|
49
|
+
call_real(worker_class, item, queue, redis_pool) do
|
50
|
+
_server.call(worker_class.new, item, queue, redis_pool) do
|
49
51
|
yield
|
50
52
|
end
|
51
53
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest'
|
2
4
|
require 'sidekiq_unique_jobs/normalizer'
|
3
5
|
|
@@ -5,9 +7,8 @@ module SidekiqUniqueJobs
|
|
5
7
|
# This class exists to be testable and the entire api should be considered private
|
6
8
|
# rubocop:disable ClassLength
|
7
9
|
class UniqueArgs
|
8
|
-
CLASS_NAME = 'SidekiqUniqueJobs::UniqueArgs'
|
10
|
+
CLASS_NAME = 'SidekiqUniqueJobs::UniqueArgs'
|
9
11
|
extend Forwardable
|
10
|
-
include Normalizer
|
11
12
|
|
12
13
|
def_delegators :SidekiqUniqueJobs, :config, :worker_class_constantize
|
13
14
|
def_delegators :Sidekiq, :logger
|
@@ -16,9 +17,9 @@ module SidekiqUniqueJobs
|
|
16
17
|
new(item).unique_digest
|
17
18
|
end
|
18
19
|
|
19
|
-
def initialize(
|
20
|
+
def initialize(item)
|
20
21
|
Sidekiq::Logging.with_context(CLASS_NAME) do
|
21
|
-
@item =
|
22
|
+
@item = item
|
22
23
|
@worker_class ||= worker_class_constantize(@item[CLASS_KEY])
|
23
24
|
@item[UNIQUE_PREFIX_KEY] ||= unique_prefix
|
24
25
|
@item[UNIQUE_ARGS_KEY] = unique_args(@item[ARGS_KEY])
|
@@ -41,15 +42,16 @@ module SidekiqUniqueJobs
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def digestable_hash
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
@item.slice(CLASS_KEY, QUEUE_KEY, UNIQUE_ARGS_KEY).tap do |hash|
|
46
|
+
if unique_on_all_queues?
|
47
|
+
logger.debug { "#{__method__} deleting queue: #{@item[QUEUE_KEY]}" }
|
48
|
+
hash.delete(QUEUE_KEY)
|
49
|
+
end
|
50
|
+
if unique_across_workers?
|
51
|
+
logger.debug { "#{__method__} deleting class: #{@item[CLASS_KEY]}" }
|
52
|
+
hash.delete(CLASS_KEY)
|
49
53
|
end
|
50
|
-
hash.delete(QUEUE_KEY)
|
51
54
|
end
|
52
|
-
hash
|
53
55
|
end
|
54
56
|
|
55
57
|
def unique_args(args)
|
@@ -59,9 +61,13 @@ module SidekiqUniqueJobs
|
|
59
61
|
logger.debug { "#{__method__} : unique arguments disabled" }
|
60
62
|
args
|
61
63
|
end
|
62
|
-
rescue NameError
|
63
|
-
#
|
64
|
-
|
64
|
+
rescue NameError => ex
|
65
|
+
logger.error "#{__method__}(#{args}) : failed with (#{ex.message})"
|
66
|
+
logger.error ex
|
67
|
+
|
68
|
+
raise if config.raise_unique_args_errors
|
69
|
+
|
70
|
+
args
|
65
71
|
end
|
66
72
|
|
67
73
|
def unique_on_all_queues?
|
@@ -69,6 +75,11 @@ module SidekiqUniqueJobs
|
|
69
75
|
@item[UNIQUE_ON_ALL_QUEUES_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ON_ALL_QUEUES_KEY]
|
70
76
|
end
|
71
77
|
|
78
|
+
def unique_across_workers?
|
79
|
+
return unless sidekiq_worker_class?
|
80
|
+
@item[UNIQUE_ACROSS_WORKERS_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ACROSS_WORKERS_KEY]
|
81
|
+
end
|
82
|
+
|
72
83
|
def unique_args_enabled?
|
73
84
|
return unless sidekiq_worker_class?
|
74
85
|
unique_args_method # && !unique_args_method.is_a?(Boolean)
|
@@ -106,6 +117,7 @@ module SidekiqUniqueJobs
|
|
106
117
|
logger.warn { "#{__method__} : unique_args_method is nil. Returning (#{args})" }
|
107
118
|
return args
|
108
119
|
end
|
120
|
+
|
109
121
|
filter_args = unique_args_method.call(args)
|
110
122
|
logger.debug { "#{__method__} : #{args} -> #{filter_args}" }
|
111
123
|
filter_args
|
@@ -134,4 +146,5 @@ module SidekiqUniqueJobs
|
|
134
146
|
@unique_args_method ||= Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
|
135
147
|
end
|
136
148
|
end
|
149
|
+
# rubocop:enable ClassLength
|
137
150
|
end
|
@@ -1,22 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SidekiqUniqueJobs
|
2
4
|
module Unlockable
|
3
5
|
module_function
|
4
6
|
|
5
7
|
def unlock(item)
|
8
|
+
return unless item[UNIQUE_DIGEST_KEY]
|
6
9
|
unlock_by_key(item[UNIQUE_DIGEST_KEY], item[JID_KEY])
|
7
10
|
end
|
8
11
|
|
9
12
|
def unlock_by_key(unique_key, jid, redis_pool = nil)
|
10
|
-
|
11
|
-
after_unlock(jid)
|
12
|
-
end
|
13
|
-
|
14
|
-
def after_unlock(jid)
|
13
|
+
lock_released = Scripts::ReleaseLock.execute(redis_pool, unique_key, jid)
|
15
14
|
ensure_job_id_removed(jid)
|
15
|
+
lock_released
|
16
16
|
end
|
17
17
|
|
18
18
|
def ensure_job_id_removed(jid)
|
19
|
-
Sidekiq.redis { |
|
19
|
+
Sidekiq.redis { |conn| conn.hdel(SidekiqUniqueJobs::HASH_KEY, jid) }
|
20
20
|
end
|
21
21
|
|
22
22
|
def logger
|
@@ -1,19 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SidekiqUniqueJobs
|
2
|
-
module Util
|
3
|
-
|
4
|
-
DEFAULT_COUNT
|
5
|
-
|
6
|
-
|
4
|
+
module Util # rubocop:disable Metrics/ModuleLength
|
5
|
+
COUNT = 'COUNT'
|
6
|
+
DEFAULT_COUNT = 1_000
|
7
|
+
EXPIRE_BATCH_SIZE = 100
|
8
|
+
MATCH = 'MATCH'
|
9
|
+
KEYS_METHOD = 'keys'
|
10
|
+
SCAN_METHOD = 'scan'
|
11
|
+
SCAN_PATTERN = '*'
|
7
12
|
|
8
|
-
|
13
|
+
extend self # rubocop:disable Style/ModuleFunction
|
9
14
|
|
10
15
|
def keys(pattern = SCAN_PATTERN, count = DEFAULT_COUNT)
|
11
16
|
send("keys_by_#{redis_keys_method}", pattern, count)
|
12
17
|
end
|
13
18
|
|
14
19
|
def unique_key(jid)
|
15
|
-
connection do |
|
16
|
-
|
20
|
+
connection do |conn|
|
21
|
+
conn.hget(SidekiqUniqueJobs::HASH_KEY, jid)
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
@@ -23,7 +28,7 @@ module SidekiqUniqueJobs
|
|
23
28
|
keys, time = timed { keys(pattern, count) }
|
24
29
|
logger.debug { "#{keys.size} matching keys found in #{time} sec." }
|
25
30
|
keys = dry_run(keys)
|
26
|
-
logger.debug { "#{keys.size} matching keys after
|
31
|
+
logger.debug { "#{keys.size} matching keys after post-processing" }
|
27
32
|
unless dry_run
|
28
33
|
logger.debug { "deleting #{keys}..." }
|
29
34
|
_, time = timed { batch_delete(keys) }
|
@@ -38,18 +43,33 @@ module SidekiqUniqueJobs
|
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
41
|
-
def expire
|
46
|
+
def expire # rubocop:disable Metrics/MethodLength
|
42
47
|
removed_keys = {}
|
43
48
|
connection do |conn|
|
44
|
-
|
45
|
-
|
46
|
-
conn
|
47
|
-
|
49
|
+
cursor = '0'
|
50
|
+
loop do
|
51
|
+
cursor, jobs = get_jobs(conn, cursor)
|
52
|
+
jobs.each do |job_array|
|
53
|
+
jid, unique_key = job_array
|
54
|
+
|
55
|
+
next if conn.get(unique_key)
|
56
|
+
conn.hdel(SidekiqUniqueJobs::HASH_KEY, jid)
|
57
|
+
removed_keys[jid] = unique_key
|
58
|
+
end
|
59
|
+
|
60
|
+
break if cursor == '0'
|
48
61
|
end
|
49
62
|
end
|
63
|
+
|
50
64
|
removed_keys
|
51
65
|
end
|
52
66
|
|
67
|
+
private
|
68
|
+
|
69
|
+
def get_jobs(conn, cursor)
|
70
|
+
conn.hscan(SidekiqUniqueJobs::HASH_KEY, [cursor, MATCH, SCAN_PATTERN, COUNT, EXPIRE_BATCH_SIZE])
|
71
|
+
end
|
72
|
+
|
53
73
|
def keys_by_scan(pattern, count)
|
54
74
|
connection { |conn| conn.scan_each(match: prefix(pattern), count: count).to_a }
|
55
75
|
end
|
data/redis/acquire_lock.lua
CHANGED