rate_limit-htb 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 130ddde0f1a336c53bab0089fb2d0355a7f38f16
4
+ data.tar.gz: ce908f450073260e47d55e377dbfe2b76960bc79
5
+ SHA512:
6
+ metadata.gz: 0024efa388d90fd228c308d4bb61251e76d4c26385d7cf741de53991fd3cbd7d4b0982a798d7fd191662412196c4b3ba92378cb6cd05a8504034dc9648acdccc
7
+ data.tar.gz: c6661bfc9b20e2f0368633e090609020904a43516b7553e344aa3187ea7b70401dc73c1e3e83f70cdafc5e6b1aac40b5efec548dd92e269afe345a3213e106bb
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.16.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in rate_limit-htb.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rate_limit-htb (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (10.5.0)
11
+ rspec (3.7.0)
12
+ rspec-core (~> 3.7.0)
13
+ rspec-expectations (~> 3.7.0)
14
+ rspec-mocks (~> 3.7.0)
15
+ rspec-core (3.7.1)
16
+ rspec-support (~> 3.7.0)
17
+ rspec-expectations (3.7.0)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.7.0)
20
+ rspec-mocks (3.7.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.7.0)
23
+ rspec-support (3.7.1)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.16)
30
+ rake (~> 10.0)
31
+ rate_limit-htb!
32
+ rspec (~> 3.0)
33
+
34
+ BUNDLED WITH
35
+ 1.16.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Dominic Althaus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # RateLimit::Htb
2
+
3
+ This is a Ruby implementation of the hierarchical Token bucket algorithm. It allows you to limit
4
+ the rate certain operations are executed.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'rate_limit-htb'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install rate_limit-htb
21
+
22
+ ## Usage
23
+
24
+ ```ruby
25
+ root = RateLimit::Htb::Bucket.new 1000
26
+ child1 = RateLimit::Htb::Bucket.new 300, root
27
+ child2 = RateLimit::Htb::Bucket.new 600, root
28
+
29
+ threads = []
30
+
31
+ # prints stuff twice as fast as the other two
32
+ threads << Thread.new do
33
+ 100.times do
34
+ child1.blocking_take 200
35
+ puts "stuff"
36
+ end
37
+ end
38
+
39
+ threads << Thread.new do
40
+ 100.times do
41
+ child2.blocking_take 400
42
+ puts "stuff2"
43
+ end
44
+ end
45
+
46
+ # Is called rarely because the other thread needs all the tokens.
47
+ threads << Thread.new do
48
+ 100.times do
49
+ child2.blocking_take 400
50
+ puts "stuff3"
51
+ end
52
+ end
53
+
54
+ threads.each { |t| t.join }
55
+ ```
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/HappyKadaver/rate_limit-htb.
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rate_limit/htb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ module RateLimit
2
+ module Htb
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,128 @@
1
+ require "rate_limit/htb/version"
2
+
3
+ module RateLimit
4
+ # Htb is a ruby implementation of the hierarchical token bucket algorithm.
5
+ #
6
+ # It allows you to do rate limiting in a hierarchical fashion in other words you can put a large rate at the root of
7
+ # and smaller rates as children. This way you can guarantee your children a minimum rate and a maximum rate up to the
8
+ # rate of the parents. The rate is represented by Tokens you take out of buckets.
9
+ #
10
+ # The sum of the rates of the children on the same level may not be greater than the rate of their parent or they will
11
+ # exceed the the rate of their parent.
12
+ #
13
+ # =Example
14
+ # root = RateLimit::Htb::Bucket.new 1000
15
+ # child1 = RateLimit::Htb::Bucket.new 300, root
16
+ # child2 = RateLimit::Htb::Bucket.new 600, root
17
+ #
18
+ # threads = []
19
+ #
20
+ # # prints stuff twice as fast as the other two
21
+ # threads << Thread.new do
22
+ # 100.times do
23
+ # child1.blocking_take 200
24
+ # puts "stuff"
25
+ # end
26
+ # end
27
+ #
28
+ # threads << Thread.new do
29
+ # 100.times do
30
+ # child2.blocking_take 400
31
+ # puts "stuff2"
32
+ # end
33
+ # end
34
+ #
35
+ # # Is called rarely because the other thread needs all the tokens.
36
+ # threads << Thread.new do
37
+ # 100.times do
38
+ # child2.blocking_take 400
39
+ # puts "stuff3"
40
+ # end
41
+ # end
42
+ #
43
+ # threads.each { |t| t.join }
44
+ module Htb
45
+ class Bucket
46
+
47
+ # ==== Attributes
48
+ #
49
+ # * +rate+ - Amount of tokens generated every second.
50
+ # * +parent+ - Parent of this bucket. Any tokens taken from this bucket will also be taken from parent. When a
51
+ # parent is specified the rate of this bucket will be between the rate of this bucket and the rate of the parent.
52
+ # The parent bucket should have a larger rate than their children.
53
+ #
54
+ def initialize(rate, parent = nil)
55
+ @lock = Monitor.new
56
+ @rate = rate
57
+ @bucket_size = rate
58
+ @parent = parent
59
+ @tokens = rate
60
+ @last_update_timestamp = Time.now
61
+ end
62
+
63
+ # Take the specified amount of tokens from this bucket
64
+ #
65
+ # If you want your code to block execution until it could take the specified amount of tokens use #blocking_take
66
+ # instead.
67
+ #
68
+ # * *Returns* :
69
+ # - true if the amount of tokens could be taken from this bucket or a parent.
70
+ def take(amount)
71
+ @lock.synchronize do
72
+ replenish
73
+
74
+ could_take = can_take? amount
75
+ account amount if could_take
76
+
77
+ could_take
78
+ end
79
+ end
80
+
81
+
82
+ # This method takes the specified amount of tokens from the bucket and blocks execution until it was successful.
83
+ #
84
+ # This method tries to be smart about the amount of time it waits. It will wait the minimum time it takes to
85
+ # replenish enough tokens.
86
+ def blocking_take(amount)
87
+ # Try to take amount tokens from this bucket or wait for the tokens to replenish
88
+ # do this until we could get the amount of tokens we wanted
89
+ until take amount
90
+ duration = amount.to_f / @rate
91
+ puts "sleeping for #{duration}"
92
+ sleep duration
93
+ end
94
+ end
95
+
96
+ protected
97
+
98
+ def replenish(timestamp = Time.now)
99
+ @lock.synchronize do
100
+ @parent.replenish timestamp if @parent
101
+
102
+ elapsed = timestamp - @last_update_timestamp
103
+ @tokens = [@bucket_size, @tokens + @rate * elapsed].min
104
+
105
+ @last_update_timestamp = timestamp
106
+ end
107
+ end
108
+
109
+ def can_take?(amount)
110
+ @tokens >= amount || (@parent && @parent.can_take?(amount))
111
+ end
112
+
113
+ def account(amount)
114
+ @lock.synchronize do
115
+ @tokens = @tokens - amount
116
+ @parent.account amount if @parent
117
+ end
118
+ end
119
+
120
+ def rate
121
+ return @rate if @rate != 0
122
+ return @parent.rate if @parent
123
+
124
+ raise 'NO Bucket in this hierachie has a Limit other than zero!!'
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,27 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rate_limit/htb/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rate_limit-htb"
8
+ spec.version = RateLimit::Htb::VERSION
9
+ spec.authors = ["Dominic Althaus"]
10
+ spec.email = ["althaus.dominic@gmail.com"]
11
+
12
+ spec.summary = %q{A ruby implementation of the hierarchical token bucket algorithm.}
13
+ spec.description = %q{A ruby implementation of the hierarchical token bucket algorithm. It allows you to define rates on different levels of a hierachie to limit the speed of certain operations.}
14
+ spec.homepage = "https://github.com/HappyKadaver/rate_limit-htb"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rate_limit-htb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dominic Althaus
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: A ruby implementation of the hierarchical token bucket algorithm. It
56
+ allows you to define rates on different levels of a hierachie to limit the speed
57
+ of certain operations.
58
+ email:
59
+ - althaus.dominic@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".rspec"
66
+ - ".travis.yml"
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/console
73
+ - bin/setup
74
+ - lib/rate_limit/htb.rb
75
+ - lib/rate_limit/htb/version.rb
76
+ - rate_limit-htb.gemspec
77
+ homepage: https://github.com/HappyKadaver/rate_limit-htb
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.6.14
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: A ruby implementation of the hierarchical token bucket algorithm.
101
+ test_files: []