resque-restriction 0.3.0 → 0.4.0
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 +7 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +116 -0
- data/README.markdown +5 -2
- data/Rakefile +3 -17
- data/VERSION +1 -1
- data/lib/resque-restriction/job.rb +2 -2
- data/lib/resque-restriction/restriction_job.rb +28 -8
- data/resque-restriction.gemspec +32 -35
- data/spec/redis-test.conf +1 -1
- data/spec/resque-restriction/job_spec.rb +14 -14
- data/spec/resque-restriction/restriction_job_spec.rb +144 -48
- data/spec/spec_helper.rb +16 -18
- metadata +54 -63
- data/.gitignore +0 -5
- data/.rvmrc.example +0 -2
- data/spec/spec.opts +0 -8
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9262042b42b7838c1b204a900d56f13263afb3d5
|
4
|
+
data.tar.gz: 3fd139447714181f6b99a7f2ad484a5ad70461c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3058d61e4310002f6d2e5f6c5f85c6e7b830507138852e8fdfbc99d5a2f68b8467d63df2ea8a516cec09100e3cc00db1a13ad7e5a1976bec199b1516fc00ddff
|
7
|
+
data.tar.gz: 74d9ddcb8677d8c0ea764d8b9bae61e702aabec26e548e83546725a6cac5f38afdba12dbd3f9b3660e3052dfaca51117827cf88a892ccadf5de0f0f354b3f5ec
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
resque-restriction (0.4.0)
|
5
|
+
activejob
|
6
|
+
jeweler
|
7
|
+
mocha
|
8
|
+
resque
|
9
|
+
rspec
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activejob (4.2.0)
|
15
|
+
activesupport (= 4.2.0)
|
16
|
+
globalid (>= 0.3.0)
|
17
|
+
activesupport (4.2.0)
|
18
|
+
i18n (~> 0.7)
|
19
|
+
json (~> 1.7, >= 1.7.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
22
|
+
tzinfo (~> 1.1)
|
23
|
+
addressable (2.3.6)
|
24
|
+
builder (3.2.2)
|
25
|
+
descendants_tracker (0.0.4)
|
26
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
27
|
+
diff-lcs (1.2.5)
|
28
|
+
faraday (0.9.0)
|
29
|
+
multipart-post (>= 1.2, < 3)
|
30
|
+
git (1.2.9.1)
|
31
|
+
github_api (0.12.4)
|
32
|
+
addressable (~> 2.3)
|
33
|
+
descendants_tracker (~> 0.0.4)
|
34
|
+
faraday (~> 0.8, < 0.10)
|
35
|
+
hashie (>= 3.4)
|
36
|
+
multi_json (>= 1.7.5, < 2.0)
|
37
|
+
nokogiri (~> 1.6.6)
|
38
|
+
oauth2
|
39
|
+
globalid (0.3.3)
|
40
|
+
activesupport (>= 4.1.0)
|
41
|
+
hashie (3.4.2)
|
42
|
+
highline (1.6.21)
|
43
|
+
i18n (0.7.0)
|
44
|
+
jeweler (2.0.1)
|
45
|
+
builder
|
46
|
+
bundler (>= 1.0)
|
47
|
+
git (>= 1.2.5)
|
48
|
+
github_api
|
49
|
+
highline (>= 1.6.15)
|
50
|
+
nokogiri (>= 1.5.10)
|
51
|
+
rake
|
52
|
+
rdoc
|
53
|
+
json (1.8.3)
|
54
|
+
jwt (1.0.0)
|
55
|
+
metaclass (0.0.4)
|
56
|
+
mini_portile (0.6.1)
|
57
|
+
minitest (5.7.0)
|
58
|
+
mocha (1.1.0)
|
59
|
+
metaclass (~> 0.0.1)
|
60
|
+
mono_logger (1.1.0)
|
61
|
+
multi_json (1.11.2)
|
62
|
+
multi_xml (0.5.5)
|
63
|
+
multipart-post (2.0.0)
|
64
|
+
nokogiri (1.6.6.2)
|
65
|
+
mini_portile (~> 0.6.0)
|
66
|
+
oauth2 (1.0.0)
|
67
|
+
faraday (>= 0.8, < 0.10)
|
68
|
+
jwt (~> 1.0)
|
69
|
+
multi_json (~> 1.3)
|
70
|
+
multi_xml (~> 0.5)
|
71
|
+
rack (~> 1.2)
|
72
|
+
rack (1.6.0)
|
73
|
+
rack-protection (1.5.3)
|
74
|
+
rack
|
75
|
+
rake (10.4.2)
|
76
|
+
rdoc (4.1.0)
|
77
|
+
redis (3.2.1)
|
78
|
+
redis-namespace (1.5.1)
|
79
|
+
redis (~> 3.0, >= 3.0.4)
|
80
|
+
resque (1.25.2)
|
81
|
+
mono_logger (~> 1.0)
|
82
|
+
multi_json (~> 1.0)
|
83
|
+
redis-namespace (~> 1.3)
|
84
|
+
sinatra (>= 0.9.2)
|
85
|
+
vegas (~> 0.1.2)
|
86
|
+
rspec (3.1.0)
|
87
|
+
rspec-core (~> 3.1.0)
|
88
|
+
rspec-expectations (~> 3.1.0)
|
89
|
+
rspec-mocks (~> 3.1.0)
|
90
|
+
rspec-core (3.1.7)
|
91
|
+
rspec-support (~> 3.1.0)
|
92
|
+
rspec-expectations (3.1.2)
|
93
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
94
|
+
rspec-support (~> 3.1.0)
|
95
|
+
rspec-mocks (3.1.3)
|
96
|
+
rspec-support (~> 3.1.0)
|
97
|
+
rspec-support (3.1.2)
|
98
|
+
sinatra (1.4.5)
|
99
|
+
rack (~> 1.4)
|
100
|
+
rack-protection (~> 1.4)
|
101
|
+
tilt (~> 1.3, >= 1.3.4)
|
102
|
+
thread_safe (0.3.5)
|
103
|
+
tilt (1.4.1)
|
104
|
+
tzinfo (1.2.2)
|
105
|
+
thread_safe (~> 0.1)
|
106
|
+
vegas (0.1.11)
|
107
|
+
rack (>= 1.0.0)
|
108
|
+
|
109
|
+
PLATFORMS
|
110
|
+
ruby
|
111
|
+
|
112
|
+
DEPENDENCIES
|
113
|
+
resque-restriction!
|
114
|
+
|
115
|
+
BUNDLED WITH
|
116
|
+
1.10.3
|
data/README.markdown
CHANGED
@@ -41,16 +41,17 @@ You can also add customized restriction as you like. For example, we have a job
|
|
41
41
|
|
42
42
|
class GenerateFacebookShares < Resque::Plugins::RestrictionJob
|
43
43
|
restrict :per_day => 40
|
44
|
-
|
44
|
+
|
45
45
|
def self.restriction_identifier(options)
|
46
46
|
[self.to_s, options["user_id"]].join(":")
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
#rest of your class here
|
50
50
|
end
|
51
51
|
|
52
52
|
options["user_id"] returns the user's facebook uid, the key point is that the different restriction_identifiers can restrict different job execution numbers.
|
53
53
|
|
54
|
+
|
54
55
|
Contributing
|
55
56
|
------------
|
56
57
|
|
@@ -70,6 +71,8 @@ Contributors
|
|
70
71
|
------------
|
71
72
|
Matt Conway :: matt@conwaysplace.com :: @mattconway
|
72
73
|
|
74
|
+
Martin Fourcade :: fourcade.m@gmail.com :: @mfourcade
|
75
|
+
|
73
76
|
Copyright
|
74
77
|
---------
|
75
78
|
Copyright (c) 2010 Richard Huang. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,23 +1,9 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require '
|
3
|
-
require 'rake/rdoctask'
|
2
|
+
require 'rspec/core/rake_task'
|
4
3
|
|
5
|
-
|
6
|
-
task :default => :spec
|
7
|
-
|
8
|
-
desc 'Generate documentation for the resque-restriction plugin.'
|
9
|
-
Rake::RDocTask.new(:rdoc) do |rdoc|
|
10
|
-
rdoc.rdoc_dir = 'rdoc'
|
11
|
-
rdoc.title = 'resque_restriction'
|
12
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
13
|
-
rdoc.rdoc_files.include('README*')
|
14
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
16
5
|
|
17
|
-
|
18
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
19
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
20
|
-
end
|
6
|
+
task :default => :spec
|
21
7
|
|
22
8
|
begin
|
23
9
|
require 'jeweler'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -2,7 +2,7 @@ module Resque
|
|
2
2
|
class Job
|
3
3
|
class <<self
|
4
4
|
alias_method :origin_reserve, :reserve
|
5
|
-
|
5
|
+
|
6
6
|
def reserve(queue)
|
7
7
|
if queue =~ /^#{Plugins::Restriction::RESTRICTION_QUEUE_PREFIX}/
|
8
8
|
# If processing the restriction queue, when poping and pushing to end,
|
@@ -14,7 +14,7 @@ module Resque
|
|
14
14
|
# and return
|
15
15
|
payload = Resque.pop(queue)
|
16
16
|
if payload
|
17
|
-
if !
|
17
|
+
if !Object.const_get(payload['class']).repush(*payload['args'])
|
18
18
|
return new(queue, payload)
|
19
19
|
end
|
20
20
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
|
1
3
|
module Resque
|
2
4
|
module Plugins
|
5
|
+
|
3
6
|
module Restriction
|
4
7
|
SECONDS = {
|
5
8
|
:per_minute => 60,
|
@@ -28,7 +31,6 @@ module Resque
|
|
28
31
|
# if we get a 0 result back, the key wasn't set, so we know we are
|
29
32
|
# already tracking the count for that period'
|
30
33
|
period_active = ! Resque.redis.setnx(key, number.to_i - 1)
|
31
|
-
|
32
34
|
# If we are already tracking that period, then decrement by one to
|
33
35
|
# see if we are allowed to run, pushing to restriction queue to run
|
34
36
|
# later if not. Note that the value stored is the number of outstanding
|
@@ -44,6 +46,9 @@ module Resque
|
|
44
46
|
Resque.push restriction_queue_name, :class => to_s, :args => args
|
45
47
|
raise Resque::Job::DontPerform
|
46
48
|
end
|
49
|
+
else
|
50
|
+
# This is the first time we set the key, so we mark it to expire
|
51
|
+
mark_restriction_key_to_expire_for(key, period)
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -73,16 +78,12 @@ module Resque
|
|
73
78
|
self.to_s
|
74
79
|
end
|
75
80
|
|
76
|
-
def restriction_queue_name
|
77
|
-
queue_name = Resque.queue_from_class(self)
|
78
|
-
"#{RESTRICTION_QUEUE_PREFIX}_#{queue_name}"
|
79
|
-
end
|
80
81
|
|
81
82
|
def seconds(period)
|
82
83
|
if SECONDS.keys.include? period
|
83
84
|
SECONDS[period]
|
84
85
|
else
|
85
|
-
period.to_s =~ /^per_(\d+)$/ and $1
|
86
|
+
period.to_s =~ /^per_(\d+)$/ and $1.to_i
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
@@ -106,11 +107,30 @@ module Resque
|
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
110
|
+
def mark_restriction_key_to_expire_for(key, period)
|
111
|
+
Resque.redis.expire(key, seconds(period)) unless period == :concurrent
|
112
|
+
end
|
109
113
|
end
|
110
114
|
|
111
|
-
class RestrictionJob
|
115
|
+
class RestrictionJob < ActiveJob::Base
|
112
116
|
extend Restriction
|
113
|
-
end
|
114
117
|
|
118
|
+
before_perform do |job|
|
119
|
+
self.class.before_perform_restriction(*job.arguments)
|
120
|
+
end
|
121
|
+
|
122
|
+
after_perform do |job|
|
123
|
+
self.class.after_perform_restriction(*job.arguments)
|
124
|
+
end
|
125
|
+
|
126
|
+
rescue_from(StandardError) do |err|
|
127
|
+
self.class.on_failure_restriction(err, *self.arguments)
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.restriction_queue_name
|
131
|
+
queue_name = self.new.queue_name
|
132
|
+
"#{Resque::Plugins::Restriction::RESTRICTION_QUEUE_PREFIX}_#{queue_name}"
|
133
|
+
end
|
134
|
+
end
|
115
135
|
end
|
116
136
|
end
|
data/resque-restriction.gemspec
CHANGED
@@ -1,61 +1,58 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: resque-restriction 0.4.0 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.
|
8
|
+
s.name = "resque-restriction"
|
9
|
+
s.version = "0.4.0"
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
11
13
|
s.authors = ["Richard Huang"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
14
|
+
s.date = "2015-10-19"
|
15
|
+
s.description = "resque-restriction is an extension to resque queue system that restricts the execution number of certain jobs in a period time, the exceeded jobs will be executed at the next period."
|
16
|
+
s.email = "flyerhzm@gmail.com"
|
15
17
|
s.extra_rdoc_files = [
|
16
18
|
"LICENSE",
|
17
|
-
|
19
|
+
"README.markdown"
|
18
20
|
]
|
19
21
|
s.files = [
|
20
|
-
".
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
"spec/resque-restriction/restriction_job_spec.rb",
|
35
|
-
"spec/spec.opts",
|
36
|
-
"spec/spec_helper.rb"
|
37
|
-
]
|
38
|
-
s.homepage = %q{http://github.com/flyerhzm/resque-restriction}
|
39
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
40
|
-
s.require_paths = ["lib"]
|
41
|
-
s.rubygems_version = %q{1.3.7}
|
42
|
-
s.summary = %q{resque-restriction is an extension to resque queue system that restricts the execution number of certain jobs in a period time.}
|
43
|
-
s.test_files = [
|
22
|
+
"CHANGELOG.md",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE",
|
26
|
+
"README.markdown",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"init.rb",
|
30
|
+
"lib/resque-restriction.rb",
|
31
|
+
"lib/resque-restriction/job.rb",
|
32
|
+
"lib/resque-restriction/restriction_job.rb",
|
33
|
+
"rails/init.rb",
|
34
|
+
"resque-restriction.gemspec",
|
35
|
+
"spec/redis-test.conf",
|
44
36
|
"spec/resque-restriction/job_spec.rb",
|
45
|
-
|
46
|
-
|
37
|
+
"spec/resque-restriction/restriction_job_spec.rb",
|
38
|
+
"spec/spec_helper.rb"
|
47
39
|
]
|
40
|
+
s.homepage = "http://github.com/flyerhzm/resque-restriction"
|
41
|
+
s.rubygems_version = "2.4.8"
|
42
|
+
s.summary = "resque-restriction is an extension to resque queue system that restricts the execution number of certain jobs in a period time."
|
48
43
|
|
49
44
|
if s.respond_to? :specification_version then
|
50
|
-
|
51
|
-
s.specification_version = 3
|
45
|
+
s.specification_version = 4
|
52
46
|
|
53
47
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_runtime_dependency(%q<resque-restriction>, [">= 0"])
|
54
49
|
s.add_runtime_dependency(%q<resque>, [">= 1.7.0"])
|
55
50
|
else
|
51
|
+
s.add_dependency(%q<resque-restriction>, [">= 0"])
|
56
52
|
s.add_dependency(%q<resque>, [">= 1.7.0"])
|
57
53
|
end
|
58
54
|
else
|
55
|
+
s.add_dependency(%q<resque-restriction>, [">= 0"])
|
59
56
|
s.add_dependency(%q<resque>, [">= 1.7.0"])
|
60
57
|
end
|
61
58
|
end
|
data/spec/redis-test.conf
CHANGED
@@ -112,7 +112,7 @@ databases 16
|
|
112
112
|
# Glue small output buffers together in order to send small replies in a
|
113
113
|
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
114
114
|
# in terms of number of queries per second. Use 'yes' if unsure.
|
115
|
-
glueoutputbuf yes
|
115
|
+
# glueoutputbuf yes
|
116
116
|
|
117
117
|
# Use object sharing. Can save a lot of memory if you have many common
|
118
118
|
# string in your dataset, but performs lookups against the shared objects
|
@@ -1,37 +1,37 @@
|
|
1
|
-
require File.
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
2
|
|
3
|
-
describe Resque::Job do
|
4
|
-
before(:
|
3
|
+
RSpec.describe Resque::Job do
|
4
|
+
before(:example) do
|
5
5
|
Resque.redis.flushall
|
6
6
|
end
|
7
7
|
|
8
8
|
it "should repush restriction queue when reserve" do
|
9
9
|
Resque.push('restriction_normal', :class => 'OneHourRestrictionJob', :args => ['any args'])
|
10
|
-
Resque::Job.reserve('restriction_normal').
|
11
|
-
Resque::Job.reserve('restriction_normal').
|
12
|
-
Resque::Job.reserve('normal').
|
10
|
+
expect(Resque::Job.reserve('restriction_normal')).to eq Resque::Job.new('restriction_normal', {'class' => 'OneHourRestrictionJob', 'args' => ['any args']})
|
11
|
+
expect(Resque::Job.reserve('restriction_normal')).to be_nil
|
12
|
+
expect(Resque::Job.reserve('normal')).to be_nil
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should push back to restriction queue when still restricted" do
|
16
16
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), -1)
|
17
17
|
Resque.push('restriction_normal', :class => 'OneHourRestrictionJob', :args => ['any args'])
|
18
|
-
Resque::Job.reserve('restriction_normal').
|
19
|
-
Resque.pop('restriction_normal').
|
20
|
-
Resque::Job.reserve('normal').
|
18
|
+
expect(Resque::Job.reserve('restriction_normal')).to be_nil
|
19
|
+
expect(Resque.pop('restriction_normal')).to eq({'class' => 'OneHourRestrictionJob', 'args' => ['any args']})
|
20
|
+
expect(Resque::Job.reserve('normal')).to be_nil
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should not repush when reserve normal queue" do
|
24
24
|
Resque.push('normal', :class => 'OneHourRestrictionJob', :args => ['any args'])
|
25
|
-
Resque::Job.reserve('normal').
|
26
|
-
Resque::Job.reserve('normal').
|
27
|
-
Resque::Job.reserve('restriction_normal').
|
25
|
+
expect(Resque::Job.reserve('normal')).to eq Resque::Job.new('normal', {'class' => 'OneHourRestrictionJob', 'args' => ['any args']})
|
26
|
+
expect(Resque::Job.reserve('normal')).to be_nil
|
27
|
+
expect(Resque::Job.reserve('restriction_normal')).to be_nil
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should only push back queue_length times to restriction queue" do
|
31
31
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), -1)
|
32
32
|
3.times { Resque.push('restriction_normal', :class => 'OneHourRestrictionJob', :args => ['any args']) }
|
33
|
-
Resque.size('restriction_normal').
|
34
|
-
OneHourRestrictionJob.
|
33
|
+
expect(Resque.size('restriction_normal')).to eq 3
|
34
|
+
expect(OneHourRestrictionJob).to receive(:repush).exactly(3).times.and_return(true)
|
35
35
|
Resque::Job.reserve('restriction_normal')
|
36
36
|
end
|
37
37
|
|
@@ -1,124 +1,220 @@
|
|
1
|
-
require File.
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
2
|
|
3
|
-
describe Resque::Plugins::RestrictionJob do
|
4
|
-
|
3
|
+
RSpec.describe Resque::Plugins::RestrictionJob do
|
4
|
+
skip "should follow the convention" do
|
5
5
|
Resque::Plugin.lint(Resque::Plugins::RestrictionJob)
|
6
6
|
end
|
7
7
|
|
8
8
|
context "redis_key" do
|
9
9
|
it "should get redis_key with different period" do
|
10
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_minute).
|
11
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_hour).
|
12
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_day).
|
13
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_month).
|
14
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_year).
|
10
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_minute)).to eq "Resque::Plugins::RestrictionJob:#{Time.now.to_i / 60}"
|
11
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_hour)).to eq "Resque::Plugins::RestrictionJob:#{Time.now.to_i / (60*60)}"
|
12
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_day)).to eq "Resque::Plugins::RestrictionJob:#{Time.now.to_i / (24*60*60)}"
|
13
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_month)).to eq "Resque::Plugins::RestrictionJob:#{Date.today.strftime("%Y-%m")}"
|
14
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_year)).to eq "Resque::Plugins::RestrictionJob:#{Date.today.year}"
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should accept customization" do
|
18
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_1800).
|
19
|
-
Resque::Plugins::RestrictionJob.redis_key(:per_7200).
|
18
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_1800)).to eq "Resque::Plugins::RestrictionJob:#{Time.now.to_i / 1800}"
|
19
|
+
expect(Resque::Plugins::RestrictionJob.redis_key(:per_7200)).to eq "Resque::Plugins::RestrictionJob:#{Time.now.to_i / 7200}"
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
context "settings" do
|
24
24
|
it "get correct number to restriction jobs" do
|
25
|
-
OneDayRestrictionJob.settings.
|
26
|
-
OneHourRestrictionJob.settings.
|
27
|
-
MultipleRestrictionJob.settings.
|
28
|
-
MultiCallRestrictionJob.settings.
|
25
|
+
expect(OneDayRestrictionJob.settings).to eq({:per_day => 100})
|
26
|
+
expect(OneHourRestrictionJob.settings).to eq({:per_hour => 10})
|
27
|
+
expect(MultipleRestrictionJob.settings).to eq({:per_hour => 10, :per_300 => 2})
|
28
|
+
expect(MultiCallRestrictionJob.settings).to eq({:per_hour => 10, :per_300 => 2})
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
|
+
context 'restriction_queue_name' do
|
33
|
+
class MyJob < Resque::Plugins::RestrictionJob
|
34
|
+
queue_as 'awesome_queue_name'
|
35
|
+
|
36
|
+
def perform(args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'concats restriction queue prefix with queue name' do
|
41
|
+
expect(MyJob.restriction_queue_name).to eq("#{Resque::Plugins::Restriction::RESTRICTION_QUEUE_PREFIX}_awesome_queue_name")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
32
45
|
context "resque" do
|
33
46
|
include PerformJob
|
34
47
|
|
35
|
-
before(:
|
48
|
+
before(:example) do
|
36
49
|
Resque.redis.flushall
|
37
50
|
end
|
38
|
-
|
51
|
+
|
39
52
|
it "should set execution number and decrement it when one job first executed" do
|
40
53
|
result = perform_job(OneHourRestrictionJob, "any args")
|
41
|
-
|
42
|
-
Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour)).should == "9"
|
54
|
+
expect(Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour))).to eq "9"
|
43
55
|
end
|
44
56
|
|
45
57
|
it "should use restriction_identifier to set exclusive execution counts" do
|
46
58
|
result = perform_job(IdentifiedRestrictionJob, 1)
|
47
|
-
result.should be_true
|
48
59
|
result = perform_job(IdentifiedRestrictionJob, 1)
|
49
|
-
result.should be_true
|
50
60
|
result = perform_job(IdentifiedRestrictionJob, 2)
|
51
|
-
|
52
|
-
Resque.redis.get(IdentifiedRestrictionJob.redis_key(:per_hour, 1)).
|
53
|
-
Resque.redis.get(IdentifiedRestrictionJob.redis_key(:per_hour, 2)).
|
61
|
+
|
62
|
+
expect(Resque.redis.get(IdentifiedRestrictionJob.redis_key(:per_hour, 1))).to eq "8"
|
63
|
+
expect(Resque.redis.get(IdentifiedRestrictionJob.redis_key(:per_hour, 2))).to eq "9"
|
54
64
|
end
|
55
65
|
|
56
66
|
it "should decrement execution number when one job executed" do
|
57
67
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), 6)
|
58
68
|
result = perform_job(OneHourRestrictionJob, "any args")
|
59
|
-
|
60
|
-
Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour)).
|
69
|
+
|
70
|
+
expect(Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour))).to eq "5"
|
61
71
|
end
|
62
72
|
|
63
73
|
it "should increment execution number when concurrent job completes" do
|
64
74
|
t = Thread.new do
|
65
|
-
|
66
|
-
result.should be_true
|
75
|
+
perform_job(ConcurrentRestrictionJob, "any args")
|
67
76
|
end
|
68
77
|
sleep 0.1
|
69
|
-
Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent)).
|
78
|
+
expect(Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent))).to eq "0"
|
70
79
|
t.join
|
71
|
-
Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent)).
|
80
|
+
expect(Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent))).to eq "1"
|
72
81
|
end
|
73
82
|
|
74
83
|
it "should increment execution number when concurrent job fails" do
|
75
|
-
ConcurrentRestrictionJob.
|
84
|
+
expect_any_instance_of(ConcurrentRestrictionJob).to receive(:perform).and_raise("bad")
|
76
85
|
perform_job(ConcurrentRestrictionJob, "any args") rescue nil
|
77
|
-
Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent)).
|
86
|
+
expect(Resque.redis.get(ConcurrentRestrictionJob.redis_key(:concurrent))).to eq "1"
|
78
87
|
end
|
79
88
|
|
80
89
|
it "should put the job into restriction queue when execution count < 0" do
|
81
90
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), 0)
|
82
91
|
result = perform_job(OneHourRestrictionJob, "any args")
|
83
|
-
result.
|
84
|
-
Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour)).
|
85
|
-
Resque.redis.lrange("queue:restriction_normal", 0, -1).
|
92
|
+
# expect(result).to_not be(true)
|
93
|
+
expect(Resque.redis.get(OneHourRestrictionJob.redis_key(:per_hour))).to eq "0"
|
94
|
+
expect(Resque.redis.lrange("queue:restriction_normal", 0, -1)).to eq [Resque.encode(:class => "OneHourRestrictionJob", :args => ["any args"])]
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "expiration of period keys" do
|
98
|
+
class MyJob < Resque::Plugins::RestrictionJob
|
99
|
+
def perform(args)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
shared_examples_for "expiration" do
|
104
|
+
before(:example) do
|
105
|
+
MyJob.restrict period => 10
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when the key is not set" do
|
109
|
+
it "should mark period keys to expire" do
|
110
|
+
perform_job(MyJob, "any args")
|
111
|
+
expect(Resque.redis.ttl(MyJob.redis_key(period))).to eq MyJob.seconds(period)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when the key is set" do
|
116
|
+
before(:example) do
|
117
|
+
Resque.redis.set(MyJob.redis_key(period), 5)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should not mark period keys to expire" do
|
121
|
+
perform_job(MyJob, "any args")
|
122
|
+
expect(Resque.redis.ttl(MyJob.redis_key(period))).to eq -1
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "per minute" do
|
128
|
+
def period
|
129
|
+
:per_minute
|
130
|
+
end
|
131
|
+
|
132
|
+
it_should_behave_like "expiration"
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "per hour" do
|
136
|
+
def period
|
137
|
+
:per_hour
|
138
|
+
end
|
139
|
+
|
140
|
+
it_should_behave_like "expiration"
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "per day" do
|
144
|
+
def period
|
145
|
+
:per_day
|
146
|
+
end
|
147
|
+
|
148
|
+
it_should_behave_like "expiration"
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "per week" do
|
152
|
+
def period
|
153
|
+
:per_week
|
154
|
+
end
|
155
|
+
|
156
|
+
it_should_behave_like "expiration"
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "per month" do
|
160
|
+
def period
|
161
|
+
:per_month
|
162
|
+
end
|
163
|
+
|
164
|
+
it_should_behave_like "expiration"
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "per year" do
|
168
|
+
def period
|
169
|
+
:per_year
|
170
|
+
end
|
171
|
+
|
172
|
+
it_should_behave_like "expiration"
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "per custom period" do
|
176
|
+
def period
|
177
|
+
:per_359
|
178
|
+
end
|
179
|
+
|
180
|
+
it_should_behave_like "expiration"
|
181
|
+
end
|
86
182
|
end
|
87
183
|
|
88
184
|
context "multiple restrict" do
|
89
185
|
it "should restrict per_minute" do
|
90
186
|
result = perform_job(MultipleRestrictionJob, "any args")
|
91
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour)).
|
92
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300)).
|
187
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour))).to eq "9"
|
188
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300))).to eq "1"
|
93
189
|
result = perform_job(MultipleRestrictionJob, "any args")
|
94
190
|
result = perform_job(MultipleRestrictionJob, "any args")
|
95
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour)).
|
96
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300)).
|
191
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour))).to eq "8"
|
192
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300))).to eq "0"
|
97
193
|
end
|
98
194
|
|
99
195
|
it "should restrict per_hour" do
|
100
196
|
Resque.redis.set(MultipleRestrictionJob.redis_key(:per_hour), 1)
|
101
197
|
Resque.redis.set(MultipleRestrictionJob.redis_key(:per_300), 2)
|
102
198
|
result = perform_job(MultipleRestrictionJob, "any args")
|
103
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour)).
|
104
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300)).
|
199
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour))).to eq "0"
|
200
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300))).to eq "1"
|
105
201
|
result = perform_job(MultipleRestrictionJob, "any args")
|
106
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour)).
|
107
|
-
Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300)).
|
202
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_hour))).to eq "0"
|
203
|
+
expect(Resque.redis.get(MultipleRestrictionJob.redis_key(:per_300))).to eq "1"
|
108
204
|
end
|
109
205
|
end
|
110
206
|
|
111
207
|
context "repush" do
|
112
208
|
it "should push restricted jobs onto restriction queue" do
|
113
209
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), -1)
|
114
|
-
Resque.
|
115
|
-
OneHourRestrictionJob.repush('any args').
|
210
|
+
expect(Resque).to receive(:push).once.with('restriction_normal', :class => 'OneHourRestrictionJob', :args => ['any args'])
|
211
|
+
expect(OneHourRestrictionJob.repush('any args')).to be(true)
|
116
212
|
end
|
117
213
|
|
118
214
|
it "should not push unrestricted jobs onto restriction queue" do
|
119
215
|
Resque.redis.set(OneHourRestrictionJob.redis_key(:per_hour), 1)
|
120
|
-
Resque.
|
121
|
-
OneHourRestrictionJob.repush('any args').
|
216
|
+
expect(Resque).not_to receive(:push)
|
217
|
+
expect(OneHourRestrictionJob.repush('any args')).to be(false)
|
122
218
|
end
|
123
219
|
|
124
220
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'spec/autorun'
|
3
2
|
require 'mocha'
|
4
3
|
|
5
4
|
dir = File.dirname(__FILE__)
|
@@ -38,53 +37,52 @@ puts "Starting redis for testing at localhost:9736..."
|
|
38
37
|
`redis-server #{dir}/redis-test.conf`
|
39
38
|
Resque.redis = 'localhost:9736'
|
40
39
|
|
41
|
-
|
40
|
+
#
|
42
41
|
# Helper to perform job classes
|
43
42
|
#
|
44
43
|
module PerformJob
|
45
44
|
def perform_job(klass, *args)
|
46
|
-
|
47
|
-
resque_job.perform
|
45
|
+
klass.perform_now(*args)
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
49
|
class OneDayRestrictionJob < Resque::Plugins::RestrictionJob
|
52
50
|
restrict :per_day => 100
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
def
|
52
|
+
queue_as 'normal'
|
53
|
+
|
54
|
+
def perform(args)
|
57
55
|
end
|
58
56
|
end
|
59
57
|
|
60
58
|
class OneHourRestrictionJob < Resque::Plugins::RestrictionJob
|
61
59
|
restrict :per_hour => 10
|
62
60
|
|
63
|
-
|
61
|
+
queue_as 'normal'
|
64
62
|
|
65
|
-
def
|
63
|
+
def perform(args)
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
69
67
|
class IdentifiedRestrictionJob < Resque::Plugins::RestrictionJob
|
70
68
|
restrict :per_hour => 10
|
71
69
|
|
72
|
-
|
70
|
+
queue_as 'normal'
|
73
71
|
|
74
72
|
def self.restriction_identifier(*args)
|
75
73
|
[self.to_s, args.first].join(":")
|
76
74
|
end
|
77
75
|
|
78
|
-
def
|
76
|
+
def perform(args)
|
79
77
|
end
|
80
78
|
end
|
81
79
|
|
82
80
|
class ConcurrentRestrictionJob < Resque::Plugins::RestrictionJob
|
83
81
|
restrict :concurrent => 1
|
84
82
|
|
85
|
-
|
83
|
+
queue_as 'normal'
|
86
84
|
|
87
|
-
def
|
85
|
+
def perform(args)
|
88
86
|
sleep 0.2
|
89
87
|
end
|
90
88
|
end
|
@@ -92,9 +90,9 @@ end
|
|
92
90
|
class MultipleRestrictionJob < Resque::Plugins::RestrictionJob
|
93
91
|
restrict :per_hour => 10, :per_300 => 2
|
94
92
|
|
95
|
-
|
93
|
+
queue_as 'normal'
|
96
94
|
|
97
|
-
def
|
95
|
+
def perform(args)
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
@@ -102,8 +100,8 @@ class MultiCallRestrictionJob < Resque::Plugins::RestrictionJob
|
|
102
100
|
restrict :per_hour => 10
|
103
101
|
restrict :per_300 => 2
|
104
102
|
|
105
|
-
|
103
|
+
queue_as 'normal'
|
106
104
|
|
107
|
-
def
|
105
|
+
def perform(args)
|
108
106
|
end
|
109
|
-
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,51 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-restriction
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease: false
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 0
|
10
|
-
version: 0.3.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Richard Huang
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
date: 2015-10-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: resque-restriction
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: resque
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
27
31
|
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 11
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 7
|
33
|
-
- 0
|
32
|
+
- !ruby/object:Gem::Version
|
34
33
|
version: 1.7.0
|
35
34
|
type: :runtime
|
36
|
-
|
37
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.7.0
|
41
|
+
description: resque-restriction is an extension to resque queue system that restricts
|
42
|
+
the execution number of certain jobs in a period time, the exceeded jobs will be
|
43
|
+
executed at the next period.
|
38
44
|
email: flyerhzm@gmail.com
|
39
45
|
executables: []
|
40
|
-
|
41
46
|
extensions: []
|
42
|
-
|
43
|
-
extra_rdoc_files:
|
47
|
+
extra_rdoc_files:
|
44
48
|
- LICENSE
|
45
49
|
- README.markdown
|
46
|
-
files:
|
47
|
-
- .
|
48
|
-
-
|
50
|
+
files:
|
51
|
+
- CHANGELOG.md
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
49
54
|
- LICENSE
|
50
55
|
- README.markdown
|
51
56
|
- Rakefile
|
@@ -59,43 +64,29 @@ files:
|
|
59
64
|
- spec/redis-test.conf
|
60
65
|
- spec/resque-restriction/job_spec.rb
|
61
66
|
- spec/resque-restriction/restriction_job_spec.rb
|
62
|
-
- spec/spec.opts
|
63
67
|
- spec/spec_helper.rb
|
64
|
-
has_rdoc: true
|
65
68
|
homepage: http://github.com/flyerhzm/resque-restriction
|
66
69
|
licenses: []
|
67
|
-
|
70
|
+
metadata: {}
|
68
71
|
post_install_message:
|
69
|
-
rdoc_options:
|
70
|
-
|
71
|
-
require_paths:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
72
74
|
- lib
|
73
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
-
|
75
|
-
requirements:
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
76
77
|
- - ">="
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
version: "0"
|
82
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
|
-
requirements:
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
85
82
|
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
88
|
-
segments:
|
89
|
-
- 0
|
90
|
-
version: "0"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
91
85
|
requirements: []
|
92
|
-
|
93
86
|
rubyforge_project:
|
94
|
-
rubygems_version:
|
87
|
+
rubygems_version: 2.4.8
|
95
88
|
signing_key:
|
96
|
-
specification_version:
|
97
|
-
summary: resque-restriction is an extension to resque queue system that restricts
|
98
|
-
|
99
|
-
|
100
|
-
- spec/resque-restriction/restriction_job_spec.rb
|
101
|
-
- spec/spec_helper.rb
|
89
|
+
specification_version: 4
|
90
|
+
summary: resque-restriction is an extension to resque queue system that restricts
|
91
|
+
the execution number of certain jobs in a period time.
|
92
|
+
test_files: []
|
data/.rvmrc.example
DELETED