resque-restriction 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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