sidekiq-unique-jobs 5.0.11 → 6.0.0.rc1
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 +17 -9
- data/.gitignore +1 -3
- data/.reek +105 -0
- data/.rubocop.yml +36 -1
- data/.simplecov +7 -2
- data/.travis.yml +11 -10
- data/Appraisals +3 -7
- data/CHANGELOG.md +17 -0
- data/Gemfile +16 -13
- data/Guardfile +55 -0
- data/README.md +85 -73
- data/examples/another_unique_job.rb +13 -0
- data/examples/custom_queue_job.rb +12 -0
- data/examples/custom_queue_job_with_filter_method.rb +13 -0
- data/examples/custom_queue_job_with_filter_proc.rb +16 -0
- data/examples/expiring_job.rb +12 -0
- data/examples/inline_worker.rb +12 -0
- data/examples/just_a_worker.rb +13 -0
- data/examples/long_running_job.rb +12 -0
- data/examples/main_job.rb +13 -0
- data/examples/my_job.rb +12 -0
- data/examples/my_unique_job.rb +16 -0
- data/examples/my_unique_job_with_filter_method.rb +21 -0
- data/examples/my_unique_job_with_filter_proc.rb +19 -0
- data/examples/notify_worker.rb +14 -0
- data/examples/plain_class.rb +13 -0
- data/examples/simple_worker.rb +15 -0
- data/examples/spawn_simple_worker.rb +12 -0
- data/examples/test_class.rb +9 -0
- data/examples/unique_across_workers_job.rb +20 -0
- data/examples/unique_job_with_conditional_parameter.rb +18 -0
- data/examples/unique_job_with_filter_method.rb +18 -0
- data/examples/unique_job_with_nil_unique_args.rb +20 -0
- data/examples/unique_job_with_no_unique_args_method.rb +16 -0
- data/examples/unique_job_withthout_unique_args_parameter.rb +18 -0
- data/examples/unique_on_all_queues_job.rb +16 -0
- data/examples/until_and_while_executing_job.rb +13 -0
- data/examples/until_executed_2_job.rb +24 -0
- data/examples/until_executed_job.rb +25 -0
- data/examples/until_executing_job.rb +11 -0
- data/examples/until_expired_job.rb +12 -0
- data/examples/until_global_expired_job.rb +12 -0
- data/examples/while_executing_job.rb +15 -0
- data/examples/while_executing_reject_job.rb +14 -0
- data/examples/without_argument_job.rb +13 -0
- data/lib/sidekiq-unique-jobs.rb +1 -91
- data/lib/sidekiq/simulator.rb +15 -16
- data/lib/sidekiq_unique_jobs.rb +79 -0
- data/lib/sidekiq_unique_jobs/cli.rb +9 -18
- data/lib/sidekiq_unique_jobs/client/middleware.rb +16 -18
- data/lib/sidekiq_unique_jobs/connection.rb +18 -0
- data/lib/sidekiq_unique_jobs/constants.rb +13 -17
- data/lib/sidekiq_unique_jobs/core_ext.rb +28 -55
- data/lib/sidekiq_unique_jobs/exceptions.rb +30 -0
- data/lib/sidekiq_unique_jobs/lock/base_lock.rb +84 -0
- data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +11 -6
- data/lib/sidekiq_unique_jobs/lock/until_executed.rb +6 -58
- data/lib/sidekiq_unique_jobs/lock/until_executing.rb +6 -5
- data/lib/sidekiq_unique_jobs/lock/until_expired.rb +17 -0
- data/lib/sidekiq_unique_jobs/lock/while_executing.rb +20 -34
- data/lib/sidekiq_unique_jobs/lock/while_executing_reject.rb +78 -0
- data/lib/sidekiq_unique_jobs/lock/while_executing_requeue.rb +20 -0
- data/lib/sidekiq_unique_jobs/locksmith.rb +149 -0
- data/lib/sidekiq_unique_jobs/logging.rb +30 -0
- data/lib/sidekiq_unique_jobs/options_with_fallback.rb +27 -41
- data/lib/sidekiq_unique_jobs/scripts.rb +25 -24
- data/lib/sidekiq_unique_jobs/server/middleware.rb +12 -20
- data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +5 -5
- data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +42 -0
- data/lib/sidekiq_unique_jobs/testing.rb +40 -50
- data/lib/sidekiq_unique_jobs/timeout.rb +15 -0
- data/lib/sidekiq_unique_jobs/timeout/calculator.rb +49 -0
- data/lib/sidekiq_unique_jobs/unique_args.rb +33 -77
- data/lib/sidekiq_unique_jobs/unlockable.rb +5 -14
- data/lib/sidekiq_unique_jobs/util.rb +28 -90
- data/lib/sidekiq_unique_jobs/version.rb +1 -1
- data/redis/acquire_lock.lua +5 -3
- data/redis/create.lua +58 -0
- data/redis/delete.lua +11 -0
- data/redis/release_stale_locks.lua +90 -0
- data/redis/signal.lua +21 -0
- data/sidekiq-unique-jobs.gemspec +15 -8
- metadata +108 -32
- data/lib/sidekiq_unique_jobs/config.rb +0 -17
- data/lib/sidekiq_unique_jobs/lock.rb +0 -12
- data/lib/sidekiq_unique_jobs/lock/until_timeout.rb +0 -17
- data/lib/sidekiq_unique_jobs/run_lock_failed.rb +0 -3
- data/lib/sidekiq_unique_jobs/script_mock.rb +0 -66
- data/lib/sidekiq_unique_jobs/scripts/acquire_lock.rb +0 -47
- data/lib/sidekiq_unique_jobs/scripts/release_lock.rb +0 -49
- data/lib/sidekiq_unique_jobs/testing/sidekiq_overrides.rb +0 -50
- data/lib/sidekiq_unique_jobs/timeout_calculator.rb +0 -67
- data/redis/synchronize.lua +0 -16
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqUniqueJobs
|
4
|
+
module Timeout
|
5
|
+
class Calculator
|
6
|
+
include SidekiqUniqueJobs::SidekiqWorkerMethods
|
7
|
+
attr_reader :item
|
8
|
+
|
9
|
+
def initialize(item)
|
10
|
+
@item = item
|
11
|
+
@worker_class = item[CLASS_KEY]
|
12
|
+
end
|
13
|
+
|
14
|
+
def time_until_scheduled
|
15
|
+
return 0 unless scheduled_at
|
16
|
+
scheduled_at.to_i - Time.now.utc.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def scheduled_at
|
20
|
+
@scheduled_at ||= item[AT_KEY]
|
21
|
+
end
|
22
|
+
|
23
|
+
def seconds
|
24
|
+
raise NotImplementedError, "##{__method__} needs to be implemented in #{self.class}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def lock_expiration
|
28
|
+
@lock_expiration ||= begin
|
29
|
+
expiration = item[LOCK_EXPIRATION_KEY]
|
30
|
+
expiration ||= worker_options[LOCK_EXPIRATION_KEY]
|
31
|
+
expiration && expiration + time_until_scheduled
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def lock_timeout
|
36
|
+
@lock_timeout = begin
|
37
|
+
timeout = default_worker_options[LOCK_TIMEOUT_KEY]
|
38
|
+
timeout = default_lock_timeout if default_lock_timeout
|
39
|
+
timeout = worker_options[LOCK_TIMEOUT_KEY] if worker_options.key?(LOCK_TIMEOUT_KEY)
|
40
|
+
timeout
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_lock_timeout
|
45
|
+
SidekiqUniqueJobs.config.default_lock_timeout
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -5,101 +5,73 @@ require 'sidekiq_unique_jobs/normalizer'
|
|
5
5
|
|
6
6
|
module SidekiqUniqueJobs
|
7
7
|
# This class exists to be testable and the entire api should be considered private
|
8
|
-
# rubocop:disable ClassLength
|
9
8
|
class UniqueArgs
|
10
9
|
CLASS_NAME = 'SidekiqUniqueJobs::UniqueArgs'
|
11
|
-
extend Forwardable
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
include SidekiqUniqueJobs::Logging
|
12
|
+
include SidekiqUniqueJobs::SidekiqWorkerMethods
|
15
13
|
|
16
14
|
def self.digest(item)
|
17
15
|
new(item).unique_digest
|
18
16
|
end
|
19
17
|
|
18
|
+
attr_reader :item
|
19
|
+
|
20
20
|
def initialize(item)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
@item = item
|
22
|
+
@worker_class = item[CLASS_KEY]
|
23
|
+
|
24
|
+
add_uniqueness_to_item
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_uniqueness_to_item
|
28
|
+
item[UNIQUE_PREFIX_KEY] ||= unique_prefix
|
29
|
+
item[UNIQUE_ARGS_KEY] = unique_args(item[ARGS_KEY])
|
30
|
+
item[UNIQUE_DIGEST_KEY] = unique_digest
|
28
31
|
end
|
29
32
|
|
30
33
|
def unique_digest
|
31
|
-
@unique_digest ||=
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
@unique_digest ||= create_digest
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_digest
|
38
|
+
digest = Digest::MD5.hexdigest(Sidekiq.dump_json(digestable_hash))
|
39
|
+
"#{unique_prefix}:#{digest}"
|
37
40
|
end
|
38
41
|
|
39
42
|
def unique_prefix
|
40
|
-
|
41
|
-
@worker_class.get_sidekiq_options[UNIQUE_PREFIX_KEY] || config.unique_prefix
|
43
|
+
worker_options[UNIQUE_PREFIX_KEY] || SidekiqUniqueJobs.config.unique_prefix
|
42
44
|
end
|
43
45
|
|
44
46
|
def digestable_hash
|
45
47
|
@item.slice(CLASS_KEY, QUEUE_KEY, UNIQUE_ARGS_KEY).tap do |hash|
|
46
|
-
if unique_on_all_queues?
|
47
|
-
|
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)
|
53
|
-
end
|
48
|
+
hash.delete(QUEUE_KEY) if unique_on_all_queues?
|
49
|
+
hash.delete(CLASS_KEY) if unique_across_workers?
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
53
|
def unique_args(args)
|
58
|
-
if unique_args_enabled?
|
59
|
-
filtered_args(args)
|
60
|
-
else
|
61
|
-
logger.debug { "#{__method__} : unique arguments disabled" }
|
62
|
-
args
|
63
|
-
end
|
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
|
-
|
54
|
+
return filtered_args(args) if unique_args_enabled?
|
70
55
|
args
|
71
56
|
end
|
72
57
|
|
73
58
|
def unique_on_all_queues?
|
74
|
-
|
75
|
-
@item[UNIQUE_ON_ALL_QUEUES_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ON_ALL_QUEUES_KEY]
|
59
|
+
item[UNIQUE_ON_ALL_QUEUES_KEY] || worker_options[UNIQUE_ON_ALL_QUEUES_KEY]
|
76
60
|
end
|
77
61
|
|
78
62
|
def unique_across_workers?
|
79
|
-
|
80
|
-
@item[UNIQUE_ACROSS_WORKERS_KEY] || @worker_class.get_sidekiq_options[UNIQUE_ACROSS_WORKERS_KEY]
|
63
|
+
item[UNIQUE_ACROSS_WORKERS_KEY] || worker_options[UNIQUE_ACROSS_WORKERS_KEY]
|
81
64
|
end
|
82
65
|
|
83
66
|
def unique_args_enabled?
|
84
|
-
return unless sidekiq_worker_class?
|
85
67
|
unique_args_method # && !unique_args_method.is_a?(Boolean)
|
86
68
|
end
|
87
69
|
|
88
|
-
def sidekiq_worker_class?
|
89
|
-
if @worker_class.respond_to?(:get_sidekiq_options)
|
90
|
-
true
|
91
|
-
else
|
92
|
-
logger.debug { "#{__method__} #{@worker_class} does not respond to :get_sidekiq_options" }
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
70
|
# Filters unique arguments by proc or symbol
|
98
71
|
# returns provided arguments for other configurations
|
99
72
|
def filtered_args(args)
|
100
73
|
return args if args.empty?
|
101
74
|
json_args = Normalizer.jsonify(args)
|
102
|
-
logger.debug { "#filtered_args #{args} => #{json_args}" }
|
103
75
|
|
104
76
|
case unique_args_method
|
105
77
|
when Proc
|
@@ -107,44 +79,28 @@ module SidekiqUniqueJobs
|
|
107
79
|
when Symbol
|
108
80
|
filter_by_symbol(json_args)
|
109
81
|
else
|
110
|
-
|
82
|
+
log_debug("#{__method__} arguments not filtered (using all arguments for uniqueness)")
|
111
83
|
json_args
|
112
84
|
end
|
113
85
|
end
|
114
86
|
|
115
87
|
def filter_by_proc(args)
|
116
|
-
|
117
|
-
logger.warn { "#{__method__} : unique_args_method is nil. Returning (#{args})" }
|
118
|
-
return args
|
119
|
-
end
|
120
|
-
|
121
|
-
filter_args = unique_args_method.call(args)
|
122
|
-
logger.debug { "#{__method__} : #{args} -> #{filter_args}" }
|
123
|
-
filter_args
|
88
|
+
unique_args_method.call(args)
|
124
89
|
end
|
125
90
|
|
126
91
|
def filter_by_symbol(args)
|
127
|
-
unless
|
128
|
-
logger.warn do
|
129
|
-
"#{__method__} : #{@worker_class} does not respond to #{unique_args_method}). Returning (#{args})"
|
130
|
-
end
|
131
|
-
return args
|
132
|
-
end
|
92
|
+
return args unless worker_method_defined?(unique_args_method)
|
133
93
|
|
134
|
-
|
135
|
-
logger.debug { "#{__method__} : #{unique_args_method}(#{args}) => #{filter_args}" }
|
136
|
-
filter_args
|
94
|
+
worker_class.send(unique_args_method, args)
|
137
95
|
rescue ArgumentError => ex
|
138
|
-
|
139
|
-
logger.fatal ex
|
96
|
+
log_fatal(ex)
|
140
97
|
args
|
141
98
|
end
|
142
99
|
|
143
100
|
def unique_args_method
|
144
|
-
@unique_args_method ||=
|
145
|
-
@unique_args_method ||= :unique_args if
|
101
|
+
@unique_args_method ||= worker_options[UNIQUE_ARGS_KEY]
|
102
|
+
@unique_args_method ||= :unique_args if worker_method_defined?(:unique_args)
|
146
103
|
@unique_args_method ||= Sidekiq.default_worker_options.stringify_keys[UNIQUE_ARGS_KEY]
|
147
104
|
end
|
148
105
|
end
|
149
|
-
# rubocop:enable ClassLength
|
150
106
|
end
|
@@ -5,22 +5,13 @@ module SidekiqUniqueJobs
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def unlock(item)
|
8
|
-
|
9
|
-
|
8
|
+
SidekiqUniqueJobs::UniqueArgs.digest(item)
|
9
|
+
SidekiqUniqueJobs::Locksmith.new(item).unlock
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
lock_released
|
16
|
-
end
|
17
|
-
|
18
|
-
def ensure_job_id_removed(jid)
|
19
|
-
Sidekiq.redis { |conn| conn.hdel(SidekiqUniqueJobs::HASH_KEY, jid) }
|
20
|
-
end
|
21
|
-
|
22
|
-
def logger
|
23
|
-
SidekiqUniqueJobs.logger
|
12
|
+
def delete(item)
|
13
|
+
SidekiqUniqueJobs::UniqueArgs.digest(item)
|
14
|
+
SidekiqUniqueJobs::Locksmith.new(item).delete!
|
24
15
|
end
|
25
16
|
end
|
26
17
|
end
|
@@ -1,85 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SidekiqUniqueJobs
|
4
|
-
module Util
|
4
|
+
module Util
|
5
5
|
COUNT = 'COUNT'
|
6
6
|
DEFAULT_COUNT = 1_000
|
7
7
|
EXPIRE_BATCH_SIZE = 100
|
8
|
-
|
9
|
-
KEYS_METHOD = 'keys'
|
10
|
-
SCAN_METHOD = 'scan'
|
8
|
+
SCAN_METHOD = 'SCAN'
|
11
9
|
SCAN_PATTERN = '*'
|
12
10
|
|
11
|
+
include SidekiqUniqueJobs::Logging
|
12
|
+
include SidekiqUniqueJobs::Connection
|
13
13
|
extend self # rubocop:disable Style/ModuleFunction
|
14
14
|
|
15
15
|
def keys(pattern = SCAN_PATTERN, count = DEFAULT_COUNT)
|
16
|
-
|
16
|
+
return redis(&:keys) if pattern.nil?
|
17
|
+
redis { |conn| conn.scan_each(match: prefix(pattern), count: count).to_a }
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def del(pattern = SCAN_PATTERN, count = 0
|
20
|
+
# Deletes unique keys from redis
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# @param pattern [String] a pattern to scan for in redis
|
24
|
+
# @param count [Integer] the maximum number of keys to delete
|
25
|
+
# @return [Boolean] report success
|
26
|
+
def del(pattern = SCAN_PATTERN, count = 0)
|
26
27
|
raise ArgumentError, 'Please provide a number of keys to delete greater than zero' if count.zero?
|
27
|
-
|
28
|
-
keys, time = timed { keys(pattern, count) }
|
29
|
-
logger.debug { "#{keys.size} matching keys found in #{time} sec." }
|
30
|
-
keys = dry_run(keys)
|
31
|
-
logger.debug { "#{keys.size} matching keys after post-processing" }
|
32
|
-
unless dry_run
|
33
|
-
logger.debug { "deleting #{keys}..." }
|
34
|
-
_, time = timed { batch_delete(keys) }
|
35
|
-
logger.debug { "Deleted in #{time} sec." }
|
36
|
-
end
|
37
|
-
keys.size
|
38
|
-
end
|
39
|
-
|
40
|
-
def unique_hash
|
41
|
-
connection do |conn|
|
42
|
-
conn.hgetall(SidekiqUniqueJobs::HASH_KEY)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def expire # rubocop:disable Metrics/MethodLength
|
47
|
-
removed_keys = {}
|
48
|
-
connection do |conn|
|
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
|
28
|
+
pattern = "#{pattern}:*" unless pattern.end_with?(':*')
|
59
29
|
|
60
|
-
|
61
|
-
|
62
|
-
|
30
|
+
log_debug { "Deleting keys by: #{pattern}" }
|
31
|
+
keys, time = timed { keys(pattern, count) }
|
32
|
+
key_size = keys.size
|
33
|
+
log_debug { "#{key_size} keys found in #{time} sec." }
|
34
|
+
_, time = timed { batch_delete(keys) }
|
35
|
+
log_debug { "Deleted #{key_size} keys in #{time} sec." }
|
63
36
|
|
64
|
-
|
37
|
+
key_size
|
65
38
|
end
|
66
39
|
|
67
40
|
private
|
68
41
|
|
69
|
-
def get_jobs(conn, cursor)
|
70
|
-
conn.hscan(SidekiqUniqueJobs::HASH_KEY, [cursor, MATCH, SCAN_PATTERN, COUNT, EXPIRE_BATCH_SIZE])
|
71
|
-
end
|
72
|
-
|
73
|
-
def keys_by_scan(pattern, count)
|
74
|
-
connection { |conn| conn.scan_each(match: prefix(pattern), count: count).to_a }
|
75
|
-
end
|
76
|
-
|
77
|
-
def keys_by_keys(pattern, _count)
|
78
|
-
connection { |conn| conn.keys(prefix(pattern)).to_a }
|
79
|
-
end
|
80
|
-
|
81
42
|
def batch_delete(keys)
|
82
|
-
|
43
|
+
redis do |conn|
|
83
44
|
keys.each_slice(500) do |chunk|
|
84
45
|
conn.pipelined do
|
85
46
|
chunk.each do |key|
|
@@ -90,22 +51,15 @@ module SidekiqUniqueJobs
|
|
90
51
|
end
|
91
52
|
end
|
92
53
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
def timed(&_block)
|
100
|
-
start = Time.now
|
101
|
-
result = yield
|
102
|
-
elapsed = (Time.now - start).round(2)
|
54
|
+
def timed
|
55
|
+
start = current_time
|
56
|
+
result = yield
|
57
|
+
elapsed = (current_time - start).round(2)
|
103
58
|
[result, elapsed]
|
104
59
|
end
|
105
60
|
|
106
|
-
def
|
107
|
-
|
108
|
-
keys.map { |key| prefix(key) }
|
61
|
+
def current_time
|
62
|
+
Time.now
|
109
63
|
end
|
110
64
|
|
111
65
|
def prefix(key)
|
@@ -117,21 +71,5 @@ module SidekiqUniqueJobs
|
|
117
71
|
def unique_prefix
|
118
72
|
SidekiqUniqueJobs.config.unique_prefix
|
119
73
|
end
|
120
|
-
|
121
|
-
def connection(&block)
|
122
|
-
SidekiqUniqueJobs.connection(&block)
|
123
|
-
end
|
124
|
-
|
125
|
-
def redis_version
|
126
|
-
SidekiqUniqueJobs.redis_version
|
127
|
-
end
|
128
|
-
|
129
|
-
def redis_keys_method
|
130
|
-
(redis_version >= '2.8') ? SCAN_METHOD : KEYS_METHOD
|
131
|
-
end
|
132
|
-
|
133
|
-
def logger
|
134
|
-
SidekiqUniqueJobs.logger
|
135
|
-
end
|
136
74
|
end
|
137
75
|
end
|
data/redis/acquire_lock.lua
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
local unique_key = KEYS[1]
|
2
2
|
local job_id = ARGV[1]
|
3
|
-
local expires = ARGV[2]
|
3
|
+
local expires = tonumber(ARGV[2])
|
4
4
|
local stored_jid = redis.pcall('get', unique_key)
|
5
5
|
|
6
6
|
if stored_jid then
|
@@ -11,8 +11,10 @@ if stored_jid then
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
if redis.
|
15
|
-
|
14
|
+
if redis.call('SET', unique_key, job_id, 'nx') then
|
15
|
+
if expires then
|
16
|
+
redis.call('EXPIRE', unique_key, expires)
|
17
|
+
end
|
16
18
|
return 1
|
17
19
|
else
|
18
20
|
return 0
|