resque-rate_limited 1.2.0 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codelimate.yml +17 -0
- data/.rspec +1 -1
- data/.rubocop.yml +20 -12
- data/.travis.yml +15 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +19 -2
- data/README.md +54 -45
- data/Rakefile +10 -0
- data/lib/resque-rate_limited/version.rb +1 -1
- data/resque-rate_limited.gemspec +19 -31
- data/script/console +2 -0
- metadata +16 -175
- data/circle.yml +0 -10
- data/spec/apis/angellist_queue_spec.rb +0 -51
- data/spec/apis/evernote_queue_spec.rb +0 -77
- data/spec/apis/twitter_queue_spec.rb +0 -52
- data/spec/rate_limited_spec.rb +0 -243
- data/spec/rate_limited_un_pause_spec.rb +0 -49
- data/spec/spec_helper.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a577c3a5760f78c7d2bcc9a09f88f760a912659
|
4
|
+
data.tar.gz: 9daa34e0d508084219855c54a265c732a4432be6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83ac5456c7bc19657ef0dd753f3cc9ef2cc5bd0b1f74bb0db0aae7a560c0e1f3440757006f69fc348fe635b33a73e932cd2684c6faa447be9316c0d14778df8b
|
7
|
+
data.tar.gz: 798a48a1325d621a5a86bde14921f7b212da93d0a54122c9d5e06d4c54fe642159b19cf3939fa46a620035b0f887a5221a7bb3ffc6b6bb6b400fc3a32a1cafa8
|
data/.codelimate.yml
ADDED
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
--color
|
2
|
-
--
|
2
|
+
--require spec_helper
|
data/.rubocop.yml
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
---
|
2
2
|
AllCops:
|
3
|
+
TargetRubyVersion: 2.0
|
4
|
+
DisplayCopNames: true
|
3
5
|
Exclude:
|
4
6
|
- 'tmp/**/*'
|
5
7
|
- 'coverage/**/*'
|
6
|
-
- 'spec/dummy/**/*'
|
7
8
|
|
8
9
|
#-------------------------------------------------------------------------------
|
9
10
|
# Project standards
|
@@ -25,11 +26,6 @@ FileName:
|
|
25
26
|
Description: 'Use snake_case for source file names.'
|
26
27
|
Enabled: true
|
27
28
|
|
28
|
-
Style/SymbolArray:
|
29
|
-
Description: 'Use %i or %I for arrays of symbols.'
|
30
|
-
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-i'
|
31
|
-
Enabled: false # Only available in Ruby 2.0+
|
32
|
-
|
33
29
|
Style/ExtraSpacing:
|
34
30
|
Description: 'Do not use unnecessary spacing.'
|
35
31
|
Enabled: true
|
@@ -38,9 +34,21 @@ Lint/LiteralInInterpolation:
|
|
38
34
|
Description: 'Avoid interpolating literals in strings'
|
39
35
|
AutoCorrect: true
|
40
36
|
|
41
|
-
|
42
|
-
#
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
Style/PercentLiteralDelimiters:
|
38
|
+
# Hound and CodeClimate are currently using an old version of Rubocop with
|
39
|
+
# different defaults, so we set them explicitly here.
|
40
|
+
PreferredDelimiters:
|
41
|
+
default: ()
|
42
|
+
'%i': '[]'
|
43
|
+
'%I': '[]'
|
44
|
+
'%r': '{}'
|
45
|
+
'%w': '[]'
|
46
|
+
'%W': '[]'
|
47
|
+
|
48
|
+
Metrics/LineLength:
|
49
|
+
Max: 120
|
50
|
+
|
51
|
+
Metrics/BlockLength:
|
52
|
+
Exclude:
|
53
|
+
- 'spec/**/*_spec.rb'
|
54
|
+
- '*.gemspec'
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## [1.2.1](https://github.com/Xenapto/resque-rate_limited/tree/1.2.1) (2017-04-26)
|
4
|
+
[Full Changelog](https://github.com/Xenapto/resque-rate_limited/compare/v1.2.0...1.2.1)
|
5
|
+
|
6
|
+
**Merged pull requests:**
|
7
|
+
|
8
|
+
- Prepare for more recent rubies [\#1](https://github.com/Xenapto/resque-rate_limited/pull/1) ([dominicsayers](https://github.com/dominicsayers))
|
9
|
+
|
10
|
+
## [v1.2.0](https://github.com/Xenapto/resque-rate_limited/tree/v1.2.0) (2016-10-07)
|
11
|
+
[Full Changelog](https://github.com/Xenapto/resque-rate_limited/compare/v1.1.0...v1.2.0)
|
12
|
+
|
13
|
+
## [v1.1.0](https://github.com/Xenapto/resque-rate_limited/tree/v1.1.0) (2016-10-03)
|
14
|
+
|
15
|
+
|
16
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Gemfile
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in resque_rate_limited.gemspec
|
4
2
|
gemspec
|
3
|
+
ruby RUBY_VERSION
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'bundler'
|
7
|
+
gem 'gem-release'
|
8
|
+
gem 'github_changelog_generator'
|
9
|
+
gem 'guard'
|
10
|
+
gem 'guard-rspec'
|
11
|
+
gem 'guard-rubocop'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :test do
|
15
|
+
gem 'codeclimate-test-reporter'
|
16
|
+
gem 'coveralls'
|
17
|
+
gem 'fuubar'
|
18
|
+
gem 'rspec'
|
19
|
+
gem 'rspec_junit_formatter'
|
20
|
+
gem 'simplecov'
|
21
|
+
end
|
data/README.md
CHANGED
@@ -1,16 +1,23 @@
|
|
1
|
-
|
1
|
+
## Resque rate-limited
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem version](https://badge.fury.io/rb/resque-rate_limited.svg)](https://rubygems.org/gems/resque-rate_limited)
|
4
|
+
[![Gem downloads](https://img.shields.io/gem/dt/resque-rate_limited.svg)](https://rubygems.org/gems/resque-rate_limited)
|
5
|
+
[![Build Status](https://travis-ci.org/Xenapto/resque-rate_limited.svg?branch=master)](https://travis-ci.org/Xenapto/resque-rate_limited)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/Xenapto/resque-rate_limited/badges/gpa.svg)](https://codeclimate.com/github/Xenapto/resque-rate_limited)
|
7
|
+
[![Test Coverage](https://codeclimate.com/github/Xenapto/resque-rate_limited/badges/coverage.svg)](https://codeclimate.com/github/Xenapto/resque-rate_limited/coverage)
|
8
|
+
[![Dependency Status](https://gemnasium.com/badges/github.com/Xenapto/resque-rate_limited.svg)](https://gemnasium.com/github.com/Xenapto/resque-rate_limited)
|
9
|
+
[![Security](https://hakiri.io/github/Xenapto/resque-rate_limited/master.svg)](https://hakiri.io/github/Xenapto/resque-rate_limited/master)
|
4
10
|
|
5
|
-
|
11
|
+
A Resque plugin which makes handling jobs that use rate-limited APIs easier
|
6
12
|
|
7
|
-
|
13
|
+
If you have a series of jobs in a queue, this gem will pause the queue when one of the jobs hits a rate limit, and re-start the queue when the rate limit has expired.
|
8
14
|
|
9
|
-
|
15
|
+
There are two ways to use the gem:
|
10
16
|
|
11
|
-
If you are using
|
17
|
+
1. If the API you are using has a dedicated queue included in the gem (currently Twitter, Angellist and Evernote) then you just need to make some very minor changes to how you queue jobs, and the gem will do the rest.
|
18
|
+
1. If you are using another API, then you need to write a little code that catches the rate limit signal.
|
12
19
|
|
13
|
-
|
20
|
+
### Installation
|
14
21
|
|
15
22
|
Add this line to your application's Gemfile:
|
16
23
|
|
@@ -26,15 +33,15 @@ Or install it yourself as:
|
|
26
33
|
|
27
34
|
$ gem install resque-rate_limited
|
28
35
|
|
29
|
-
|
36
|
+
### Usage
|
30
37
|
|
31
|
-
### Configuration
|
32
38
|
#### Redis
|
33
39
|
The gem uses [redis-mutex](https://github.com/kenn/redis-mutex ) which requires you to register the Redis server: (e.g. in `config/initializers/redis_mutex.rb` for Rails)
|
34
40
|
|
35
41
|
```ruby
|
36
42
|
RedisClassy.redis = Redis.new
|
37
43
|
```
|
44
|
+
|
38
45
|
Note that Redis Mutex uses the `redis-classy` gem internally.
|
39
46
|
|
40
47
|
#### Un Pause
|
@@ -51,28 +58,33 @@ Resque::Plugins::RateLimited::UnPause.queue = :my_queue
|
|
51
58
|
Please see the section below on how to unpause on heroku as an alternative. If you don't install `resque-scheduler` AND configure the queue, then the gem will not schedule unpause jobs this way.
|
52
59
|
|
53
60
|
#### Workers
|
54
|
-
Queues are paused by renaming them, so a resque queue called
|
61
|
+
Queues are paused by renaming them, so a resque queue called `twitter_api` will be renamed `twitter_api_paused` when it hits a rate limit. Of course this will only work if your resque workers are not also taking jobs from the `twitter_api_paused` queue. So your worker commands need to look like:
|
55
62
|
|
56
63
|
Either
|
64
|
+
|
57
65
|
```ruby
|
58
66
|
bin/resque work --queues=high,low,twitter_api
|
59
67
|
```
|
60
68
|
or
|
69
|
+
|
61
70
|
```ruby
|
62
71
|
env QUEUES=high,low,twitter_api bundle exec rake jobs:work
|
63
72
|
```
|
64
73
|
|
65
74
|
NOT
|
75
|
+
|
66
76
|
```ruby
|
67
77
|
bin/resque work --queues=*
|
68
78
|
```
|
69
|
-
|
79
|
+
|
80
|
+
and NOT
|
81
|
+
|
70
82
|
```ruby
|
71
83
|
env QUEUES=* bundle exec rake jobs:work
|
72
84
|
```
|
73
85
|
|
74
86
|
#### Unpausing on heroku
|
75
|
-
The built in schedler on heroku doesn't support dynamic scheduling from an API, so unless you want to provision an extra worker to run resque-scheduler - the best option is just to unpause all your queues on a regular basis. If they aren't paused this is a harmless no-op. If not enough time has elapsed the jobs will just hit the rate_limit and get paused again. We've found that a hourly
|
87
|
+
The built in schedler on heroku doesn't support dynamic scheduling from an API, so unless you want to provision an extra worker to run resque-scheduler - the best option is just to unpause all your queues on a regular basis. If they aren't paused this is a harmless no-op. If not enough time has elapsed the jobs will just hit the rate_limit and get paused again. We've found that a hourly `rake unpause` job seems to work well. The rake task would need to call:
|
76
88
|
|
77
89
|
```ruby
|
78
90
|
Resque::Plugins::RateLimited.TwitterQueue.un_pause
|
@@ -80,12 +92,12 @@ Resque::Plugins::RateLimited.AngellistQueue.un_pause
|
|
80
92
|
MyQueue.un_pause
|
81
93
|
MyJob.un_pause
|
82
94
|
```
|
83
|
-
|
84
|
-
If you're using the [twitter gem](https://github.com/sferik/twitter), this is really simple. Instead of queuing using Resque.enqueue
|
95
|
+
#### A pausable job using one of the build-in queues (Twitter, Angellist, Evernote)
|
96
|
+
If you're using the [twitter gem](https://github.com/sferik/twitter), this is really simple. Instead of queuing using `Resque.enqueue`, you just use `Resque::Plugins::RateLimited:TwitterQueue.enqueue`.
|
85
97
|
|
86
|
-
Make sure your code in perform doesn't catch the
|
98
|
+
Make sure your code in perform doesn't catch the rate limit exception.
|
87
99
|
|
88
|
-
The TwitterQueue will catch the exception and pause the queue (as well as re-scheduling the jobs and scheduling an un pause (if you are using resque-scheduler)). Any jobs you add while the queue is paused will be added to the paused queue
|
100
|
+
The TwitterQueue will catch the exception and pause the queue (as well as re-scheduling the jobs and scheduling an un pause (if you are using `resque-scheduler`)). Any jobs you add while the queue is paused will be added to the paused queue
|
89
101
|
|
90
102
|
```ruby
|
91
103
|
class TwitterJob
|
@@ -101,8 +113,8 @@ class TwitterJob
|
|
101
113
|
end
|
102
114
|
```
|
103
115
|
|
104
|
-
|
105
|
-
If you only have one class of job you want to queue using the
|
116
|
+
#### A single class of pausable job using a new API
|
117
|
+
If you only have one class of job you want to queue using the API, then you can use the `PauseQueue` module directly
|
106
118
|
|
107
119
|
```ruby
|
108
120
|
class MyApiJob
|
@@ -121,10 +133,10 @@ class MyApiJob
|
|
121
133
|
rate_limited_enqueue(self, *params)
|
122
134
|
end
|
123
135
|
end
|
124
|
-
|
136
|
+
```
|
125
137
|
|
126
|
-
|
127
|
-
If you have more than one class of job you want to queue to the
|
138
|
+
#### Multiple classes of pausable job using a new API
|
139
|
+
If you have more than one class of job you want to queue to the API, then you need to add another Queue class. This isn't hard
|
128
140
|
|
129
141
|
```ruby
|
130
142
|
class MyApiQueue < Resque::Plugins::RateLimited::BaseApiQueue
|
@@ -138,32 +150,37 @@ class MyApiQueue < Resque::Plugins::RateLimited::BaseApiQueue
|
|
138
150
|
rate_limited_requeue(self, klass, *params)
|
139
151
|
end
|
140
152
|
end
|
141
|
-
|
153
|
+
```
|
154
|
+
|
142
155
|
If you do this - please contribute - and I'll add to the gem.
|
143
156
|
|
144
|
-
|
157
|
+
### Development Documentation
|
145
158
|
All the functions are class methods
|
146
159
|
|
147
160
|
```ruby
|
148
161
|
rate_limited_enqueue(klass, *params)
|
149
162
|
rate_limited_requeue(klass, *params)
|
150
|
-
|
163
|
+
```
|
164
|
+
|
151
165
|
Queue the job specified to the resque queue specified by `@queue`. `rate_limited_requeue` is intended for use when you need the job to be pushed back to the queue; there are two reasons to split this from `rate_limited_enqueue`. Firstly it makes testing with stubs easier - secondly there is a boundary condition when you need to requeue the last job in the queue.
|
152
166
|
|
153
167
|
```ruby
|
154
168
|
pause
|
155
|
-
|
169
|
+
```
|
170
|
+
|
156
171
|
Pauses the queue specified by `@queue`, if it is not already paused.
|
157
172
|
In most cases you should call `pause_until` to pause a queue when you hit a rate limit.
|
158
173
|
|
159
174
|
```ruby
|
160
175
|
un_pause
|
161
|
-
|
176
|
+
```
|
177
|
+
|
162
178
|
Un-pauses the queue specified by `@queue`, if it is paused.
|
163
179
|
|
164
180
|
```ruby
|
165
181
|
pause_until(timestamp)
|
166
|
-
|
182
|
+
```
|
183
|
+
|
167
184
|
Pauses the queue (specified by `@queue`) and then queues a job to unpause the queue specified by `@queue`, using resque-scheduler to the queue specified by `Resque::Plugins::RateLimited::UnPause.queue` at the timestamp specified.
|
168
185
|
If `resque-schedule` is not included, or `UnPause.queue` isn't specified this will just pause the queue.
|
169
186
|
|
@@ -171,26 +188,29 @@ This is the prefered function to call when you hit a rate limit, since it with w
|
|
171
188
|
|
172
189
|
```ruby
|
173
190
|
paused?
|
174
|
-
|
191
|
+
```
|
192
|
+
|
175
193
|
This returns true or false to indicate wheher the queue is paused. Be aware that the queue state could change get after the call returns, but before your code executes. Use `with_lock` if you need to avoid this.
|
176
194
|
|
177
195
|
```ruby
|
178
196
|
paused_queue_name
|
179
|
-
|
197
|
+
```
|
198
|
+
|
180
199
|
Returns the name of the queue when it is paused.
|
181
200
|
|
182
201
|
```ruby
|
183
202
|
with_lock(&block)
|
184
|
-
|
203
|
+
```
|
204
|
+
|
185
205
|
Takes ownership of the PauseQueue semaphor before executing the block passed. Useful if you need to test the state of the queue and take some action without the state changing.
|
186
206
|
|
187
207
|
```ruby
|
188
208
|
find_class(klass)
|
189
|
-
|
190
|
-
Takes the parameter passed, and if it's a string class name, tries to turn it into a class.
|
209
|
+
```
|
191
210
|
|
211
|
+
Takes the parameter passed, and if it's a string class name, tries to turn it into a class.
|
192
212
|
|
193
|
-
|
213
|
+
### Contributing
|
194
214
|
|
195
215
|
1. Fork it ( https://github.com/[my-github-username]/resque_rate_limited/fork )
|
196
216
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
@@ -198,18 +218,7 @@ Takes the parameter passed, and if it's a string class name, tries to turn it in
|
|
198
218
|
4. Push to the branch (`git push origin my-new-feature`)
|
199
219
|
5. Create a new Pull Request
|
200
220
|
|
201
|
-
|
202
|
-
## Version history
|
203
|
-
|
204
|
-
0.0.x Mostly pre-release versions
|
205
|
-
|
206
|
-
1.0.0 First release version. Breaking change - renamed `pause_for` to be `pause_until` to better reflect function
|
207
|
-
|
208
|
-
1.1.0 Enqueues underlying job instead of directly performing it
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
## Final thoughts
|
221
|
+
### Final thoughts
|
213
222
|
Thanks to [Dominic](https://github.com/dominicsayers) for idea of renaming the redis key - and the sample code that does this.
|
214
223
|
|
215
224
|
This is my first gem - so please forgive any errors - and feedback very welcome
|
data/Rakefile
CHANGED
data/resque-rate_limited.gemspec
CHANGED
@@ -1,43 +1,31 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'resque-rate_limited/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
11
|
-
spec.summary
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
spec.name = 'resque-rate_limited'
|
7
|
+
spec.version = RateLimited::VERSION
|
8
|
+
spec.authors = ['Greg Dowling']
|
9
|
+
spec.email = ['mail@greddowling.com']
|
10
|
+
spec.summary = 'A Resque plugin to help manage jobs that use rate-limited APIs, pausing when you hit the '\
|
11
|
+
'limits and restarting later.'
|
12
|
+
spec.description = 'A Resque plugin which allows you to create dedicated queues for jobs that use rate-limited '\
|
13
|
+
'APIs. These queues will pause when one of the jobs hits a rate limit, and unpause after a '\
|
14
|
+
'suitable time period. The rate-limited queue can be used directly, and just requires '\
|
15
|
+
'catching the rate limit exception and pausing the queue. There are also additional queues '\
|
16
|
+
'provided that already include the pause/retry logic for Twitter, AngelList and Evernote; '\
|
17
|
+
'these allow you to support rate-limited APIs with minimal changes.'
|
18
|
+
spec.homepage = 'http://github.com/Xenapto/resque-rate_limited'
|
19
|
+
spec.license = 'MIT'
|
17
20
|
|
18
|
-
spec.
|
19
|
-
spec.
|
20
|
-
|
21
|
-
spec.
|
22
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
-
spec.require_paths = ['lib']
|
21
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).reject { |f| f =~ %r{^spec/} }
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features|coverage|script)/})
|
24
|
+
spec.require_paths = ['lib']
|
25
25
|
|
26
26
|
spec.add_dependency 'resque', '~> 1.9', '>= 1.9.10'
|
27
27
|
spec.add_dependency 'redis-mutex', '~> 4.0', '>= 4.0.0'
|
28
|
-
|
29
28
|
spec.add_dependency 'angellist_api', '~> 1.0', '>= 1.0.7'
|
30
29
|
spec.add_dependency 'evernote-thrift', '~> 1.25', '>= 1.25.1'
|
31
|
-
spec.add_dependency 'twitter', '
|
32
|
-
|
33
|
-
spec.add_development_dependency 'rake', '~> 10'
|
34
|
-
spec.add_development_dependency 'rspec', '~> 2'
|
35
|
-
spec.add_development_dependency 'simplecov', '~> 0'
|
36
|
-
spec.add_development_dependency 'rubocop', '~> 0'
|
37
|
-
spec.add_development_dependency 'reek', '~> 4'
|
38
|
-
spec.add_development_dependency 'listen', '~> 3.0', '< 3.1' # Dependency of guard, 3.1 requires Ruby 2.2+
|
39
|
-
spec.add_development_dependency 'guard', '~> 2'
|
40
|
-
spec.add_development_dependency 'guard-rspec', '~> 4'
|
41
|
-
spec.add_development_dependency 'guard-rubocop', '~> 1'
|
42
|
-
spec.add_development_dependency 'gem-release', '~> 0'
|
30
|
+
spec.add_dependency 'twitter', '>= 5.11.0'
|
43
31
|
end
|
data/script/console
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-rate_limited
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Dowling
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: resque
|
@@ -94,9 +94,6 @@ dependencies:
|
|
94
94
|
name: twitter
|
95
95
|
requirement: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- - "~>"
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: '5.11'
|
100
97
|
- - ">="
|
101
98
|
- !ruby/object:Gem::Version
|
102
99
|
version: 5.11.0
|
@@ -104,180 +101,34 @@ dependencies:
|
|
104
101
|
prerelease: false
|
105
102
|
version_requirements: !ruby/object:Gem::Requirement
|
106
103
|
requirements:
|
107
|
-
- - "~>"
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '5.11'
|
110
104
|
- - ">="
|
111
105
|
- !ruby/object:Gem::Version
|
112
106
|
version: 5.11.0
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
type: :development
|
121
|
-
prerelease: false
|
122
|
-
version_requirements: !ruby/object:Gem::Requirement
|
123
|
-
requirements:
|
124
|
-
- - "~>"
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: '10'
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: rspec
|
129
|
-
requirement: !ruby/object:Gem::Requirement
|
130
|
-
requirements:
|
131
|
-
- - "~>"
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '2'
|
134
|
-
type: :development
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
requirements:
|
138
|
-
- - "~>"
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: '2'
|
141
|
-
- !ruby/object:Gem::Dependency
|
142
|
-
name: simplecov
|
143
|
-
requirement: !ruby/object:Gem::Requirement
|
144
|
-
requirements:
|
145
|
-
- - "~>"
|
146
|
-
- !ruby/object:Gem::Version
|
147
|
-
version: '0'
|
148
|
-
type: :development
|
149
|
-
prerelease: false
|
150
|
-
version_requirements: !ruby/object:Gem::Requirement
|
151
|
-
requirements:
|
152
|
-
- - "~>"
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
version: '0'
|
155
|
-
- !ruby/object:Gem::Dependency
|
156
|
-
name: rubocop
|
157
|
-
requirement: !ruby/object:Gem::Requirement
|
158
|
-
requirements:
|
159
|
-
- - "~>"
|
160
|
-
- !ruby/object:Gem::Version
|
161
|
-
version: '0'
|
162
|
-
type: :development
|
163
|
-
prerelease: false
|
164
|
-
version_requirements: !ruby/object:Gem::Requirement
|
165
|
-
requirements:
|
166
|
-
- - "~>"
|
167
|
-
- !ruby/object:Gem::Version
|
168
|
-
version: '0'
|
169
|
-
- !ruby/object:Gem::Dependency
|
170
|
-
name: reek
|
171
|
-
requirement: !ruby/object:Gem::Requirement
|
172
|
-
requirements:
|
173
|
-
- - "~>"
|
174
|
-
- !ruby/object:Gem::Version
|
175
|
-
version: '4'
|
176
|
-
type: :development
|
177
|
-
prerelease: false
|
178
|
-
version_requirements: !ruby/object:Gem::Requirement
|
179
|
-
requirements:
|
180
|
-
- - "~>"
|
181
|
-
- !ruby/object:Gem::Version
|
182
|
-
version: '4'
|
183
|
-
- !ruby/object:Gem::Dependency
|
184
|
-
name: listen
|
185
|
-
requirement: !ruby/object:Gem::Requirement
|
186
|
-
requirements:
|
187
|
-
- - "~>"
|
188
|
-
- !ruby/object:Gem::Version
|
189
|
-
version: '3.0'
|
190
|
-
- - "<"
|
191
|
-
- !ruby/object:Gem::Version
|
192
|
-
version: '3.1'
|
193
|
-
type: :development
|
194
|
-
prerelease: false
|
195
|
-
version_requirements: !ruby/object:Gem::Requirement
|
196
|
-
requirements:
|
197
|
-
- - "~>"
|
198
|
-
- !ruby/object:Gem::Version
|
199
|
-
version: '3.0'
|
200
|
-
- - "<"
|
201
|
-
- !ruby/object:Gem::Version
|
202
|
-
version: '3.1'
|
203
|
-
- !ruby/object:Gem::Dependency
|
204
|
-
name: guard
|
205
|
-
requirement: !ruby/object:Gem::Requirement
|
206
|
-
requirements:
|
207
|
-
- - "~>"
|
208
|
-
- !ruby/object:Gem::Version
|
209
|
-
version: '2'
|
210
|
-
type: :development
|
211
|
-
prerelease: false
|
212
|
-
version_requirements: !ruby/object:Gem::Requirement
|
213
|
-
requirements:
|
214
|
-
- - "~>"
|
215
|
-
- !ruby/object:Gem::Version
|
216
|
-
version: '2'
|
217
|
-
- !ruby/object:Gem::Dependency
|
218
|
-
name: guard-rspec
|
219
|
-
requirement: !ruby/object:Gem::Requirement
|
220
|
-
requirements:
|
221
|
-
- - "~>"
|
222
|
-
- !ruby/object:Gem::Version
|
223
|
-
version: '4'
|
224
|
-
type: :development
|
225
|
-
prerelease: false
|
226
|
-
version_requirements: !ruby/object:Gem::Requirement
|
227
|
-
requirements:
|
228
|
-
- - "~>"
|
229
|
-
- !ruby/object:Gem::Version
|
230
|
-
version: '4'
|
231
|
-
- !ruby/object:Gem::Dependency
|
232
|
-
name: guard-rubocop
|
233
|
-
requirement: !ruby/object:Gem::Requirement
|
234
|
-
requirements:
|
235
|
-
- - "~>"
|
236
|
-
- !ruby/object:Gem::Version
|
237
|
-
version: '1'
|
238
|
-
type: :development
|
239
|
-
prerelease: false
|
240
|
-
version_requirements: !ruby/object:Gem::Requirement
|
241
|
-
requirements:
|
242
|
-
- - "~>"
|
243
|
-
- !ruby/object:Gem::Version
|
244
|
-
version: '1'
|
245
|
-
- !ruby/object:Gem::Dependency
|
246
|
-
name: gem-release
|
247
|
-
requirement: !ruby/object:Gem::Requirement
|
248
|
-
requirements:
|
249
|
-
- - "~>"
|
250
|
-
- !ruby/object:Gem::Version
|
251
|
-
version: '0'
|
252
|
-
type: :development
|
253
|
-
prerelease: false
|
254
|
-
version_requirements: !ruby/object:Gem::Requirement
|
255
|
-
requirements:
|
256
|
-
- - "~>"
|
257
|
-
- !ruby/object:Gem::Version
|
258
|
-
version: '0'
|
259
|
-
description: |-
|
260
|
-
A Resque plugin which allows you to create dedicated queues for jobs that use rate limited apis.
|
261
|
-
These queues will pause when one of the jobs hits a rate limit, and unpause after a suitable time period.
|
262
|
-
The rate_limited can be used directly, and just requires catching the rate limit exception and pausing the
|
263
|
-
queue. There are also additional queues provided that already include the pause/rety logic for twitter, angelist
|
264
|
-
and evernote; these allow you to support rate limited apis with minimal changes.
|
107
|
+
description: A Resque plugin which allows you to create dedicated queues for jobs
|
108
|
+
that use rate-limited APIs. These queues will pause when one of the jobs hits a
|
109
|
+
rate limit, and unpause after a suitable time period. The rate-limited queue can
|
110
|
+
be used directly, and just requires catching the rate limit exception and pausing
|
111
|
+
the queue. There are also additional queues provided that already include the pause/retry
|
112
|
+
logic for Twitter, AngelList and Evernote; these allow you to support rate-limited
|
113
|
+
APIs with minimal changes.
|
265
114
|
email:
|
266
115
|
- mail@greddowling.com
|
267
116
|
executables: []
|
268
117
|
extensions: []
|
269
118
|
extra_rdoc_files: []
|
270
119
|
files:
|
120
|
+
- ".codelimate.yml"
|
271
121
|
- ".gitignore"
|
272
122
|
- ".hound.yml"
|
273
123
|
- ".rspec"
|
274
124
|
- ".rubocop.yml"
|
125
|
+
- ".travis.yml"
|
126
|
+
- CHANGELOG.md
|
275
127
|
- Gemfile
|
276
128
|
- Guardfile
|
277
129
|
- LICENSE.txt
|
278
130
|
- README.md
|
279
131
|
- Rakefile
|
280
|
-
- circle.yml
|
281
132
|
- lib/resque-rate_limited/version.rb
|
282
133
|
- lib/resque/plugins/rate_limited/apis/angellist_queue.rb
|
283
134
|
- lib/resque/plugins/rate_limited/apis/base_api_queue.rb
|
@@ -287,12 +138,7 @@ files:
|
|
287
138
|
- lib/resque/plugins/rate_limited/rate_limited_un_pause.rb
|
288
139
|
- lib/resque/rate_limited.rb
|
289
140
|
- resque-rate_limited.gemspec
|
290
|
-
-
|
291
|
-
- spec/apis/evernote_queue_spec.rb
|
292
|
-
- spec/apis/twitter_queue_spec.rb
|
293
|
-
- spec/rate_limited_spec.rb
|
294
|
-
- spec/rate_limited_un_pause_spec.rb
|
295
|
-
- spec/spec_helper.rb
|
141
|
+
- script/console
|
296
142
|
homepage: http://github.com/Xenapto/resque-rate_limited
|
297
143
|
licenses:
|
298
144
|
- MIT
|
@@ -313,15 +159,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
313
159
|
version: '0'
|
314
160
|
requirements: []
|
315
161
|
rubyforge_project:
|
316
|
-
rubygems_version: 2.6.
|
162
|
+
rubygems_version: 2.6.11
|
317
163
|
signing_key:
|
318
164
|
specification_version: 4
|
319
|
-
summary: A Resque plugin to help manage jobs that use rate
|
165
|
+
summary: A Resque plugin to help manage jobs that use rate-limited APIs, pausing when
|
320
166
|
you hit the limits and restarting later.
|
321
167
|
test_files:
|
322
|
-
-
|
323
|
-
- spec/apis/evernote_queue_spec.rb
|
324
|
-
- spec/apis/twitter_queue_spec.rb
|
325
|
-
- spec/rate_limited_spec.rb
|
326
|
-
- spec/rate_limited_un_pause_spec.rb
|
327
|
-
- spec/spec_helper.rb
|
168
|
+
- script/console
|
data/circle.yml
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'resque/rate_limited'
|
3
|
-
|
4
|
-
class RateLimitedTestQueueAL
|
5
|
-
def self.perform(succeed)
|
6
|
-
raise(AngellistApi::Error::TooManyRequests, 'error') unless succeed
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe Resque::Plugins::RateLimited::AngellistQueue do
|
11
|
-
before do
|
12
|
-
Resque::Plugins::RateLimited::AngellistQueue.stub(:paused?).and_return(false)
|
13
|
-
end
|
14
|
-
|
15
|
-
describe 'enqueue' do
|
16
|
-
it 'enqueues to the correct queue with the correct parameters' do
|
17
|
-
Resque.should_receive(:enqueue_to).with(
|
18
|
-
:angellist_api,
|
19
|
-
Resque::Plugins::RateLimited::AngellistQueue,
|
20
|
-
RateLimitedTestQueueAL.to_s,
|
21
|
-
true
|
22
|
-
)
|
23
|
-
Resque::Plugins::RateLimited::AngellistQueue
|
24
|
-
.enqueue(RateLimitedTestQueueAL, true)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe 'perform' do
|
29
|
-
before do
|
30
|
-
Resque.inline = true
|
31
|
-
end
|
32
|
-
context 'with everything' do
|
33
|
-
it 'calls the class with the right parameters' do
|
34
|
-
RateLimitedTestQueueAL.should_receive(:perform).with('test_param')
|
35
|
-
Resque::Plugins::RateLimited::AngellistQueue
|
36
|
-
.enqueue(RateLimitedTestQueueAL, 'test_param')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'with rate limit exception' do
|
41
|
-
before do
|
42
|
-
Resque::Plugins::RateLimited::AngellistQueue.stub(:rate_limited_requeue)
|
43
|
-
end
|
44
|
-
it 'pauses queue when request fails' do
|
45
|
-
Resque::Plugins::RateLimited::AngellistQueue.should_receive(:pause_until)
|
46
|
-
Resque::Plugins::RateLimited::AngellistQueue
|
47
|
-
.enqueue(RateLimitedTestQueueAL, false)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'resque/rate_limited'
|
3
|
-
|
4
|
-
class RateLimitDuration
|
5
|
-
def self.seconds
|
6
|
-
60
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class RateLimitedTestQueueEn
|
11
|
-
def self.perform(succeed)
|
12
|
-
raise(
|
13
|
-
Evernote::EDAM::Error::EDAMSystemException,
|
14
|
-
errorCode: Evernote::EDAM::Error::EDAMErrorCode::RATE_LIMIT_REACHED,
|
15
|
-
rateLimitDuration: RateLimitDuration
|
16
|
-
) unless succeed
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class RateLimitedTestQueueOther
|
21
|
-
def self.perform
|
22
|
-
raise(Evernote::EDAM::Error::EDAMSystemException)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe Resque::Plugins::RateLimited::EvernoteQueue do
|
27
|
-
before do
|
28
|
-
Resque::Plugins::RateLimited::EvernoteQueue.stub(:paused?).and_return(false)
|
29
|
-
end
|
30
|
-
describe 'enqueue' do
|
31
|
-
it 'enqueues to the correct queue with the correct parameters' do
|
32
|
-
Resque.should_receive(:enqueue_to).with(
|
33
|
-
:evernote_api,
|
34
|
-
Resque::Plugins::RateLimited::EvernoteQueue,
|
35
|
-
RateLimitedTestQueueEn.to_s,
|
36
|
-
true
|
37
|
-
)
|
38
|
-
Resque::Plugins::RateLimited::EvernoteQueue
|
39
|
-
.enqueue(RateLimitedTestQueueEn, true)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe 'perform' do
|
44
|
-
before do
|
45
|
-
Resque.inline = true
|
46
|
-
end
|
47
|
-
context 'with everything' do
|
48
|
-
it 'calls the class with the right parameters' do
|
49
|
-
RateLimitedTestQueueEn.should_receive(:perform).with('test_param')
|
50
|
-
Resque::Plugins::RateLimited::EvernoteQueue
|
51
|
-
.enqueue(RateLimitedTestQueueEn, 'test_param')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'with rate limit exception' do
|
56
|
-
before do
|
57
|
-
Resque::Plugins::RateLimited::EvernoteQueue.stub(:rate_limited_requeue)
|
58
|
-
end
|
59
|
-
it 'pauses queue when request fails' do
|
60
|
-
Resque::Plugins::RateLimited::EvernoteQueue.should_receive(:pause_until)
|
61
|
-
Resque::Plugins::RateLimited::EvernoteQueue
|
62
|
-
.enqueue(RateLimitedTestQueueEn, false)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'with exception that is not rate limit' do
|
67
|
-
before do
|
68
|
-
Resque::Plugins::RateLimited::EvernoteQueue.stub(:rate_limited_requeue)
|
69
|
-
end
|
70
|
-
it 'raises the exception when request fails' do
|
71
|
-
expect do
|
72
|
-
Resque::Plugins::RateLimited::EvernoteQueue.enqueue(RateLimitedTestQueueOther)
|
73
|
-
end.to raise_error Evernote::EDAM::Error::EDAMSystemException
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'resque/rate_limited'
|
3
|
-
|
4
|
-
class RateLimitedTestQueueTw
|
5
|
-
def self.perform(succeed)
|
6
|
-
raise(Twitter::Error::TooManyRequests
|
7
|
-
.new('', 'x-rate-limit-reset' => (Time.now + 60).to_i)) unless succeed
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe Resque::Plugins::RateLimited::TwitterQueue do
|
12
|
-
before do
|
13
|
-
Resque::Plugins::RateLimited::TwitterQueue.stub(:paused?).and_return(false)
|
14
|
-
end
|
15
|
-
|
16
|
-
describe 'enqueue' do
|
17
|
-
it 'enqueues to the correct queue with the correct parameters' do
|
18
|
-
Resque.should_receive(:enqueue_to).with(
|
19
|
-
:twitter_api,
|
20
|
-
Resque::Plugins::RateLimited::TwitterQueue,
|
21
|
-
RateLimitedTestQueueTw.to_s,
|
22
|
-
true
|
23
|
-
)
|
24
|
-
Resque::Plugins::RateLimited::TwitterQueue
|
25
|
-
.enqueue(RateLimitedTestQueueTw, true)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe 'perform' do
|
30
|
-
before do
|
31
|
-
Resque.inline = true
|
32
|
-
end
|
33
|
-
context 'with everything' do
|
34
|
-
it 'calls the class with the right parameters' do
|
35
|
-
RateLimitedTestQueueTw.should_receive(:perform).with('test_param')
|
36
|
-
Resque::Plugins::RateLimited::TwitterQueue
|
37
|
-
.enqueue(RateLimitedTestQueueTw, 'test_param')
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'with rate limit exception' do
|
42
|
-
before do
|
43
|
-
Resque::Plugins::RateLimited::TwitterQueue.stub(:rate_limited_requeue)
|
44
|
-
end
|
45
|
-
it 'pauses queue when request fails' do
|
46
|
-
Resque::Plugins::RateLimited::TwitterQueue.should_receive(:pause_until)
|
47
|
-
Resque::Plugins::RateLimited::TwitterQueue
|
48
|
-
.enqueue(RateLimitedTestQueueTw, false)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/spec/rate_limited_spec.rb
DELETED
@@ -1,243 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'resque/rate_limited'
|
3
|
-
|
4
|
-
class RateLimitedTestQueue
|
5
|
-
extend Resque::Plugins::RateLimited
|
6
|
-
|
7
|
-
@queue = :test
|
8
|
-
|
9
|
-
def self.perform(succeed)
|
10
|
-
rate_limited_requeue(self, succeed) unless succeed
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.queue_name_private
|
14
|
-
@queue.to_s
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.queue_private
|
18
|
-
@queue
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe Resque::Plugins::RateLimited do
|
23
|
-
it 'should be compliance with Resque::Plugin document' do
|
24
|
-
expect { Resque::Plugin.lint(Resque::Plugins::RateLimited) }.to_not raise_error
|
25
|
-
end
|
26
|
-
|
27
|
-
shared_examples_for 'queue' do |queue_suffix|
|
28
|
-
it 'should queue to the correct queue' do
|
29
|
-
queue_param = queue_suffix.empty? ? RateLimitedTestQueue.queue_private : "#{RateLimitedTestQueue.queue_name_private}#{queue_suffix}"
|
30
|
-
Resque.should_receive(:enqueue_to).with(queue_param, nil, nil)
|
31
|
-
RateLimitedTestQueue.rate_limited_enqueue(nil, nil)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'when queue is not paused' do
|
36
|
-
before do
|
37
|
-
RateLimitedTestQueue.stub(:paused?).and_return(false)
|
38
|
-
end
|
39
|
-
|
40
|
-
describe 'enqueue' do
|
41
|
-
include_examples 'queue', ''
|
42
|
-
end
|
43
|
-
|
44
|
-
describe 'paused?' do
|
45
|
-
it { RateLimitedTestQueue.paused?.should be false }
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'perform' do
|
49
|
-
it 'should requeue the job on failure' do
|
50
|
-
Resque.should_receive(:enqueue_to)
|
51
|
-
RateLimitedTestQueue.perform(false)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should not requeue the job on success' do
|
55
|
-
Resque.should_not_receive(:enqueue_to)
|
56
|
-
RateLimitedTestQueue.perform(true)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe 'pause' do
|
61
|
-
it 'should rename the queue to paused' do
|
62
|
-
Resque.redis.should_receive(:renamenx).with("queue:#{RateLimitedTestQueue.queue_name_private}", "queue:#{RateLimitedTestQueue.queue_name_private}_paused")
|
63
|
-
RateLimitedTestQueue.pause
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe 'un_pause' do
|
68
|
-
it 'should not unpause the queue' do
|
69
|
-
Resque.redis.should_not_receive(:renamenx).with("queue:#{RateLimitedTestQueue.queue_name_private}", "queue:#{RateLimitedTestQueue.queue_name_private}_paused")
|
70
|
-
RateLimitedTestQueue.un_pause
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe 'pause_until' do
|
75
|
-
before do
|
76
|
-
Resque.redis.stub(:renamenx).and_return(true)
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should pause the queue' do
|
80
|
-
RateLimitedTestQueue.should_receive(:pause)
|
81
|
-
RateLimitedTestQueue.pause_until(Time.now + (5 * 60 * 60))
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'should schedule an unpause job' do
|
85
|
-
Resque::Plugins::RateLimited::UnPause.should_receive(:enqueue)
|
86
|
-
.with(nil, 'RateLimitedTestQueue')
|
87
|
-
RateLimitedTestQueue.pause_until(nil)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'when queue is paused' do
|
93
|
-
before do
|
94
|
-
RateLimitedTestQueue.stub(:paused?).and_return(true)
|
95
|
-
end
|
96
|
-
|
97
|
-
describe 'enqueue' do
|
98
|
-
include_examples 'queue', '_paused'
|
99
|
-
end
|
100
|
-
|
101
|
-
describe 'paused?' do
|
102
|
-
it { RateLimitedTestQueue.paused?.should be true }
|
103
|
-
end
|
104
|
-
|
105
|
-
describe 'perform' do
|
106
|
-
it 'should not execute the block' do
|
107
|
-
Resque.should_receive(:enqueue_to).with("#{RateLimitedTestQueue.queue_name_private}_paused", RateLimitedTestQueue, true)
|
108
|
-
RateLimitedTestQueue.should_not_receive(:perform)
|
109
|
-
RateLimitedTestQueue.around_perform_with_check_and_requeue(true)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe 'un_pause' do
|
114
|
-
it 'should rename the queue to live' do
|
115
|
-
Resque.redis.should_receive(:renamenx).with("queue:#{RateLimitedTestQueue.queue_name_private}_paused", "queue:#{RateLimitedTestQueue.queue_name_private}")
|
116
|
-
RateLimitedTestQueue.un_pause
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe 'when queue is paused and Resque is in inline mode' do
|
122
|
-
let(:resque_prefix) { Resque::Plugins::RateLimited::RESQUE_PREFIX }
|
123
|
-
let(:queue) { resque_prefix + RateLimitedTestQueue.queue_name_private }
|
124
|
-
let(:paused_queue) { resque_prefix + RateLimitedTestQueue.paused_queue_name }
|
125
|
-
|
126
|
-
before do
|
127
|
-
Resque.redis.stub(:exists).with(queue).and_return(false)
|
128
|
-
Resque.redis.stub(:exists).with(paused_queue).and_return(true)
|
129
|
-
Resque.inline = true
|
130
|
-
end
|
131
|
-
|
132
|
-
after do
|
133
|
-
Resque.inline = false
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'would be paused' do
|
137
|
-
expect(Resque.redis.exists(queue)).to eq false
|
138
|
-
expect(Resque.redis.exists(paused_queue)).to eq true
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'says it is not paused' do
|
142
|
-
expect(RateLimitedTestQueue.paused?).to eq false
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'performs the job' do
|
146
|
-
expect do
|
147
|
-
# Stack overflow unless handled
|
148
|
-
RateLimitedTestQueue.rate_limited_enqueue(RateLimitedTestQueue, true)
|
149
|
-
end.not_to raise_error
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
describe 'find_class' do
|
154
|
-
it 'works with symbol' do
|
155
|
-
RateLimitedTestQueue.find_class(RateLimitedTestQueue).should eq RateLimitedTestQueue
|
156
|
-
end
|
157
|
-
|
158
|
-
it 'works with simple string' do
|
159
|
-
RateLimitedTestQueue.find_class('RateLimitedTestQueue').should eq RateLimitedTestQueue
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'works with complex string' do
|
163
|
-
RateLimitedTestQueue.find_class('Resque::Plugins::RateLimited').should eq Resque::Plugins::RateLimited
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
context 'with redis errors' do
|
168
|
-
before do
|
169
|
-
RateLimitedTestQueue.stub(:paused?).and_return(true)
|
170
|
-
end
|
171
|
-
context 'with not found error' do
|
172
|
-
before do
|
173
|
-
Resque.redis.stub(:renamenx).and_raise(Redis::CommandError.new('ERR no such key'))
|
174
|
-
end
|
175
|
-
|
176
|
-
describe 'pause' do
|
177
|
-
it 'should not throw exception' do
|
178
|
-
expect { RateLimitedTestQueue.pause }.to_not raise_error
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
describe 'un_pause' do
|
183
|
-
it 'should not throw exception' do
|
184
|
-
expect { RateLimitedTestQueue.un_pause }.to_not raise_error
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
context 'with other errror' do
|
190
|
-
before do
|
191
|
-
Resque.redis.stub(:renamenx).and_raise(Redis::CommandError.new('ERR something else'))
|
192
|
-
end
|
193
|
-
|
194
|
-
describe 'pause' do
|
195
|
-
it 'should throw exception' do
|
196
|
-
expect { RateLimitedTestQueue.pause }.to raise_error(Redis::CommandError)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
describe 'un_pause' do
|
201
|
-
it 'should throw exception' do
|
202
|
-
expect { RateLimitedTestQueue.un_pause }.to raise_error(Redis::CommandError)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
describe 'paused?' do
|
209
|
-
context 'with paused queue' do
|
210
|
-
before do
|
211
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}_paused").and_return(true)
|
212
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}").and_return(false)
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'should return the true if the paused queue exists' do
|
216
|
-
expect(RateLimitedTestQueue.paused?).to eq(true)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
context 'with un paused queue' do
|
221
|
-
before do
|
222
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}_paused").and_return(false)
|
223
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}").and_return(true)
|
224
|
-
end
|
225
|
-
|
226
|
-
it 'should return the false if the main queue exists exist' do
|
227
|
-
expect(RateLimitedTestQueue.paused?).to eq(false)
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
context 'with unknown queue state' do
|
232
|
-
before do
|
233
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}_paused").and_return(false)
|
234
|
-
Resque.redis.stub(:exists).with("queue:#{RateLimitedTestQueue.queue_name_private}").and_return(false)
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'should return the default' do
|
238
|
-
expect(RateLimitedTestQueue.paused?(true)).to eq(true)
|
239
|
-
expect(RateLimitedTestQueue.paused?(false)).to eq(false)
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'resque/rate_limited'
|
3
|
-
|
4
|
-
class RateLimitedTestQueue
|
5
|
-
end
|
6
|
-
|
7
|
-
describe Resque::Plugins::RateLimited::UnPause do
|
8
|
-
describe 'perform' do
|
9
|
-
it 'unpauses the queue' do
|
10
|
-
RateLimitedTestQueue.should_receive(:un_pause)
|
11
|
-
Resque::Plugins::RateLimited::UnPause.perform(RateLimitedTestQueue)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe 'enqueue' do
|
16
|
-
before { Resque.stub(:respond_to?).and_return(true) }
|
17
|
-
context 'with no queue defined' do
|
18
|
-
it 'does not queue the job' do
|
19
|
-
Resque.should_not_receive(:enqueue_at_with_queue)
|
20
|
-
Resque::Plugins::RateLimited::UnPause.enqueue(Time.now, RateLimitedTestQueue)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context 'with queue defined' do
|
25
|
-
before { Resque::Plugins::RateLimited::UnPause.queue = :queue_name }
|
26
|
-
it 'queues the job' do
|
27
|
-
Resque.should_receive(:enqueue_at_with_queue).with(
|
28
|
-
:queue_name,
|
29
|
-
nil,
|
30
|
-
Resque::Plugins::RateLimited::UnPause,
|
31
|
-
RateLimitedTestQueue
|
32
|
-
)
|
33
|
-
|
34
|
-
Resque::Plugins::RateLimited::UnPause.enqueue(nil, RateLimitedTestQueue)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe 'class_from_string' do
|
40
|
-
it 'converts unqualified classes' do
|
41
|
-
expect(Resque::Plugins::RateLimited::UnPause.class_from_string(RateLimitedTestQueue.to_s))
|
42
|
-
.to eq(RateLimitedTestQueue)
|
43
|
-
end
|
44
|
-
it 'converts qualified classes' do
|
45
|
-
expect(Resque::Plugins::RateLimited::UnPause.class_from_string(Resque::Plugins::RateLimited::UnPause.to_s))
|
46
|
-
.to eq(Resque::Plugins::RateLimited::UnPause)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler/setup'
|
3
|
-
|
4
|
-
require 'rspec'
|
5
|
-
require 'redis-classy'
|
6
|
-
require 'redis-mutex'
|
7
|
-
|
8
|
-
require 'simplecov'
|
9
|
-
|
10
|
-
SimpleCov.start
|
11
|
-
|
12
|
-
RSpec.configure do |_config|
|
13
|
-
# Use database 15 for testing so we don't accidentally step on your real data.
|
14
|
-
RedisClassy.redis = Redis.new(db: 15)
|
15
|
-
unless RedisClassy.keys.empty?
|
16
|
-
abort '[ERROR]: Redis database 15 not empty! If you are sure, run "rake flushdb" beforehand.'
|
17
|
-
end
|
18
|
-
end
|