glutton_ratelimit 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -5
- data/.github/workflows/ruby.yml +20 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +63 -0
- data/LICENSE +23 -23
- data/README.rdoc +156 -130
- data/Rakefile +50 -52
- data/VERSION +1 -1
- data/examples/limit_instance_methods.rb +33 -33
- data/examples/simple_manual.rb +31 -31
- data/glutton_ratelimit.gemspec +64 -64
- data/lib/glutton_ratelimit.rb +39 -38
- data/lib/glutton_ratelimit/averaged_throttle.rb +45 -44
- data/lib/glutton_ratelimit/bursty_ring_buffer.rb +24 -24
- data/lib/glutton_ratelimit/bursty_token_bucket.rb +30 -26
- data/test/helper.rb +20 -20
- data/test/test_glutton_ratelimit_averaged_throttle.rb +15 -15
- data/test/test_glutton_ratelimit_bursty_ring_buffer.rb +15 -15
- data/test/test_glutton_ratelimit_bursty_token_bucket.rb +15 -15
- data/test/testing_module.rb +73 -69
- metadata +56 -43
@@ -1,24 +1,24 @@
|
|
1
|
-
module GluttonRatelimit
|
2
|
-
|
3
|
-
class BurstyRingBuffer < ParentLimiter
|
4
|
-
|
5
|
-
def oldest_timestamp
|
6
|
-
@timestamps
|
7
|
-
@timestamps[0]
|
8
|
-
end
|
9
|
-
|
10
|
-
def current_timestamp= new_stamp
|
11
|
-
@timestamps.push(new_stamp).shift
|
12
|
-
end
|
13
|
-
|
14
|
-
def wait
|
15
|
-
delta = Time.now - oldest_timestamp
|
16
|
-
sleep(@time_period - delta) if delta < @time_period
|
17
|
-
self.current_timestamp = Time.now
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
|
1
|
+
module GluttonRatelimit
|
2
|
+
|
3
|
+
class BurstyRingBuffer < ParentLimiter
|
4
|
+
|
5
|
+
def oldest_timestamp
|
6
|
+
@timestamps ||= Array.new executions, (Time.now - @time_period)
|
7
|
+
@timestamps[0]
|
8
|
+
end
|
9
|
+
|
10
|
+
def current_timestamp= new_stamp
|
11
|
+
@timestamps.push(new_stamp).shift
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait
|
15
|
+
delta = Time.now - oldest_timestamp
|
16
|
+
sleep(@time_period - delta) if delta < @time_period
|
17
|
+
self.current_timestamp = Time.now
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -1,26 +1,30 @@
|
|
1
|
-
module GluttonRatelimit
|
2
|
-
|
3
|
-
class BurstyTokenBucket < ParentLimiter
|
4
|
-
|
5
|
-
|
6
|
-
@
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
|
1
|
+
module GluttonRatelimit
|
2
|
+
|
3
|
+
class BurstyTokenBucket < ParentLimiter
|
4
|
+
def initialize executions, time_period
|
5
|
+
super(executions, time_period)
|
6
|
+
@tokens = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def reset_bucket
|
10
|
+
@oldest_timestamp = Time.now
|
11
|
+
@tokens = @executions
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait
|
15
|
+
reset_bucket if @tokens.nil?
|
16
|
+
|
17
|
+
if @tokens.zero?
|
18
|
+
delta = Time.now - @oldest_timestamp
|
19
|
+
sleep(@time_period - delta) if delta < @time_period
|
20
|
+
reset_bucket
|
21
|
+
end
|
22
|
+
|
23
|
+
@tokens -= 1
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
data/test/helper.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
|
4
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
-
require 'glutton_ratelimit'
|
7
|
-
|
8
|
-
class Test::Unit::TestCase
|
9
|
-
end
|
10
|
-
|
11
|
-
def timed_run ratelimiter, passes = 1
|
12
|
-
before_last_invocation = 0
|
13
|
-
start_time = Time.now
|
14
|
-
ratelimiter.times(passes * ratelimiter.executions + 1) do
|
15
|
-
before_last_invocation = Time.now
|
16
|
-
yield
|
17
|
-
end
|
18
|
-
before_last_invocation - start_time
|
19
|
-
end
|
20
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
require 'glutton_ratelimit'
|
7
|
+
|
8
|
+
class Test::Unit::TestCase
|
9
|
+
end
|
10
|
+
|
11
|
+
def timed_run ratelimiter, passes = 1
|
12
|
+
before_last_invocation = 0
|
13
|
+
start_time = Time.now
|
14
|
+
ratelimiter.times(passes * ratelimiter.executions + 1) do
|
15
|
+
before_last_invocation = Time.now
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
before_last_invocation - start_time
|
19
|
+
end
|
20
|
+
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'testing_module.rb'
|
3
|
-
|
4
|
-
class TestGluttonRatelimitAveragedThrottle < Test::Unit::TestCase
|
5
|
-
include TestingModule
|
6
|
-
|
7
|
-
def setup
|
8
|
-
@testClass = GluttonRatelimit::AveragedThrottle
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_object_creations
|
12
|
-
rl = @testClass.new 1, 1
|
13
|
-
assert_instance_of GluttonRatelimit::AveragedThrottle, rl
|
14
|
-
end
|
15
|
-
end
|
1
|
+
require 'helper'
|
2
|
+
require 'testing_module.rb'
|
3
|
+
|
4
|
+
class TestGluttonRatelimitAveragedThrottle < Test::Unit::TestCase
|
5
|
+
include TestingModule # All the shared tests are in here.
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@testClass = GluttonRatelimit::AveragedThrottle
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_object_creations
|
12
|
+
rl = @testClass.new 1, 1
|
13
|
+
assert_instance_of GluttonRatelimit::AveragedThrottle, rl
|
14
|
+
end
|
15
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'testing_module.rb'
|
3
|
-
|
4
|
-
class TestGluttonRatelimitBurstyRingBuffer < Test::Unit::TestCase
|
5
|
-
include TestingModule
|
6
|
-
|
7
|
-
def setup
|
8
|
-
@testClass = GluttonRatelimit::BurstyRingBuffer
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_object_creations
|
12
|
-
rl = @testClass.new 1, 1
|
13
|
-
assert_instance_of GluttonRatelimit::BurstyRingBuffer, rl
|
14
|
-
end
|
15
|
-
end
|
1
|
+
require 'helper'
|
2
|
+
require 'testing_module.rb'
|
3
|
+
|
4
|
+
class TestGluttonRatelimitBurstyRingBuffer < Test::Unit::TestCase
|
5
|
+
include TestingModule # All the shared tests are in here.
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@testClass = GluttonRatelimit::BurstyRingBuffer
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_object_creations
|
12
|
+
rl = @testClass.new 1, 1
|
13
|
+
assert_instance_of GluttonRatelimit::BurstyRingBuffer, rl
|
14
|
+
end
|
15
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'testing_module.rb'
|
3
|
-
|
4
|
-
class TestGluttonRatelimitBurtyTokenBucket < Test::Unit::TestCase
|
5
|
-
include TestingModule
|
6
|
-
|
7
|
-
def setup
|
8
|
-
@testClass = GluttonRatelimit::BurstyTokenBucket
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_object_creations
|
12
|
-
rl = @testClass.new 1, 1
|
13
|
-
assert_instance_of GluttonRatelimit::BurstyTokenBucket, rl
|
14
|
-
end
|
15
|
-
end
|
1
|
+
require 'helper'
|
2
|
+
require 'testing_module.rb'
|
3
|
+
|
4
|
+
class TestGluttonRatelimitBurtyTokenBucket < Test::Unit::TestCase
|
5
|
+
include TestingModule # All the shared tests are in here.
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@testClass = GluttonRatelimit::BurstyTokenBucket
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_object_creations
|
12
|
+
rl = @testClass.new 1, 1
|
13
|
+
assert_instance_of GluttonRatelimit::BurstyTokenBucket, rl
|
14
|
+
end
|
15
|
+
end
|
data/test/testing_module.rb
CHANGED
@@ -1,69 +1,73 @@
|
|
1
|
-
module TestingModule
|
2
|
-
# This module assumes use as a mixin within
|
3
|
-
# a test class which defines @testClass.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
1
|
+
module TestingModule
|
2
|
+
# This module assumes use as a mixin within
|
3
|
+
# a test class which defines @testClass.
|
4
|
+
|
5
|
+
TIMING_TOLERANCE = 0.995 # Timing can be off by 0.5%
|
6
|
+
|
7
|
+
def test_120_tasks_every_second_with_ms_task
|
8
|
+
min_time = 1
|
9
|
+
rl = @testClass.new 120, min_time
|
10
|
+
delta = timed_run(rl) { sleep 0.001 }
|
11
|
+
# puts "\n#{delta} >? #{min_time}"
|
12
|
+
assert((delta / min_time) > TIMING_TOLERANCE)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_120_tasks_every_quarter_second_with_ms_task
|
16
|
+
min_time = 0.25
|
17
|
+
rl = @testClass.new 120, min_time
|
18
|
+
delta = timed_run(rl) { sleep 0.001 }
|
19
|
+
# puts "\n#{delta} >? #{min_time}"
|
20
|
+
assert((delta / min_time) > TIMING_TOLERANCE)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_120_tasks_every_second_with_cenisecond_task
|
24
|
+
min_time = 1
|
25
|
+
rl = @testClass.new 120, min_time
|
26
|
+
delta = timed_run(rl) { sleep 0.01 }
|
27
|
+
# puts "\n#{delta} >? #{min_time}"
|
28
|
+
assert((delta / min_time) > TIMING_TOLERANCE)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_50_tasks_every_second_with_no_task
|
32
|
+
min_time = 1
|
33
|
+
rl = @testClass.new 50, min_time
|
34
|
+
delta = timed_run(rl) { sleep 0 }
|
35
|
+
# puts "\n#{delta} >? #{min_time}"
|
36
|
+
assert((delta / min_time) > TIMING_TOLERANCE)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_1_task_every_1_seconds_with_1_second_task
|
40
|
+
min_time = 1
|
41
|
+
rl = @testClass.new 1, min_time
|
42
|
+
delta = timed_run(rl) { sleep 1 }
|
43
|
+
# puts "\n#{delta} >? #{min_time}"
|
44
|
+
assert((delta / min_time) > TIMING_TOLERANCE)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_5_tasks_every_quarter_second_four_runs_with_ms_task
|
48
|
+
min_time = 0.25
|
49
|
+
runs = 4
|
50
|
+
rl = @testClass.new 1, min_time
|
51
|
+
delta = timed_run(rl, runs) { sleep 0.001 }
|
52
|
+
# puts "\n#{delta} >? #{min_time * runs}"
|
53
|
+
assert((delta / (min_time * runs)) > TIMING_TOLERANCE)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_120_tasks_every_half_second_two_runs_with_no_task
|
57
|
+
min_time = 0.5
|
58
|
+
runs = 2
|
59
|
+
rl = @testClass.new 120, min_time
|
60
|
+
delta = timed_run(rl, 2) { sleep 0 }
|
61
|
+
# puts "\n#{delta} >? #{min_time * runs}"
|
62
|
+
assert((delta / (min_time * runs)) > TIMING_TOLERANCE)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_10_tasks_every_1_seconds_two_runs_with_short_rnd_task
|
66
|
+
min_time = 1
|
67
|
+
runs = 2
|
68
|
+
rl = @testClass.new 10, min_time
|
69
|
+
delta = timed_run(rl, 2) { sleep(0.2 * rand) }
|
70
|
+
# puts "\n#{delta} >? #{min_time * runs}"
|
71
|
+
assert((delta / (min_time * runs)) > TIMING_TOLERANCE)
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,34 +1,58 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: glutton_ratelimit
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Wally Glutton
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
date: 2019-12-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jeweler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
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: test-unit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A Ruby library for limiting the number of times a method can be invoked
|
42
|
+
within a specified time period.
|
22
43
|
email: stungeye@gmail.com
|
23
44
|
executables: []
|
24
|
-
|
25
45
|
extensions: []
|
26
|
-
|
27
|
-
extra_rdoc_files:
|
46
|
+
extra_rdoc_files:
|
28
47
|
- LICENSE
|
29
48
|
- README.rdoc
|
30
|
-
files:
|
31
|
-
- .document
|
49
|
+
files:
|
50
|
+
- ".document"
|
51
|
+
- ".github/workflows/ruby.yml"
|
52
|
+
- ".ruby-version"
|
53
|
+
- ".travis.yml"
|
54
|
+
- Gemfile
|
55
|
+
- Gemfile.lock
|
32
56
|
- LICENSE
|
33
57
|
- README.rdoc
|
34
58
|
- Rakefile
|
@@ -47,36 +71,25 @@ files:
|
|
47
71
|
- test/testing_module.rb
|
48
72
|
homepage: http://github.com/stungeye/glutton_ratelimit
|
49
73
|
licenses: []
|
50
|
-
|
74
|
+
metadata: {}
|
51
75
|
post_install_message:
|
52
76
|
rdoc_options: []
|
53
|
-
|
54
|
-
require_paths:
|
77
|
+
require_paths:
|
55
78
|
- lib
|
56
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
-
|
58
|
-
requirements:
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
59
81
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
version: "0"
|
65
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
|
-
requirements:
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
68
86
|
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
|
71
|
-
segments:
|
72
|
-
- 0
|
73
|
-
version: "0"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
74
89
|
requirements: []
|
75
|
-
|
76
90
|
rubyforge_project:
|
77
|
-
rubygems_version:
|
91
|
+
rubygems_version: 2.7.6.2
|
78
92
|
signing_key:
|
79
|
-
specification_version:
|
93
|
+
specification_version: 4
|
80
94
|
summary: Simple Ruby library for self-imposed rater-limiting.
|
81
95
|
test_files: []
|
82
|
-
|