resque-unique_by_arity 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/resque/unique_by_arity.rb +8 -0
- data/lib/resque/unique_by_arity/configuration.rb +34 -4
- data/lib/resque/unique_by_arity/cop.rb +3 -1
- data/lib/resque/unique_by_arity/cop_modulizer.rb +5 -5
- data/lib/resque/unique_by_arity/validation.rb +12 -0
- data/lib/resque/unique_by_arity/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74a015294d4c2dfa38a26395f3c83747c49cc380
|
4
|
+
data.tar.gz: 3a2aa2f9318deaab45185805561efde660c2dda0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f811ec7c91598ddd783b69c1eeedb6ca7f5bf0b2b75b04c5d637bd6cd143c4f3f292cb16f82cca03d2b72227c201a9690bbbe5f0dcd2ef45bd69e129859741e2
|
7
|
+
data.tar.gz: 7be024ae58c1a2a70c12add6f5b24d471bc7b85c6ac26db7c20b9d7236a7e3ee3d54a645d953ca350ca37a077a88460e2aca7655be8ad0f0f3cb8451d1774f40
|
data/README.md
CHANGED
@@ -158,7 +158,7 @@ class MyJob
|
|
158
158
|
def self.redis_unique_hash(payload)
|
159
159
|
# ... See source @ lib/resque/unique_by_arity/cop_modulizer.rb
|
160
160
|
# for how the built-in version works
|
161
|
-
# uniqueness_args = payload["args"] # over simplified
|
161
|
+
# uniqueness_args = payload["args"] # over simplified & ignoring arity
|
162
162
|
# args = { class: job, args: uniqueness_args }
|
163
163
|
# return [Digest::MD5.hexdigest(Resque.encode(args)), uniqueness_args]
|
164
164
|
end
|
@@ -9,12 +9,14 @@ require "resque/unique_by_arity/version"
|
|
9
9
|
require "resque/unique_by_arity/configuration"
|
10
10
|
require "resque/unique_by_arity/cop"
|
11
11
|
require "resque/unique_by_arity/cop_modulizer"
|
12
|
+
require "resque/unique_by_arity/validation"
|
12
13
|
|
13
14
|
# Usage:
|
14
15
|
#
|
15
16
|
# class MyJob
|
16
17
|
# include UniqueByArity::Cop.new(
|
17
18
|
# arity_for_uniqueness: 1,
|
19
|
+
# arity_for_validation: :warning, # or nil, false, or :error
|
18
20
|
# unique_at_runtime: true,
|
19
21
|
# unique_in_queue: true
|
20
22
|
# )
|
@@ -58,6 +60,12 @@ module Resque
|
|
58
60
|
def uniqueness_arity_for_uniqueness=(arity_for_uniqueness)
|
59
61
|
@uniqueness_configuration.arity_for_uniqueness = arity_for_uniqueness
|
60
62
|
end
|
63
|
+
def uniqueness_arity_for_validation
|
64
|
+
@uniqueness_configuration.arity_validation
|
65
|
+
end
|
66
|
+
def uniqueness_arity_for_validation=(arity_validation)
|
67
|
+
@uniqueness_configuration.arity_validation = arity_validation
|
68
|
+
end
|
61
69
|
def uniqueness_lock_after_execution_period
|
62
70
|
@uniqueness_configuration.lock_after_execution_period
|
63
71
|
end
|
@@ -2,9 +2,11 @@ require 'logger'
|
|
2
2
|
module Resque
|
3
3
|
module UniqueByArity
|
4
4
|
class Configuration
|
5
|
+
VALID_ARITY_VALIDATION_LEVELS = [ :warning, :error, nil, false ]
|
5
6
|
attr_accessor :logger
|
6
7
|
attr_accessor :log_level
|
7
8
|
attr_accessor :arity_for_uniqueness
|
9
|
+
attr_accessor :arity_validation
|
8
10
|
attr_accessor :lock_after_execution_period
|
9
11
|
attr_accessor :unique_at_runtime
|
10
12
|
attr_accessor :unique_in_queue
|
@@ -13,17 +15,20 @@ module Resque
|
|
13
15
|
@logger = options.key?(:logger) ? options[:logger] : Logger.new(STDOUT)
|
14
16
|
@log_level = options.key?(:log_level) ? options[:log_level] : :debug
|
15
17
|
@arity_for_uniqueness = options.key?(:arity_for_uniqueness) ? options[:arity_for_uniqueness] : 1
|
18
|
+
@arity_validation = options.key?(:arity_validation) ? options[:arity_validation] : :warning
|
19
|
+
raise ArgumentError, "UniqueByArity::Cop.new requires arity_validation values of nil, false, :warning, :error, or an class descending from Exception but the value is #{@arity_validation} (#{@arity_validation.class})" unless VALID_ARITY_VALIDATION_LEVELS.include?(@arity_validation) || @arity_validation.ancestors.include?(Exception)
|
16
20
|
@lock_after_execution_period = options.key?(:lock_after_execution_period) ? options[:lock_after_execution_period] : nil
|
17
21
|
@unique_at_runtime = options.key?(:unique_at_runtime) ? options[:unique_at_runtime] : false
|
18
22
|
@unique_in_queue = options.key?(:unique_in_queue) ? options[:unique_in_queue] : false
|
19
23
|
@unique_across_queues = options.key?(:unique_across_queues) ? options[:unique_across_queues] : false
|
20
24
|
# The default config initialization shouldn't trigger any warnings.
|
21
|
-
if options.keys.length > 0
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
if options.keys.length > 0 && @logger
|
26
|
+
Resque::UniqueByArity.unique_log ":arity_for_uniqueness is set to #{@arity_for_uniqueness}, but no uniqueness enforcement was turned on [:unique_at_runtime, :unique_in_queue, :unique_across_queues]" unless @unique_at_runtime || @unique_in_queue || @unique_across_queues
|
27
|
+
Resque::UniqueByArity.unique_log ":lock_after_execution_period is set to #{@lock_after_execution_period}, but :unique_at_runtime is not set" if @lock_after_execution_period && !@unique_at_runtime
|
28
|
+
Resque::UniqueByArity.unique_log ":unique_in_queue and :unique_across_queues should not be set at the same time, as :unique_across_queues will always supercede :unique_in_queue" if @unique_in_queue && @unique_across_queues
|
25
29
|
end
|
26
30
|
end
|
31
|
+
|
27
32
|
def to_hash
|
28
33
|
{
|
29
34
|
logger: logger,
|
@@ -35,6 +40,31 @@ module Resque
|
|
35
40
|
unique_across_queues: unique_across_queues
|
36
41
|
}
|
37
42
|
end
|
43
|
+
|
44
|
+
def validate_arity(klass_string, perform_method)
|
45
|
+
return true unless arity_validation
|
46
|
+
# method.arity -
|
47
|
+
# Returns an indication of the number of arguments accepted by a method.
|
48
|
+
# Returns a non-negative integer for methods that take a fixed number of arguments.
|
49
|
+
# For Ruby methods that take a variable number of arguments, returns -n-1, where n is the number of required arguments.
|
50
|
+
# For methods written in C, returns -1 if the call takes a variable number of arguments.
|
51
|
+
# Example:
|
52
|
+
# for perform(opts = {}), method(:perform).arity # => -1
|
53
|
+
# which means that the only valid arity_for_uniqueness is 0
|
54
|
+
msg = if perform_method.arity < (arity_for_uniqueness - 1)
|
55
|
+
"#{klass_string}.#{perform_method.name} has arity of #{perform_method.arity} which will not work with arity_for_uniqueness of #{arity_for_uniqueness}"
|
56
|
+
elsif (required_parameter_names = perform_method.parameters.take_while { |a| a[0] == :req }.map { |b| b[1] }).length < arity_for_uniqueness
|
57
|
+
"#{klass_string}.#{perform_method.name} has the following required parameters: #{required_parameter_names}, which is not enough to satisfy the configured arity_for_uniqueness of #{arity_for_uniqueness}"
|
58
|
+
end
|
59
|
+
case arity_validation
|
60
|
+
when :warning then
|
61
|
+
Resque::UniqueByArity.unique_log(msg)
|
62
|
+
when :error then
|
63
|
+
raise ArgumentError, msg
|
64
|
+
else
|
65
|
+
raise arity_validation, msg
|
66
|
+
end if msg
|
67
|
+
end
|
38
68
|
end
|
39
69
|
end
|
40
70
|
end
|
@@ -14,13 +14,15 @@ module Resque
|
|
14
14
|
# defines a redis_key method, which we have to override.
|
15
15
|
base.send(:include, Resque::Plugins::UniqueJob) if @configuration.unique_in_queue || @configuration.unique_across_queues
|
16
16
|
|
17
|
-
# gem is resque-unique_at_runtime
|
17
|
+
# gem is resque-unique_at_runtime, which is a rewrite of resque-lonely_job
|
18
18
|
# see: https://github.com/pboling/resque-unique_at_runtime
|
19
19
|
base.send(:extend, Resque::Plugins::UniqueAtRuntime) if @configuration.unique_at_runtime
|
20
20
|
|
21
21
|
uniqueness_cop_module = Resque::UniqueByArity::CopModulizer.to_mod(@configuration)
|
22
22
|
# This will override methods from both plugins above, if configured for both
|
23
23
|
base.send(:extend, uniqueness_cop_module)
|
24
|
+
|
25
|
+
base.singleton_class.prepend Resque::UniqueByArity::Validation
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -7,7 +7,7 @@ module Resque
|
|
7
7
|
# @return [Array<String, arguments>] the key base hash used to enforce uniqueness, and the arguments from the payload used to calculate it
|
8
8
|
define_method(:redis_unique_hash) do |payload|
|
9
9
|
payload = Resque.decode(Resque.encode(payload))
|
10
|
-
|
10
|
+
Resque::UniqueByArity.unique_log "payload is #{payload.inspect}" if ENV['RESQUE_DEBUG'] == 'true'
|
11
11
|
job = payload["class"]
|
12
12
|
# It seems possible that some jobs may not have an "args" key in the payload.
|
13
13
|
args = payload["args"] || []
|
@@ -45,7 +45,7 @@ module Resque
|
|
45
45
|
define_method(:unique_at_queue_time_redis_key) do |queue, payload|
|
46
46
|
unique_hash, args_for_uniqueness = redis_unique_hash(payload)
|
47
47
|
key = "#{solo_key_namespace(queue)}:#{solo_redis_key_prefix}:#{unique_hash}"
|
48
|
-
|
48
|
+
Resque::UniqueByArity.unique_log "#{ColorizedString['[Queue-Time]'].green} #{self}.unique_at_queue_time_redis_key for #{args_for_uniqueness} is: #{ColorizedString[key].green}" if ENV['RESQUE_DEBUG'] == 'true'
|
49
49
|
key
|
50
50
|
end
|
51
51
|
#
|
@@ -54,7 +54,7 @@ module Resque
|
|
54
54
|
# solo_key_namespace may or may not ignore the queue passed in, depending on config.
|
55
55
|
key_match = "#{solo_key_namespace(self.instance_variable_get(:@queue))}:#{solo_redis_key_prefix}:*"
|
56
56
|
keys = Resque.redis.keys(key_match)
|
57
|
-
|
57
|
+
Resque::UniqueByArity.unique_log "Purging #{keys.length} keys from #{ColorizedString[key_match].red}"
|
58
58
|
Resque.redis.del keys if keys.length > 0
|
59
59
|
end
|
60
60
|
if configuration.unique_in_queue
|
@@ -89,14 +89,14 @@ module Resque
|
|
89
89
|
define_method(:unique_at_runtime_redis_key) do |*args|
|
90
90
|
unique_hash, args_for_uniqueness = redis_unique_hash({"class" => self.to_s, "args" => args})
|
91
91
|
key = "#{runtime_key_namespace}:#{unique_hash}"
|
92
|
-
|
92
|
+
Resque::UniqueByArity.unique_log "#{ColorizedString['[Run-Time]'].yellow} #{self}.unique_at_runtime_redis_key for #{args_for_uniqueness} is: #{ColorizedString[key].yellow}" if ENV['RESQUE_DEBUG'] == 'true'
|
93
93
|
key
|
94
94
|
end
|
95
95
|
# @return [Fixnum] number of keys that were deleted
|
96
96
|
define_method(:purge_unique_at_runtime_redis_keys) do
|
97
97
|
key_match = "#{runtime_key_namespace}:*"
|
98
98
|
keys = Resque.redis.keys(key_match)
|
99
|
-
|
99
|
+
Resque::UniqueByArity.unique_log "Purging #{keys.length} keys from #{ColorizedString[key_match].red}"
|
100
100
|
Resque.redis.del keys if keys.length > 0
|
101
101
|
end
|
102
102
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-unique_by_arity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Boling
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: resque-unique_at_runtime
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- lib/resque/unique_by_arity/configuration.rb
|
115
115
|
- lib/resque/unique_by_arity/cop.rb
|
116
116
|
- lib/resque/unique_by_arity/cop_modulizer.rb
|
117
|
+
- lib/resque/unique_by_arity/validation.rb
|
117
118
|
- lib/resque/unique_by_arity/version.rb
|
118
119
|
- resque-unique_by_arity.gemspec
|
119
120
|
homepage: https://github.com/pboling/resque-unique_by_arity
|