sidekiq-unique-jobs 6.0.0.rc6 → 6.0.0.rc7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sidekiq-unique-jobs might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.codeclimate.yml +6 -7
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.reek.yml +17 -48
- data/.rubocop.yml +3 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +2 -0
- data/README.md +65 -23
- data/assets/unique_digests_1.png +0 -0
- data/assets/unique_digests_2.png +0 -0
- data/examples/another_unique_job.rb +4 -2
- data/examples/custom_queue_job_with_filter_method.rb +1 -1
- data/examples/custom_queue_job_with_filter_proc.rb +1 -1
- data/examples/expiring_job.rb +1 -1
- data/examples/inline_worker.rb +1 -1
- data/examples/just_a_worker.rb +1 -1
- data/examples/long_running_job.rb +4 -2
- data/examples/main_job.rb +3 -2
- data/examples/my_unique_job.rb +4 -5
- data/examples/my_unique_job_with_filter_method.rb +3 -3
- data/examples/my_unique_job_with_filter_proc.rb +3 -3
- data/examples/notify_worker.rb +2 -2
- data/examples/simple_worker.rb +2 -2
- data/examples/unique_across_workers_job.rb +1 -1
- data/examples/unique_job_on_conflict_raise.rb +14 -0
- data/examples/unique_job_on_conflict_reject.rb +14 -0
- data/examples/unique_job_on_conflict_reschedule.rb +14 -0
- data/examples/unique_job_with_conditional_parameter.rb +3 -3
- data/examples/unique_job_with_filter_method.rb +5 -2
- data/examples/unique_job_with_nil_unique_args.rb +3 -3
- data/examples/unique_job_with_no_unique_args_method.rb +3 -3
- data/examples/unique_job_withthout_unique_args_parameter.rb +3 -3
- data/examples/unique_on_all_queues_job.rb +1 -1
- data/examples/until_and_while_executing_job.rb +4 -1
- data/examples/until_executed_2_job.rb +5 -5
- data/examples/until_executed_job.rb +5 -5
- data/examples/until_executing_job.rb +1 -1
- data/examples/until_expired_job.rb +1 -1
- data/examples/until_global_expired_job.rb +1 -1
- data/examples/while_executing_job.rb +2 -2
- data/examples/while_executing_reject_job.rb +2 -2
- data/examples/without_argument_job.rb +1 -1
- data/lib/sidekiq_unique_jobs.rb +30 -0
- data/lib/sidekiq_unique_jobs/client/middleware.rb +12 -1
- data/lib/sidekiq_unique_jobs/connection.rb +5 -1
- data/lib/sidekiq_unique_jobs/constants.rb +3 -0
- data/lib/sidekiq_unique_jobs/digests.rb +111 -0
- data/lib/sidekiq_unique_jobs/exceptions.rb +15 -16
- data/lib/sidekiq_unique_jobs/lock/base_lock.rb +44 -3
- data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +13 -3
- data/lib/sidekiq_unique_jobs/lock/until_executed.rb +8 -1
- data/lib/sidekiq_unique_jobs/lock/until_executing.rb +8 -1
- data/lib/sidekiq_unique_jobs/lock/until_expired.rb +14 -2
- data/lib/sidekiq_unique_jobs/lock/while_executing.rb +19 -5
- data/lib/sidekiq_unique_jobs/lock/while_executing_reject.rb +16 -63
- data/lib/sidekiq_unique_jobs/locksmith.rb +36 -13
- data/lib/sidekiq_unique_jobs/logging.rb +24 -1
- data/lib/sidekiq_unique_jobs/normalizer.rb +6 -0
- data/lib/sidekiq_unique_jobs/on_conflict.rb +24 -0
- data/lib/sidekiq_unique_jobs/on_conflict/log.rb +20 -0
- data/lib/sidekiq_unique_jobs/on_conflict/null_strategy.rb +16 -0
- data/lib/sidekiq_unique_jobs/on_conflict/raise.rb +17 -0
- data/lib/sidekiq_unique_jobs/on_conflict/reject.rb +72 -0
- data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +24 -0
- data/lib/sidekiq_unique_jobs/on_conflict/strategy.rb +28 -0
- data/lib/sidekiq_unique_jobs/options_with_fallback.rb +19 -4
- data/lib/sidekiq_unique_jobs/scripts.rb +31 -0
- data/lib/sidekiq_unique_jobs/server/middleware.rb +10 -0
- data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +15 -1
- data/lib/sidekiq_unique_jobs/timeout/calculator.rb +17 -4
- data/lib/sidekiq_unique_jobs/unique_args.rb +47 -5
- data/lib/sidekiq_unique_jobs/unlockable.rb +10 -0
- data/lib/sidekiq_unique_jobs/util.rb +12 -7
- data/lib/sidekiq_unique_jobs/version.rb +1 -1
- data/lib/sidekiq_unique_jobs/web.rb +51 -0
- data/lib/sidekiq_unique_jobs/web/helpers.rb +37 -0
- data/lib/sidekiq_unique_jobs/web/views/unique_digest.erb +28 -0
- data/lib/sidekiq_unique_jobs/web/views/unique_digests.erb +42 -0
- data/redis/create.lua +4 -2
- data/redis/delete.lua +3 -1
- data/redis/delete_by_digest.lua +22 -0
- data/redis/signal.lua +3 -1
- data/sidekiq-unique-jobs.gemspec +2 -0
- metadata +49 -3
- data/lib/sidekiq_unique_jobs/lock/while_executing_requeue.rb +0 -21
@@ -2,74 +2,27 @@
|
|
2
2
|
|
3
3
|
module SidekiqUniqueJobs
|
4
4
|
class Lock
|
5
|
+
# Locks jobs while executing
|
6
|
+
# Locks from the server process
|
7
|
+
# Unlocks after the server is done processing
|
8
|
+
#
|
9
|
+
# See {#lock} for more information about the client.
|
10
|
+
# See {#execute} for more information about the server
|
11
|
+
#
|
12
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
5
13
|
class WhileExecutingReject < WhileExecuting
|
14
|
+
# Executes in the Sidekiq server process
|
15
|
+
# @yield to the worker class perform method
|
6
16
|
def execute
|
7
|
-
return
|
17
|
+
return strategy.call unless locksmith.lock(item[LOCK_TIMEOUT_KEY])
|
8
18
|
|
9
|
-
with_cleanup { yield
|
19
|
+
with_cleanup { yield }
|
10
20
|
end
|
11
21
|
|
12
|
-
#
|
13
|
-
|
14
|
-
def
|
15
|
-
|
16
|
-
send_to_deadset
|
17
|
-
end
|
18
|
-
|
19
|
-
def send_to_deadset
|
20
|
-
log_info { "Adding dead #{item[CLASS_KEY]} job #{item[JID_KEY]}" }
|
21
|
-
|
22
|
-
if deadset_kill?
|
23
|
-
deadset_kill
|
24
|
-
else
|
25
|
-
push_to_deadset
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def deadset_kill?
|
30
|
-
deadset.respond_to?(:kill)
|
31
|
-
end
|
32
|
-
|
33
|
-
def deadset_kill
|
34
|
-
if kill_with_options?
|
35
|
-
kill_job_with_options
|
36
|
-
else
|
37
|
-
kill_job_without_options
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def kill_with_options?
|
42
|
-
Sidekiq::DeadSet.instance_method(:kill).arity > 1
|
43
|
-
end
|
44
|
-
|
45
|
-
def kill_job_without_options
|
46
|
-
deadset.kill(payload)
|
47
|
-
end
|
48
|
-
|
49
|
-
def kill_job_with_options
|
50
|
-
deadset.kill(payload, notify_failure: false)
|
51
|
-
end
|
52
|
-
|
53
|
-
def deadset
|
54
|
-
@deadset ||= Sidekiq::DeadSet.new
|
55
|
-
end
|
56
|
-
|
57
|
-
def push_to_deadset
|
58
|
-
Sidekiq.redis do |conn|
|
59
|
-
conn.multi do
|
60
|
-
conn.zadd('dead', current_time, payload)
|
61
|
-
conn.zremrangebyscore('dead', '-inf', current_time - Sidekiq::DeadSet.timeout)
|
62
|
-
conn.zremrangebyrank('dead', 0, -Sidekiq::DeadSet.max_jobs)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def current_time
|
68
|
-
@current_time ||= Time.now.to_f
|
69
|
-
end
|
70
|
-
|
71
|
-
def payload
|
72
|
-
@payload ||= Sidekiq.dump_json(item)
|
22
|
+
# Overridden with a forced {OnConflict::Reject} strategy
|
23
|
+
# @return [OnConflict::Reject] a reject strategy
|
24
|
+
def strategy
|
25
|
+
@strategy ||= OnConflict.find_strategy(:reject).new(item)
|
73
26
|
end
|
74
27
|
end
|
75
28
|
end
|
@@ -1,12 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SidekiqUniqueJobs
|
4
|
+
# Lock manager class that handles all the various locks
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
4
7
|
class Locksmith # rubocop:disable ClassLength
|
5
8
|
API_VERSION = '1'
|
6
9
|
EXPIRES_IN = 10
|
7
10
|
|
8
11
|
include SidekiqUniqueJobs::Connection
|
9
12
|
|
13
|
+
# @param [Hash] item a Sidekiq job hash
|
14
|
+
# @option item [Integer] :lock_expiration the configured expiration
|
15
|
+
# @option item [String] :jid the sidekiq job id
|
16
|
+
# @option item [String] :unique_digest the unique digest (See: {UniqueArgs#unique_digest})
|
17
|
+
# @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
|
10
18
|
def initialize(item, redis_pool = nil)
|
11
19
|
@concurrency = 1 # removed in a0cff5bc42edbe7190d6ede7e7f845074d2d7af6
|
12
20
|
@expiration = item[LOCK_EXPIRATION_KEY]
|
@@ -15,38 +23,51 @@ module SidekiqUniqueJobs
|
|
15
23
|
@redis_pool = redis_pool
|
16
24
|
end
|
17
25
|
|
26
|
+
# Creates the necessary keys in redis to attempt a lock
|
27
|
+
# @return [String] the Sidekiq job_id
|
18
28
|
def create
|
19
29
|
Scripts.call(
|
20
30
|
:create,
|
21
31
|
redis_pool,
|
22
|
-
keys: [exists_key, grabbed_key, available_key, version_key, unique_digest],
|
32
|
+
keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
|
23
33
|
argv: [jid, expiration, API_VERSION, concurrency],
|
24
34
|
)
|
25
35
|
end
|
26
36
|
|
37
|
+
# Checks if the exists key is created in redis
|
38
|
+
# @return [true, false]
|
27
39
|
def exists?
|
28
40
|
redis(redis_pool) { |conn| conn.exists(exists_key) }
|
29
41
|
end
|
30
42
|
|
43
|
+
# The number of available resourced for this lock
|
44
|
+
# @return [Integer] the number of available resources
|
31
45
|
def available_count
|
32
46
|
return concurrency unless exists?
|
33
47
|
|
34
48
|
redis(redis_pool) { |conn| conn.llen(available_key) }
|
35
49
|
end
|
36
50
|
|
51
|
+
# Deletes the lock unless it has an expiration set
|
37
52
|
def delete
|
38
|
-
return
|
53
|
+
return if expiration
|
39
54
|
delete!
|
40
55
|
end
|
41
56
|
|
57
|
+
# Deletes the lock regardless of if it has an expiration set
|
42
58
|
def delete!
|
43
59
|
Scripts.call(
|
44
60
|
:delete,
|
45
61
|
redis_pool,
|
46
|
-
keys: [exists_key, grabbed_key, available_key, version_key, unique_digest],
|
62
|
+
keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
|
47
63
|
)
|
48
64
|
end
|
49
65
|
|
66
|
+
# Create a lock for the item
|
67
|
+
# @param [Integer] timeout the number of seconds to wait for a lock.
|
68
|
+
# nil means wait indefinitely
|
69
|
+
# @yield the block to execute if a lock is successful
|
70
|
+
# @return the Sidekiq job_id (jid)
|
50
71
|
def lock(timeout = nil, &block)
|
51
72
|
create
|
52
73
|
|
@@ -57,23 +78,34 @@ module SidekiqUniqueJobs
|
|
57
78
|
end
|
58
79
|
alias wait lock
|
59
80
|
|
81
|
+
# Removes the lock keys from Redis
|
82
|
+
# @return [false] unless locked?
|
83
|
+
# @return [String] Sidekiq job_id (jid) if successful
|
60
84
|
def unlock
|
61
85
|
return false unless locked?
|
62
86
|
signal(jid)
|
63
87
|
end
|
64
88
|
|
89
|
+
# Removes the lock keys from Redis
|
90
|
+
# @param [String] token the unique token to check for a lock.
|
91
|
+
# nil will default to the jid provided in the initializer
|
92
|
+
# @return [true, false]
|
65
93
|
def locked?(token = nil)
|
66
94
|
token ||= jid
|
67
95
|
redis(redis_pool) { |conn| conn.hexists(grabbed_key, token) }
|
68
96
|
end
|
69
97
|
|
98
|
+
# Signal that the token should be released
|
99
|
+
# @param [String] token the unique token to check for a lockk.
|
100
|
+
# nil will default to the jid provided in the initializer.
|
101
|
+
# @return [Integer] the number of available lock resources
|
70
102
|
def signal(token = nil)
|
71
103
|
token ||= jid
|
72
104
|
|
73
105
|
Scripts.call(
|
74
106
|
:signal,
|
75
107
|
redis_pool,
|
76
|
-
keys: [exists_key, grabbed_key, available_key, version_key, unique_digest],
|
108
|
+
keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
|
77
109
|
argv: [token, expiration],
|
78
110
|
)
|
79
111
|
end
|
@@ -140,12 +172,3 @@ module SidekiqUniqueJobs
|
|
140
172
|
end
|
141
173
|
end
|
142
174
|
end
|
143
|
-
|
144
|
-
require 'sidekiq_unique_jobs/lock/base_lock'
|
145
|
-
require 'sidekiq_unique_jobs/lock/until_executed'
|
146
|
-
require 'sidekiq_unique_jobs/lock/until_executing'
|
147
|
-
require 'sidekiq_unique_jobs/lock/until_expired'
|
148
|
-
require 'sidekiq_unique_jobs/lock/while_executing'
|
149
|
-
require 'sidekiq_unique_jobs/lock/while_executing_reject'
|
150
|
-
require 'sidekiq_unique_jobs/lock/while_executing_requeue'
|
151
|
-
require 'sidekiq_unique_jobs/lock/until_and_while_executing'
|
@@ -1,28 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SidekiqUniqueJobs
|
4
|
+
# Utility module for reducing the number of uses of logger.
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
4
7
|
module Logging
|
5
|
-
#
|
8
|
+
# A convenience method for using the configured logger
|
6
9
|
def logger
|
7
10
|
SidekiqUniqueJobs.logger
|
8
11
|
end
|
9
12
|
|
13
|
+
# Logs a message at debug level
|
14
|
+
# @param message_or_exception [String, Exception] the message or exception to log
|
15
|
+
# @yield the message or exception to use for log message
|
16
|
+
# Used for compatibility with logger
|
10
17
|
def log_debug(message_or_exception = nil, &block)
|
11
18
|
logger.debug(message_or_exception, &block)
|
12
19
|
end
|
13
20
|
|
21
|
+
# Logs a message at info level
|
22
|
+
# @param message_or_exception [String, Exception] the message or exception to log
|
23
|
+
# @yield the message or exception to use for log message
|
24
|
+
# Used for compatibility with logger
|
14
25
|
def log_info(message_or_exception = nil, &block)
|
15
26
|
logger.info(message_or_exception, &block)
|
16
27
|
end
|
17
28
|
|
29
|
+
# Logs a message at warn level
|
30
|
+
# @param message_or_exception [String, Exception] the message or exception to log
|
31
|
+
# @yield the message or exception to use for log message
|
32
|
+
# Used for compatibility with logger
|
18
33
|
def log_warn(message_or_exception = nil, &block)
|
19
34
|
logger.warn(message_or_exception, &block)
|
20
35
|
end
|
21
36
|
|
37
|
+
# Logs a message at error level
|
38
|
+
# @param message_or_exception [String, Exception] the message or exception to log
|
39
|
+
# @yield the message or exception to use for log message
|
40
|
+
# Used for compatibility with logger
|
22
41
|
def log_error(message_or_exception = nil, &block)
|
23
42
|
logger.error(message_or_exception, &block)
|
24
43
|
end
|
25
44
|
|
45
|
+
# Logs a message at fatal level
|
46
|
+
# @param message_or_exception [String, Exception] the message or exception to log
|
47
|
+
# @yield the message or exception to use for log message
|
48
|
+
# Used for compatibility with logger
|
26
49
|
def log_fatal(message_or_exception = nil, &block)
|
27
50
|
logger.fatal(message_or_exception, &block)
|
28
51
|
end
|
@@ -3,7 +3,13 @@
|
|
3
3
|
require 'json'
|
4
4
|
|
5
5
|
module SidekiqUniqueJobs
|
6
|
+
# Normalizes hashes by dumping them to json and loading them from json
|
7
|
+
#
|
8
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
6
9
|
module Normalizer
|
10
|
+
# Changes hash to a json compatible hash
|
11
|
+
# @param [Hash] args
|
12
|
+
# @return [Hash] a json compatible hash
|
7
13
|
def self.jsonify(args)
|
8
14
|
Sidekiq.load_json(Sidekiq.dump_json(args))
|
9
15
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'on_conflict/strategy'
|
4
|
+
require_relative 'on_conflict/null_strategy'
|
5
|
+
require_relative 'on_conflict/log'
|
6
|
+
require_relative 'on_conflict/raise'
|
7
|
+
require_relative 'on_conflict/reject'
|
8
|
+
require_relative 'on_conflict/reschedule'
|
9
|
+
|
10
|
+
module SidekiqUniqueJobs
|
11
|
+
module OnConflict
|
12
|
+
STRATEGIES = {
|
13
|
+
log: OnConflict::Log,
|
14
|
+
raise: OnConflict::Raise,
|
15
|
+
reject: OnConflict::Reject,
|
16
|
+
reschedule: OnConflict::Reschedule,
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
# returns OnConflict::NullStrategy when no other could be found
|
20
|
+
def self.find_strategy(strategy)
|
21
|
+
STRATEGIES.fetch(strategy.to_s.to_sym) { OnConflict::NullStrategy }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module OnConflict
|
5
|
+
# Strategy to log information about conflict
|
6
|
+
#
|
7
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
8
|
+
class Log < OnConflict::Strategy
|
9
|
+
include SidekiqUniqueJobs::Logging
|
10
|
+
|
11
|
+
# Logs an informational message about that the job was not unique
|
12
|
+
def call
|
13
|
+
log_info(
|
14
|
+
"skipping job with id (#{item[JID_KEY]}) " \
|
15
|
+
"because unique_digest: (#{item[UNIQUE_DIGEST_KEY]}) already exists",
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module OnConflict
|
5
|
+
# Default conflict strategy class that does nothing
|
6
|
+
#
|
7
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
8
|
+
class NullStrategy < OnConflict::Strategy
|
9
|
+
# Do nothing on conflict
|
10
|
+
# @return [nil]
|
11
|
+
def call
|
12
|
+
# NOOP
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module OnConflict
|
5
|
+
# Strategy to raise an error on conflict
|
6
|
+
#
|
7
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
8
|
+
class Raise < OnConflict::Strategy
|
9
|
+
# Raise an error on conflict.
|
10
|
+
# This will cause Sidekiq to retry the job
|
11
|
+
# @raise [SidekiqUniqueJobs::Conflict]
|
12
|
+
def call
|
13
|
+
fail SidekiqUniqueJobs::Conflict, item
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module OnConflict
|
5
|
+
# Strategy to send jobs to dead queue
|
6
|
+
#
|
7
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
8
|
+
class Reject < OnConflict::Strategy
|
9
|
+
# Send jobs to dead queue
|
10
|
+
def call
|
11
|
+
log_debug { "Rejecting job with jid: #{item[JID_KEY]}" }
|
12
|
+
send_to_deadset
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_to_deadset
|
16
|
+
log_info { "Adding dead #{item[CLASS_KEY]} job #{item[JID_KEY]}" }
|
17
|
+
|
18
|
+
if deadset_kill?
|
19
|
+
deadset_kill
|
20
|
+
else
|
21
|
+
push_to_deadset
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def deadset_kill?
|
26
|
+
deadset.respond_to?(:kill)
|
27
|
+
end
|
28
|
+
|
29
|
+
def deadset_kill
|
30
|
+
if kill_with_options?
|
31
|
+
kill_job_with_options
|
32
|
+
else
|
33
|
+
kill_job_without_options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def kill_with_options?
|
38
|
+
Sidekiq::DeadSet.instance_method(:kill).arity > 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def kill_job_without_options
|
42
|
+
deadset.kill(payload)
|
43
|
+
end
|
44
|
+
|
45
|
+
def kill_job_with_options
|
46
|
+
deadset.kill(payload, notify_failure: false)
|
47
|
+
end
|
48
|
+
|
49
|
+
def deadset
|
50
|
+
@deadset ||= Sidekiq::DeadSet.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def push_to_deadset
|
54
|
+
Sidekiq.redis do |conn|
|
55
|
+
conn.multi do
|
56
|
+
conn.zadd('dead', current_time, payload)
|
57
|
+
conn.zremrangebyscore('dead', '-inf', current_time - Sidekiq::DeadSet.timeout)
|
58
|
+
conn.zremrangebyrank('dead', 0, -Sidekiq::DeadSet.max_jobs)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_time
|
64
|
+
@current_time ||= Time.now.to_f
|
65
|
+
end
|
66
|
+
|
67
|
+
def payload
|
68
|
+
@payload ||= Sidekiq.dump_json(item)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module OnConflict
|
5
|
+
# Strategy to reschedule job on conflict
|
6
|
+
#
|
7
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
8
|
+
class Reschedule < OnConflict::Strategy
|
9
|
+
include SidekiqUniqueJobs::SidekiqWorkerMethods
|
10
|
+
|
11
|
+
# @param [Hash] item sidekiq job hash
|
12
|
+
def initialize(item)
|
13
|
+
super
|
14
|
+
@worker_class = item[CLASS_KEY]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new job from the current one.
|
18
|
+
# This will mess up sidekiq stats because a new job is created
|
19
|
+
def call
|
20
|
+
worker_class&.perform_in(5, *item[ARGS_KEY]) if sidekiq_worker_class?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|