resque-unique_in_queue 2.0.0 → 2.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 +147 -0
- data/LICENSE.md +14 -0
- data/README.md +517 -63
- data/lib/resque/plugins/unique_in_queue.rb +8 -5
- data/lib/resque/unique_in_queue/configuration.rb +18 -17
- data/lib/resque/unique_in_queue/queue.rb +8 -7
- data/lib/resque/unique_in_queue/resque_ext/job.rb +12 -12
- data/lib/resque/unique_in_queue/resque_ext/resque.rb +4 -4
- data/lib/resque/unique_in_queue/version.rb +7 -1
- data/lib/resque/unique_in_queue.rb +8 -0
- data/lib/resque-unique_in_queue.rb +20 -12
- data/sig/resque/unique_in_queue.rbs +8 -0
- data.tar.gz.sig +0 -0
- metadata +176 -57
- metadata.gz.sig +0 -0
- data/.gitignore +0 -17
- data/.rubocop.yml +0 -2
- data/.rubocop_todo.yml +0 -91
- data/.ruby-version +0 -1
- data/.travis.yml +0 -7
- data/Gemfile +0 -18
- data/LICENSE +0 -24
- data/Rakefile +0 -14
- data/resque-unique_in_queue.gemspec +0 -34
|
@@ -18,6 +18,8 @@ module Resque
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
module ClassMethods
|
|
21
|
+
# The plugin stores per-job configuration on the job class.
|
|
22
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
21
23
|
def unique_in_queue_redis_key(queue, item)
|
|
22
24
|
"#{unique_in_queue_key_base}:queue:#{queue}:job:#{Resque::UniqueInQueue::Queue.const_for(item).redis_key(item)}"
|
|
23
25
|
end
|
|
@@ -26,8 +28,8 @@ module Resque
|
|
|
26
28
|
# a hash containing string keys 'class' and 'args'
|
|
27
29
|
def redis_key(payload)
|
|
28
30
|
payload = Resque.decode(Resque.encode(payload))
|
|
29
|
-
job
|
|
30
|
-
args = payload[
|
|
31
|
+
job = payload["class"]
|
|
32
|
+
args = payload["args"]
|
|
31
33
|
args.map! do |arg|
|
|
32
34
|
arg.is_a?(Hash) ? arg.sort : arg
|
|
33
35
|
end
|
|
@@ -46,7 +48,7 @@ module Resque
|
|
|
46
48
|
# end
|
|
47
49
|
def lock_after_execution_period
|
|
48
50
|
instance_variable_get(:@lock_after_execution_period) ||
|
|
49
|
-
|
|
51
|
+
instance_variable_set(:@lock_after_execution_period, Resque::UniqueInQueue.configuration&.lock_after_execution_period)
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
# The default ttl of a locking key is -1 (forever).
|
|
@@ -59,7 +61,7 @@ module Resque
|
|
|
59
61
|
# end
|
|
60
62
|
def ttl
|
|
61
63
|
instance_variable_get(:@ttl) ||
|
|
62
|
-
|
|
64
|
+
instance_variable_set(:@ttl, Resque::UniqueInQueue.configuration&.ttl)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
# Should not generally be overridden per each class because it wouldn't
|
|
@@ -68,8 +70,9 @@ module Resque
|
|
|
68
70
|
# and general cleanup of stray keys would be nearly impossible.
|
|
69
71
|
def unique_in_queue_key_base
|
|
70
72
|
instance_variable_get(:@unique_in_queue_key_base) ||
|
|
71
|
-
|
|
73
|
+
instance_variable_set(:@unique_in_queue_key_base, Resque::UniqueInQueue.configuration&.unique_in_queue_key_base)
|
|
72
74
|
end
|
|
75
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
73
76
|
end
|
|
74
77
|
end
|
|
75
78
|
end
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "logger"
|
|
2
2
|
module Resque
|
|
3
3
|
module UniqueInQueue
|
|
4
4
|
class Configuration
|
|
5
5
|
DEFAULT_LOCK_AFTER_EXECUTION_PERIOD = 0
|
|
6
6
|
DEFAULT_TTL = -1
|
|
7
|
-
DEFAULT_UNIQUE_IN_QUEUE_KEY_BASE =
|
|
7
|
+
DEFAULT_UNIQUE_IN_QUEUE_KEY_BASE = "r-uiq".freeze
|
|
8
8
|
DEFAULT_LOG_LEVEL = :debug
|
|
9
9
|
|
|
10
10
|
include Singleton
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
attr_reader :debug_mode
|
|
13
|
+
|
|
14
|
+
attr_accessor :lock_after_execution_period,
|
|
15
|
+
:log_level,
|
|
16
|
+
:logger,
|
|
17
|
+
:ttl,
|
|
18
|
+
:unique_in_queue_key_base
|
|
18
19
|
|
|
19
20
|
def initialize
|
|
20
21
|
debug_mode_from_env
|
|
@@ -25,18 +26,18 @@ module Resque
|
|
|
25
26
|
@unique_in_queue_key_base = DEFAULT_UNIQUE_IN_QUEUE_KEY_BASE
|
|
26
27
|
if @debug_mode
|
|
27
28
|
# Make sure there is a logger when in debug_mode
|
|
28
|
-
@logger ||= Logger.new(
|
|
29
|
+
@logger ||= Logger.new($stdout)
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def to_hash
|
|
33
34
|
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
debug_mode: debug_mode,
|
|
36
|
+
lock_after_execution_period: lock_after_execution_period,
|
|
37
|
+
log_level: log_level,
|
|
38
|
+
logger: logger,
|
|
39
|
+
ttl: ttl,
|
|
40
|
+
unique_in_queue_key_base: unique_in_queue_key_base
|
|
40
41
|
}
|
|
41
42
|
end
|
|
42
43
|
|
|
@@ -47,8 +48,8 @@ module Resque
|
|
|
47
48
|
private
|
|
48
49
|
|
|
49
50
|
def debug_mode_from_env
|
|
50
|
-
env_debug = ENV[
|
|
51
|
-
@debug_mode = !!(env_debug ==
|
|
51
|
+
env_debug = ENV["RESQUE_DEBUG"]
|
|
52
|
+
@debug_mode = !!(env_debug == "true" || (env_debug.is_a?(String) && env_debug.match?(/queue/)))
|
|
52
53
|
end
|
|
53
54
|
end
|
|
54
55
|
end
|
|
@@ -4,7 +4,7 @@ module Resque
|
|
|
4
4
|
def queued?(queue, item)
|
|
5
5
|
return false unless is_unique?(item)
|
|
6
6
|
|
|
7
|
-
redis.get(unique_key(queue, item)) ==
|
|
7
|
+
redis.get(unique_key(queue, item)) == "1"
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def mark_queued(queue, item)
|
|
@@ -56,16 +56,17 @@ module Resque
|
|
|
56
56
|
|
|
57
57
|
redis.lrange(redis_queue, 0, -1).each do |string|
|
|
58
58
|
json = Resque.decode(string)
|
|
59
|
-
next unless json[
|
|
60
|
-
next if args.any? && json[
|
|
59
|
+
next unless json["class"] == klass
|
|
60
|
+
next if args.any? && json["args"] != args
|
|
61
61
|
|
|
62
62
|
Resque::UniqueInQueue::Queue.mark_unqueued(queue, json)
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def cleanup(queue)
|
|
67
|
-
|
|
68
|
-
redis.
|
|
67
|
+
pattern = "#{Resque::UniqueInQueue.configuration&.unique_in_queue_key_base}:queue:#{queue}:job:*"
|
|
68
|
+
keys = redis.scan_each(match: pattern, count: 1_000_000).to_a
|
|
69
|
+
redis.del(keys) if keys.any?
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
private
|
|
@@ -75,12 +76,12 @@ module Resque
|
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
def item_class(item)
|
|
78
|
-
item[:class] || item[
|
|
79
|
+
item[:class] || item["class"]
|
|
79
80
|
end
|
|
80
81
|
|
|
81
82
|
def const_for(item)
|
|
82
83
|
Resque.constantize(item_class(item))
|
|
83
|
-
|
|
84
|
+
end
|
|
84
85
|
|
|
85
86
|
module_function :queued?, :mark_queued, :mark_unqueued, :unique_key
|
|
86
87
|
module_function :is_unique?, :item_ttl, :lock_after_execution_period
|
|
@@ -3,11 +3,11 @@ module Resque
|
|
|
3
3
|
class << self
|
|
4
4
|
# Mark an item as queued
|
|
5
5
|
def create_unique_in_queue(queue, klass, *args)
|
|
6
|
-
item = {
|
|
6
|
+
item = {class: klass.to_s, args: args}
|
|
7
7
|
if Resque.inline? || !Resque::UniqueInQueue::Queue.is_unique?(item)
|
|
8
8
|
return create_without_unique_in_queue(queue, klass, *args)
|
|
9
9
|
end
|
|
10
|
-
return
|
|
10
|
+
return "EXISTED" if Resque::UniqueInQueue::Queue.queued?(queue, item)
|
|
11
11
|
|
|
12
12
|
create_return_value = false
|
|
13
13
|
# redis transaction block
|
|
@@ -31,21 +31,21 @@ module Resque
|
|
|
31
31
|
destroy_without_unique_in_queue(queue, klass, *args)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
alias_method :create_without_unique_in_queue, :create
|
|
35
|
+
alias_method :create, :create_unique_in_queue
|
|
36
|
+
alias_method :reserve_without_unique_in_queue, :reserve
|
|
37
|
+
alias_method :reserve, :reserve_unique_in_queue
|
|
38
|
+
alias_method :destroy_without_unique_in_queue, :destroy
|
|
39
|
+
alias_method :destroy, :destroy_unique_in_queue
|
|
40
40
|
|
|
41
41
|
if defined?(Resque::Plugins::PriorityEnqueue::Resque)
|
|
42
42
|
# Hack to support resque-priority_enqueue: https://github.com/coupa/resque-priority_enqueue
|
|
43
43
|
def priority_create_unique_in_queue(queue, klass, *args)
|
|
44
|
-
item = {
|
|
44
|
+
item = {class: klass.to_s, args: args}
|
|
45
45
|
if Resque.inline? || !Resque::UniqueInQueue::Queue.is_unique?(item)
|
|
46
46
|
return priority_create_without_unique_in_queue(queue, klass, *args)
|
|
47
47
|
end
|
|
48
|
-
return
|
|
48
|
+
return "EXISTED" if Resque::UniqueInQueue::Queue.queued?(queue, item)
|
|
49
49
|
|
|
50
50
|
priority_create_return_value = false
|
|
51
51
|
# redis transaction block
|
|
@@ -56,8 +56,8 @@ module Resque
|
|
|
56
56
|
priority_create_return_value
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
alias_method :priority_create_without_unique_in_queue, :priority_create
|
|
60
|
+
alias_method :priority_create, :priority_create_unique_in_queue
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
end
|
|
@@ -10,7 +10,7 @@ module Resque
|
|
|
10
10
|
return nil if before_hooks.any? { |result| result == false }
|
|
11
11
|
|
|
12
12
|
result = Job.create(queue, klass, *args)
|
|
13
|
-
return nil if result ==
|
|
13
|
+
return nil if result == "EXISTED"
|
|
14
14
|
|
|
15
15
|
Plugin.after_enqueue_hooks(klass).each do |hook|
|
|
16
16
|
klass.send(hook, *args)
|
|
@@ -24,7 +24,7 @@ module Resque
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def enqueued_in?(queue, klass, *args)
|
|
27
|
-
item = {
|
|
27
|
+
item = {class: klass.to_s, args: args}
|
|
28
28
|
return nil unless Resque::UniqueInQueue::Queue.is_unique?(item)
|
|
29
29
|
|
|
30
30
|
Resque::UniqueInQueue::Queue.queued?(queue, item)
|
|
@@ -35,7 +35,7 @@ module Resque
|
|
|
35
35
|
Resque::UniqueInQueue::Queue.cleanup(queue)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
alias_method :remove_queue_without_unique_in_queue_cleanup, :remove_queue
|
|
39
|
+
alias_method :remove_queue, :remove_queue_with_unique_in_queue_cleanup
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Resque
|
|
4
4
|
module UniqueInQueue
|
|
5
|
-
|
|
5
|
+
# Version namespace for this gem.
|
|
6
|
+
module Version
|
|
7
|
+
# Current gem version.
|
|
8
|
+
VERSION = "2.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,20 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "resque/unique_in_queue/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
|
|
16
|
-
require
|
|
17
|
-
require
|
|
12
|
+
require "resque/plugins/unique_in_queue"
|
|
13
|
+
require "resque/unique_in_queue/resque_ext/job"
|
|
14
|
+
require "resque/unique_in_queue/resque_ext/resque"
|
|
15
|
+
require "resque/unique_in_queue/queue"
|
|
16
|
+
require "resque/unique_in_queue/configuration"
|
|
18
17
|
|
|
19
18
|
# See lib/resque/plugins/unique_in_queue.rb for the actual plugin
|
|
20
19
|
#
|
|
@@ -23,10 +22,16 @@ require 'resque/unique_in_queue/configuration'
|
|
|
23
22
|
# Resque, Resque::Job, or Resque::Queue.
|
|
24
23
|
module Resque
|
|
25
24
|
module UniqueInQueue
|
|
26
|
-
|
|
25
|
+
# Wraps text in ANSI blue escape codes. Replaces the former `colorize`
|
|
26
|
+
# dependency; produces the exact sequence colorize's String#blue emitted.
|
|
27
|
+
def self.blue_text(text)
|
|
28
|
+
"\e[0;34;49m#{text}\e[0m"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
PLUGIN_TAG = blue_text("[R-UIQ] ").freeze
|
|
27
32
|
|
|
28
33
|
def log(message)
|
|
29
|
-
configuration.logger&.send(configuration.log_level, message)
|
|
34
|
+
configuration.logger&.send(configuration.log_level, message)
|
|
30
35
|
end
|
|
31
36
|
|
|
32
37
|
def debug(message)
|
|
@@ -40,12 +45,15 @@ module Resque
|
|
|
40
45
|
|
|
41
46
|
#### CONFIG ####
|
|
42
47
|
class << self
|
|
48
|
+
# The plugin exposes one replaceable configuration object by design.
|
|
49
|
+
# rubocop:disable ThreadSafety/ClassAndModuleAttributes
|
|
43
50
|
attr_accessor :configuration
|
|
51
|
+
# rubocop:enable ThreadSafety/ClassAndModuleAttributes
|
|
44
52
|
end
|
|
45
53
|
|
|
46
54
|
self.configuration = Configuration.instance # setup defaults
|
|
47
55
|
|
|
48
56
|
module_function(:log,
|
|
49
|
-
|
|
57
|
+
:debug)
|
|
50
58
|
end
|
|
51
59
|
end
|
data.tar.gz.sig
ADDED
|
Binary file
|