resque-unique_at_runtime 4.0.1 → 4.0.2
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +149 -0
- data/LICENSE.md +15 -0
- data/README.md +506 -79
- data/lib/resque/plugins/unique_at_runtime.rb +64 -13
- data/lib/resque/unique_at_runtime/configuration.rb +9 -9
- data/lib/resque/unique_at_runtime/version.rb +7 -1
- data/lib/resque/unique_at_runtime.rb +8 -0
- data/lib/resque-unique_at_runtime.rb +8 -9
- data/sig/resque/unique_at_runtime.rbs +8 -0
- data.tar.gz.sig +0 -0
- metadata +212 -60
- metadata.gz.sig +0 -0
- data/.gitignore +0 -17
- data/.rubocop.yml +0 -2
- data/.rubocop_todo.yml +0 -75
- data/.ruby-version +0 -1
- data/.travis.yml +0 -35
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -19
- data/LICENSE +0 -23
- data/Rakefile +0 -10
- data/resque-unique_at_runtime.gemspec +0 -54
|
@@ -15,6 +15,16 @@ module Resque
|
|
|
15
15
|
# end
|
|
16
16
|
#
|
|
17
17
|
module UniqueAtRuntime
|
|
18
|
+
ATOMIC_LOCK_SCRIPT = <<~LUA
|
|
19
|
+
local previous_timeout = redis.call("HGET", KEYS[1], ARGV[1])
|
|
20
|
+
if previous_timeout and tonumber(previous_timeout) > tonumber(ARGV[3]) then
|
|
21
|
+
return 0
|
|
22
|
+
end
|
|
23
|
+
redis.call("HSET", KEYS[1], ARGV[1], ARGV[2])
|
|
24
|
+
return 1
|
|
25
|
+
LUA
|
|
26
|
+
LEGACY_LOCK_MUTEX = Mutex.new
|
|
27
|
+
|
|
18
28
|
def self.included(base)
|
|
19
29
|
base.extend ClassMethods
|
|
20
30
|
end
|
|
@@ -26,24 +36,25 @@ module Resque
|
|
|
26
36
|
|
|
27
37
|
def runtime_lock_timeout
|
|
28
38
|
instance_variable_get(:@runtime_lock_timeout) ||
|
|
29
|
-
|
|
39
|
+
instance_variable_set(:@runtime_lock_timeout, Resque::UniqueAtRuntime.configuration&.lock_timeout)
|
|
30
40
|
end
|
|
31
41
|
|
|
32
42
|
def runtime_requeue_interval
|
|
33
43
|
instance_variable_get(:@runtime_requeue_interval) ||
|
|
34
|
-
|
|
44
|
+
instance_variable_set(:@runtime_requeue_interval, Resque::UniqueAtRuntime.configuration&.requeue_interval)
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
def unique_at_runtime_key_base
|
|
38
48
|
instance_variable_get(:@unique_at_runtime_key_base) ||
|
|
39
|
-
|
|
49
|
+
instance_variable_set(:@unique_at_runtime_key_base, Resque::UniqueAtRuntime.configuration&.unique_at_runtime_key_base)
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
# Overwrite this method to uniquely identify which mutex should be used
|
|
43
53
|
# for a resque worker.
|
|
44
54
|
def unique_at_runtime_redis_key(*_)
|
|
45
|
-
Resque
|
|
46
|
-
"#{
|
|
55
|
+
queue = Resque.queue_from_class(self)
|
|
56
|
+
Resque::UniqueAtRuntime.debug("getting key for #{queue}!")
|
|
57
|
+
queue
|
|
47
58
|
end
|
|
48
59
|
|
|
49
60
|
# returns true if the job signature can be locked (is not currently locked)
|
|
@@ -59,18 +70,56 @@ module Resque
|
|
|
59
70
|
|
|
60
71
|
Resque::UniqueAtRuntime.debug("attempting to lock queue with #{key}")
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
case atomic_lock_result(key, timeout, now)
|
|
74
|
+
when 1
|
|
75
|
+
false
|
|
76
|
+
when 0
|
|
77
|
+
key
|
|
78
|
+
else
|
|
79
|
+
legacy_queue_locked(key, timeout, now)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def atomic_lock_result(key, timeout, now)
|
|
86
|
+
result = Resque.redis.eval(
|
|
87
|
+
Resque::Plugins::UniqueAtRuntime::ATOMIC_LOCK_SCRIPT,
|
|
88
|
+
[unique_at_runtime_key_base],
|
|
89
|
+
[key, timeout, now]
|
|
90
|
+
)
|
|
91
|
+
result&.to_i
|
|
92
|
+
rescue NoMethodError, NotImplementedError, Redis::CommandError
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# FakeRedis 0.9 exposes EVAL without implementing it. Keep the old
|
|
97
|
+
# command path for that test double and older Redis clients; the mutex
|
|
98
|
+
# only makes this compatibility path deterministic within one process.
|
|
99
|
+
def legacy_queue_locked(key, timeout, now)
|
|
100
|
+
Resque::Plugins::UniqueAtRuntime::LEGACY_LOCK_MUTEX.synchronize do
|
|
101
|
+
return false if Resque.redis.hsetnx(unique_at_runtime_key_base, key, timeout)
|
|
102
|
+
|
|
103
|
+
previous_timeout = Resque.redis.hget(unique_at_runtime_key_base, key).to_i
|
|
104
|
+
return key if previous_timeout > now
|
|
66
105
|
|
|
67
|
-
|
|
106
|
+
Resque.redis.hset(unique_at_runtime_key_base, key, timeout)
|
|
107
|
+
false
|
|
108
|
+
end
|
|
68
109
|
end
|
|
69
110
|
|
|
111
|
+
public
|
|
112
|
+
|
|
70
113
|
def unlock_queue(*args)
|
|
114
|
+
if @unlock_queue_executed
|
|
115
|
+
Resque::UniqueAtRuntime.debug("unlock queue already executed")
|
|
116
|
+
return
|
|
117
|
+
end
|
|
118
|
+
|
|
71
119
|
key = unique_at_runtime_redis_key(*args)
|
|
72
120
|
Resque::UniqueAtRuntime.debug("unlock queue with #{key}")
|
|
73
|
-
Resque.redis.
|
|
121
|
+
Resque.redis.hdel(unique_at_runtime_key_base, key)
|
|
122
|
+
@unlock_queue_executed = true
|
|
74
123
|
end
|
|
75
124
|
|
|
76
125
|
def reenqueue(*args)
|
|
@@ -90,12 +139,14 @@ module Resque
|
|
|
90
139
|
# and don't perform
|
|
91
140
|
raise Resque::Job::DontPerform
|
|
92
141
|
else
|
|
93
|
-
Resque::UniqueAtRuntime.debug(
|
|
142
|
+
Resque::UniqueAtRuntime.debug("check passed will perform")
|
|
94
143
|
true
|
|
95
144
|
end
|
|
96
145
|
end
|
|
97
146
|
|
|
98
147
|
def around_perform_unlock_runtime(*args)
|
|
148
|
+
@unlock_queue_executed = false
|
|
149
|
+
|
|
99
150
|
yield
|
|
100
151
|
ensure
|
|
101
152
|
unlock_queue(*args)
|
|
@@ -105,7 +156,7 @@ module Resque
|
|
|
105
156
|
# duplicates the on_failure unlock, but that's a small price to pay for
|
|
106
157
|
# uniqueness.
|
|
107
158
|
def on_failure_unlock_runtime(*args)
|
|
108
|
-
Resque::UniqueAtRuntime.debug(
|
|
159
|
+
Resque::UniqueAtRuntime.debug("on failure unlock")
|
|
109
160
|
unlock_queue(*args)
|
|
110
161
|
end
|
|
111
162
|
end
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "logger"
|
|
4
4
|
module Resque
|
|
5
5
|
module UniqueAtRuntime
|
|
6
6
|
class Configuration
|
|
7
7
|
DEFAULT_LOCK_TIMEOUT = 60 * 60 * 24 * 5
|
|
8
8
|
DEFAULT_REQUEUE_INTERVAL = 1
|
|
9
|
-
DEFAULT_UNIQUE_AT_RUNTIME_KEY_BASE =
|
|
9
|
+
DEFAULT_UNIQUE_AT_RUNTIME_KEY_BASE = "r-uar"
|
|
10
10
|
DEFAULT_LOG_LEVEL = :debug
|
|
11
11
|
|
|
12
12
|
include Singleton
|
|
13
13
|
|
|
14
14
|
attr_accessor :debug_mode,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
:lock_timeout,
|
|
16
|
+
:log_level,
|
|
17
|
+
:logger,
|
|
18
|
+
:requeue_interval,
|
|
19
|
+
:unique_at_runtime_key_base
|
|
20
20
|
|
|
21
21
|
def initialize
|
|
22
22
|
debug_mode_from_env
|
|
@@ -49,8 +49,8 @@ module Resque
|
|
|
49
49
|
private
|
|
50
50
|
|
|
51
51
|
def debug_mode_from_env
|
|
52
|
-
env_debug = ENV[
|
|
53
|
-
@debug_mode = !!(env_debug ==
|
|
52
|
+
env_debug = ENV["RESQUE_DEBUG"]
|
|
53
|
+
@debug_mode = !!(env_debug == "true" || (env_debug.is_a?(String) && env_debug.match(/runtime/)))
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Resque
|
|
4
4
|
module UniqueAtRuntime
|
|
5
|
-
|
|
5
|
+
# Version namespace for this gem.
|
|
6
|
+
module Version
|
|
7
|
+
# Current gem version.
|
|
8
|
+
VERSION = "4.0.2"
|
|
9
|
+
end
|
|
10
|
+
# Current gem version exposed at the traditional constant location.
|
|
11
|
+
VERSION = Version::VERSION # Traditional Constant Location
|
|
6
12
|
end
|
|
7
13
|
end
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "resque/unique_at_runtime/version"
|
|
4
4
|
|
|
5
5
|
# Ruby Std Lib
|
|
6
|
-
require
|
|
6
|
+
require "digest/md5"
|
|
7
7
|
|
|
8
8
|
# External Gems
|
|
9
|
-
require
|
|
10
|
-
require 'resque'
|
|
9
|
+
require "resque"
|
|
11
10
|
|
|
12
11
|
# This Gem
|
|
13
|
-
require
|
|
14
|
-
require
|
|
15
|
-
require
|
|
12
|
+
require "resque/plugins/unique_at_runtime"
|
|
13
|
+
require "resque/unique_at_runtime/resque_ext/resque"
|
|
14
|
+
require "resque/unique_at_runtime/configuration"
|
|
16
15
|
|
|
17
16
|
# See lib/resque/plugins/unique_at_runtime.rb for the actual plugin
|
|
18
17
|
#
|
|
@@ -21,7 +20,7 @@ require 'resque/unique_at_runtime/configuration'
|
|
|
21
20
|
# Resque, Resque::Job, or Resque::Queue.
|
|
22
21
|
module Resque
|
|
23
22
|
module UniqueAtRuntime
|
|
24
|
-
PLUGIN_TAG =
|
|
23
|
+
PLUGIN_TAG = "[R-UAR] "
|
|
25
24
|
|
|
26
25
|
def log(message)
|
|
27
26
|
configuration.logger&.send(configuration.log_level, message) if configuration.logger
|
|
@@ -44,6 +43,6 @@ module Resque
|
|
|
44
43
|
self.configuration = Configuration.instance # setup defaults
|
|
45
44
|
|
|
46
45
|
module_function(:log,
|
|
47
|
-
|
|
46
|
+
:debug)
|
|
48
47
|
end
|
|
49
48
|
end
|
data.tar.gz.sig
ADDED
|
Binary file
|