full_throttle 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +42 -7
- data/full_throttle.gemspec +1 -1
- data/lib/throttle.rb +2 -2
- data/lib/throttle/version.rb +1 -1
- data/spec/lib/throttle/redis_script_spec.rb +37 -17
- data/spec/lib/throttle_spec.rb +7 -2
- metadata +16 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b46c0880281fcab9692c92cc16af9744b558af25
|
4
|
+
data.tar.gz: dbd5096b50d090cb1cb9e598fcedef8548c56324
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13584c7e550fc25474d98f45da57177f848d53017c310f207ea3aff6464c4500e72aa6299d678df1e1151913eb929e5247893610df642505c99a59536ae9196b
|
7
|
+
data.tar.gz: 090680a38e771d545bbd26d8035677b4e7f0b2d49a401c4e37656cd42b3abfbac1c2064151ee813f085925a84bee50b0c1eb9e11f12e797b3a33a4729fa0dd3c
|
data/README.md
CHANGED
@@ -1,6 +1,45 @@
|
|
1
|
-
# Throttle
|
1
|
+
# Full Throttle
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Pull the breaks on your background processing, protect api calls from abuse, and manage throughput with 0 hassle leveraging Redis to throttle concurrent processes.
|
6
|
+
|
7
|
+
Atomicity and thread-safety of throttle guaranteed by good use of Redis.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
response = Throttle.for(:user_info, 200) { api["users/#{id}"].get }
|
13
|
+
user.update(response)
|
14
|
+
```
|
15
|
+
|
16
|
+
There we have `:user_info` is the id of the throttle, `200` is the number of times that id can be executed in one second. *Full Throttle* is designed for high speed action, not long throttling windows.
|
17
|
+
|
18
|
+
__get updated status__
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
instance = Throttle.for(:user_info)
|
22
|
+
instance.status # [ bucket_time, bucket_count, bucket_size ]
|
23
|
+
```
|
24
|
+
|
25
|
+
__handle or log throttled actions__
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
begin
|
29
|
+
Throttle.for(:search_index, 300) { record.update_index! }
|
30
|
+
rescue Throttle::ThrottledError => e
|
31
|
+
...
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
__manage throughput without code pushes__ running on the console or on a cronjob to raise the limits at night and take it easy during the day
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
if (22...7).include?(Time.now.hour)
|
39
|
+
Throttle.for(:upstream_sync).set_bucket_size!(500)
|
40
|
+
end
|
41
|
+
```
|
2
42
|
|
3
|
-
TODO: Write a gem description
|
4
43
|
|
5
44
|
## Installation
|
6
45
|
|
@@ -18,13 +57,9 @@ Or install it yourself as:
|
|
18
57
|
|
19
58
|
$ gem install throttle
|
20
59
|
|
21
|
-
## Usage
|
22
|
-
|
23
|
-
TODO: Write usage instructions here
|
24
|
-
|
25
60
|
## Contributing
|
26
61
|
|
27
|
-
1. Fork it ( https://github.com/
|
62
|
+
1. Fork it ( https://github.com/rafaelbandeira3/full_throttle/fork )
|
28
63
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
64
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
65
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/full_throttle.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "redis", "~> 3.0
|
21
|
+
spec.add_dependency "redis", "~> 3.0"
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.7"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
spec.add_development_dependency "rspec", "~> 2.3"
|
data/lib/throttle.rb
CHANGED
@@ -12,7 +12,7 @@ module Throttle
|
|
12
12
|
:default_ns,
|
13
13
|
:default_polling
|
14
14
|
|
15
|
-
def for(key, max_per_second, opts = {}, &block)
|
15
|
+
def for(key, max_per_second = nil, opts = {}, &block)
|
16
16
|
polling = opts[:polling] || Throttle.default_polling
|
17
17
|
timeout = opts[:timeout] || Throttle.default_timeout
|
18
18
|
redis = opts[:redis] || Throttle.default_redis_client
|
@@ -22,7 +22,7 @@ module Throttle
|
|
22
22
|
strategy.set_bucket_size!
|
23
23
|
|
24
24
|
instance = Instance.new(strategy, polling, timeout)
|
25
|
-
instance.limit(&block)
|
25
|
+
block_given? ? instance.limit(&block) : instance
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/throttle/version.rb
CHANGED
@@ -34,29 +34,49 @@ describe Throttle::RedisScript do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
describe "acquiring permission" do
|
37
|
-
before(:each) {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
expect(subject.acquire).to eq [true, 2, t.to_i]
|
43
|
-
expect(subject.acquire).to eq [true, 3, t.to_i]
|
44
|
-
expect(subject.acquire).to eq [false, 3, t.to_i]
|
45
|
-
expect(subject.acquire).to eq [false, 3, t.to_i]
|
46
|
-
end
|
37
|
+
before(:each) { Timecop.freeze(time) }
|
38
|
+
after(:each) { Timecop.return }
|
39
|
+
|
40
|
+
it "returns time, count and flag" do
|
41
|
+
expect(subject.acquire).to eq [true, 1, time.to_i]
|
47
42
|
end
|
48
43
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
expect(subject.acquire).to eq [true,
|
53
|
-
expect(subject.acquire).to eq [true,
|
54
|
-
expect(subject.acquire).to eq [
|
44
|
+
context do
|
45
|
+
before(:each) { subject.set_bucket_size! }
|
46
|
+
it "acquires entry on bucket isn't full" do
|
47
|
+
expect(subject.acquire).to eq [true, 1, time.to_i]
|
48
|
+
expect(subject.acquire).to eq [true, 2, time.to_i]
|
49
|
+
expect(subject.acquire).to eq [true, 3, time.to_i]
|
50
|
+
expect(subject.acquire).to eq [false, 3, time.to_i]
|
51
|
+
expect(subject.acquire).to eq [false, 3, time.to_i]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "empties bucket after bucket duration" do
|
55
|
+
expect(subject.acquire).to eq [true, 1, time.to_i]
|
56
|
+
expect(subject.acquire).to eq [true, 2, time.to_i]
|
57
|
+
expect(subject.acquire).to eq [true, 3, time.to_i]
|
58
|
+
expect(subject.acquire).to eq [false, 3, time.to_i]
|
59
|
+
|
60
|
+
Timecop.freeze(time + 1)
|
61
|
+
expect(subject.acquire).to eq [true, 1, (time + 1).to_i]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "changes bucket size at runtime" do
|
65
|
+
expect(subject.acquire).to eq [true, 1, time.to_i]
|
66
|
+
expect(subject.acquire).to eq [true, 2, time.to_i]
|
67
|
+
expect(subject.acquire).to eq [true, 3, time.to_i]
|
68
|
+
expect(subject.acquire).to eq [false, 3, time.to_i]
|
55
69
|
|
56
70
|
subject.set_bucket_size!(4)
|
57
|
-
expect(subject.acquire).to eq [true, 4,
|
71
|
+
expect(subject.acquire).to eq [true, 4, time.to_i]
|
58
72
|
end
|
59
73
|
end
|
74
|
+
|
75
|
+
it "acquires always if no size set" do
|
76
|
+
credibility = ENV["CREDIBLE"] ? Float::INFINITY : 20
|
77
|
+
|
78
|
+
(0..credibility).each {|n| expect(subject.acquire).to eq [true, n + 1, time.to_i] }
|
79
|
+
end
|
60
80
|
end
|
61
81
|
end
|
62
82
|
end
|
data/spec/lib/throttle_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe Throttle do
|
|
11
11
|
let(:opts) { {} }
|
12
12
|
|
13
13
|
shared_examples "Throttle API" do
|
14
|
-
|
14
|
+
before(:each) do
|
15
15
|
expect(described_class::RedisScript).to receive(:new).
|
16
16
|
with(redis, "#{ns}:#{key}", max).
|
17
17
|
and_call_original
|
@@ -19,9 +19,14 @@ describe Throttle do
|
|
19
19
|
expect(described_class::Instance).to receive(:new).
|
20
20
|
with(kind_of(described_class::RedisScript), polling, timeout).
|
21
21
|
and_call_original
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
+
it "initializes throttle with options" do
|
25
|
+
expect(described_class.for(key, max, opts)).to be_a(described_class::Instance)
|
26
|
+
end
|
24
27
|
|
28
|
+
it "initializes and returns limit" do
|
29
|
+
expect(counter).to receive(:count)
|
25
30
|
described_class.for(key, max, opts) { counter.count }
|
26
31
|
end
|
27
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: full_throttle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafael Bandeira
|
@@ -14,70 +14,70 @@ dependencies:
|
|
14
14
|
name: redis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 3.0
|
19
|
+
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 3.0
|
26
|
+
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.7'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.7'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '10.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '2.3'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: timecop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ~>
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 0.7.1
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ~>
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.7.1
|
83
83
|
description: Redis based throttle mechanism to be used by concurrent background jobs
|
@@ -113,17 +113,17 @@ require_paths:
|
|
113
113
|
- lib
|
114
114
|
required_ruby_version: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
|
-
- -
|
116
|
+
- - '>='
|
117
117
|
- !ruby/object:Gem::Version
|
118
118
|
version: '0'
|
119
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
120
|
requirements:
|
121
|
-
- -
|
121
|
+
- - '>='
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '0'
|
124
124
|
requirements: []
|
125
125
|
rubyforge_project:
|
126
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.0.14
|
127
127
|
signing_key:
|
128
128
|
specification_version: 4
|
129
129
|
summary: Throttle mechanism for distributed work
|
@@ -132,4 +132,3 @@ test_files:
|
|
132
132
|
- spec/lib/throttle/redis_script_spec.rb
|
133
133
|
- spec/lib/throttle_spec.rb
|
134
134
|
- spec/spec_helper.rb
|
135
|
-
has_rdoc:
|