throttler 0.2.1 → 0.2.2
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.
- data/LICENSE +1 -1
- data/README.md +14 -34
- data/lib/throttler/timer.rb +8 -8
- data/lib/throttler/version.rb +4 -0
- data/lib/throttler.rb +6 -10
- data/spec/fixtures/foo.rb +2 -1
- data/spec/integration/fibers_spec.rb +3 -3
- data/spec/integration/loop_spec.rb +3 -3
- data/spec/integration/processes_spec.rb +1 -1
- data/spec/integration/threads_spec.rb +2 -2
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/throttler/timer_spec.rb +21 -12
- data/spec/unit/throttler_spec.rb +24 -15
- metadata +32 -18
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,47 +1,27 @@
|
|
1
1
|
Throttler
|
2
2
|
=========
|
3
3
|
|
4
|
-
|
4
|
+
Throttler is a tired, cranky module that throttles parallel-running Ruby scripts on a single machine.
|
5
5
|
|
6
|
-

|
7
7
|
|
8
8
|
Example
|
9
|
-
|
9
|
+
-------
|
10
10
|
|
11
|
-
|
11
|
+
Our very own peculiar use case: We have multiple Resque workers hitting the Amazon IP on multiple addresses and want to make sure they don't fire more than once per locale per IP.
|
12
12
|
|
13
13
|
class Worker
|
14
14
|
include Throttler
|
15
|
-
|
16
|
-
attr_accessor :
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
# Say a request downloads in two seconds on average
|
27
|
-
throttle(name, interval) { sleep(2) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
worker, count = Worker.new, 0
|
32
|
-
|
33
|
-
(0..3).each do |port|
|
34
|
-
10.times do
|
35
|
-
Thread.new do
|
36
|
-
count += 1
|
37
|
-
worker.interface = "eth#{port}"
|
38
|
-
loop{ worker.request }
|
15
|
+
|
16
|
+
attr_accessor :locale,
|
17
|
+
:interface
|
18
|
+
|
19
|
+
def perform
|
20
|
+
scope = "#{locale}-#{interface}"
|
21
|
+
freq = 1.0
|
22
|
+
|
23
|
+
throttle(scope, interval) do
|
24
|
+
# perform a request
|
39
25
|
end
|
40
26
|
end
|
41
27
|
end
|
42
|
-
|
43
|
-
sleep 10.25
|
44
|
-
|
45
|
-
# We expect workers to have sent 11 requests within 10 seconds on
|
46
|
-
# each of the three available network interfaces.
|
47
|
-
count.should eql(33)
|
data/lib/throttler/timer.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
module Throttler
|
1
|
+
module Throttler #:nodoc:
|
2
2
|
class Timer
|
3
3
|
def initialize(scope)
|
4
4
|
path = "/tmp/.#{scope}"
|
5
|
-
@
|
5
|
+
@timer = File.open(path, File::RDWR|File::CREAT)
|
6
6
|
end
|
7
7
|
|
8
8
|
def lock
|
9
|
-
@
|
9
|
+
@timer.flock(File::LOCK_EX)
|
10
10
|
end
|
11
11
|
|
12
12
|
def timestamp
|
13
|
-
@timestamp ||= @
|
13
|
+
@timestamp ||= @timer.gets.to_f
|
14
14
|
end
|
15
15
|
|
16
16
|
def timestamp=(time)
|
17
|
-
@
|
18
|
-
@
|
17
|
+
@timer.rewind
|
18
|
+
@timer.write(time)
|
19
19
|
@timestamp = time
|
20
20
|
end
|
21
21
|
|
22
22
|
def unlock
|
23
|
-
@
|
24
|
-
@
|
23
|
+
@timer.flock(File::LOCK_UN)
|
24
|
+
@timer.close
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/throttler.rb
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "throttler/timer"
|
2
2
|
|
3
|
-
#
|
3
|
+
# = Throttler
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# An old, rusty throttler that gets the job done
|
6
6
|
module Throttler
|
7
7
|
|
8
|
-
# Throttles the frequency in which a block is run
|
8
|
+
# Throttles the frequency in which a block is run
|
9
9
|
#
|
10
|
-
#
|
11
|
-
|
12
|
-
#
|
13
|
-
# throttle("foo") { some_code }
|
14
|
-
#
|
15
|
-
def throttle(scope, interval=1.0)
|
10
|
+
# Optionally pass a scope and interval.
|
11
|
+
def throttle(scope="throttler", interval=1.0)
|
16
12
|
timer = Timer.new(scope)
|
17
13
|
timer.lock
|
18
14
|
sleep [timer.timestamp + interval - Time.now.to_f, 0.0].max
|
data/spec/fixtures/foo.rb
CHANGED
@@ -9,11 +9,11 @@ describe "Throttler" do
|
|
9
9
|
include Throttler
|
10
10
|
|
11
11
|
def bar
|
12
|
-
throttle
|
12
|
+
throttle { }
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
FileUtils.rm "/tmp/.
|
16
|
+
FileUtils.rm "/tmp/.throttler", :force => true
|
17
17
|
end
|
18
18
|
|
19
19
|
it "throttles fibers" do
|
@@ -24,6 +24,6 @@ describe "Throttler" do
|
|
24
24
|
3.times { fib.resume }
|
25
25
|
end
|
26
26
|
|
27
|
-
time.should
|
27
|
+
time.should be_within(0.1).of(2)
|
28
28
|
end
|
29
29
|
end
|
@@ -8,11 +8,11 @@ describe "Throttler" do
|
|
8
8
|
include Throttler
|
9
9
|
|
10
10
|
def bar
|
11
|
-
throttle
|
11
|
+
throttle { }
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
FileUtils.rm "/tmp/.
|
15
|
+
FileUtils.rm "/tmp/.throttler", :force => true
|
16
16
|
end
|
17
17
|
|
18
18
|
it "throttles a loop" do
|
@@ -22,6 +22,6 @@ describe "Throttler" do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
time.should
|
25
|
+
time.should be_within(0.1).of(2)
|
26
26
|
end
|
27
27
|
end
|
@@ -7,7 +7,7 @@ describe "Throttler" do
|
|
7
7
|
include Throttler
|
8
8
|
|
9
9
|
def bar
|
10
|
-
throttle
|
10
|
+
throttle { }
|
11
11
|
end
|
12
12
|
|
13
13
|
def baz
|
@@ -15,7 +15,7 @@ describe "Throttler" do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
%w{
|
18
|
+
%w{throttler foo-prime}.each do |file|
|
19
19
|
FileUtils.rm "/tmp/.#{file}", :force => true
|
20
20
|
end
|
21
21
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,7 +6,10 @@ module Throttler
|
|
6
6
|
describe Timer do
|
7
7
|
before do
|
8
8
|
FileUtils.rm "/tmp/.foo", :force => true
|
9
|
-
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:timer) do
|
12
|
+
Timer.new("foo")
|
10
13
|
end
|
11
14
|
|
12
15
|
it "creates a file" do
|
@@ -15,8 +18,10 @@ module Throttler
|
|
15
18
|
|
16
19
|
context "#lock" do
|
17
20
|
it "locks the file" do
|
18
|
-
|
19
|
-
File.open("/tmp/.foo")
|
21
|
+
timer.lock
|
22
|
+
File.open("/tmp/.foo") do |f|
|
23
|
+
f.flock(File::LOCK_EX | File::LOCK_NB).should be_false
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
@@ -24,32 +29,36 @@ module Throttler
|
|
24
29
|
it "gets the timestamp" do
|
25
30
|
now = Time.now.to_f
|
26
31
|
File.open("/tmp/.foo", "w") { |f| f.write(now) }
|
27
|
-
|
32
|
+
timer.timestamp.should be_within(0.1).of(now)
|
28
33
|
end
|
29
34
|
|
30
35
|
it "returns 0.0 when file is first created" do
|
31
|
-
|
36
|
+
timer.timestamp.should eql(0.0)
|
32
37
|
end
|
33
38
|
end
|
34
|
-
|
39
|
+
|
35
40
|
context "#timestamp=" do
|
36
41
|
it "sets the timestamp" do
|
37
42
|
now = Time.now.to_f
|
38
|
-
|
43
|
+
timer.timestamp= now
|
39
44
|
|
40
45
|
# We need to close the file first
|
41
|
-
|
46
|
+
timer.instance_variable_get(:@timer).close
|
42
47
|
|
43
|
-
File.open("/tmp/.foo")
|
48
|
+
File.open("/tmp/.foo") do |f|
|
49
|
+
f.gets.to_f.should be_within(0.1).of(now)
|
50
|
+
end
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
47
54
|
context "#unlock" do
|
48
55
|
it "unlocks the file" do
|
49
|
-
|
50
|
-
|
56
|
+
timer.lock
|
57
|
+
timer.unlock
|
51
58
|
|
52
|
-
File.open("/tmp/.foo")
|
59
|
+
File.open("/tmp/.foo") do |f|
|
60
|
+
f.flock(File::LOCK_EX | File::LOCK_NB).should_not be_false
|
61
|
+
end
|
53
62
|
end
|
54
63
|
end
|
55
64
|
end
|
data/spec/unit/throttler_spec.rb
CHANGED
@@ -6,30 +6,39 @@ describe Throttler do
|
|
6
6
|
before do
|
7
7
|
class Foo
|
8
8
|
include Throttler
|
9
|
-
|
10
|
-
def bar
|
11
|
-
throttle("foo"){ raise }
|
12
|
-
end
|
13
9
|
end
|
14
10
|
|
15
|
-
FileUtils.rm "/tmp/.
|
11
|
+
FileUtils.rm "/tmp/.throttler", :force => true
|
12
|
+
end
|
16
13
|
|
17
|
-
|
14
|
+
let!(:foo) do
|
15
|
+
Foo.new
|
18
16
|
end
|
19
17
|
|
20
|
-
|
21
|
-
it "removes lock
|
22
|
-
|
18
|
+
describe "#throttle" do
|
19
|
+
it "removes a lock when an exception is raised" do
|
20
|
+
expect do
|
21
|
+
foo.throttle { raise }
|
22
|
+
end.to raise_error
|
23
23
|
|
24
|
-
File.open("/tmp/.
|
24
|
+
File.open("/tmp/.throttler") do |f|
|
25
|
+
f.flock(File::LOCK_EX | File::LOCK_NB).should_not be_false
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
context "by default" do
|
30
|
+
it "namespaces as `throttler`" do
|
31
|
+
foo.throttle
|
32
|
+
FileTest.exists?("/tmp/.throttler").should be_true
|
30
33
|
end
|
31
34
|
|
32
|
-
|
35
|
+
it "throttles for one second" do
|
36
|
+
time = Benchmark.realtime do
|
37
|
+
2.times{ foo.throttle }
|
38
|
+
end
|
39
|
+
|
40
|
+
time.should be_within(0.1).of(1)
|
41
|
+
end
|
33
42
|
end
|
34
|
-
end
|
43
|
+
end
|
35
44
|
end
|
metadata
CHANGED
@@ -5,33 +5,48 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 2
|
9
|
+
version: 0.2.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Hakan Ensari
|
13
|
-
- Piotr
|
13
|
+
- "Piotr \xC5\x81aszewski"
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-11-29 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
version: 2.1.0
|
34
|
+
type: :development
|
35
|
+
version_requirements: *id001
|
36
|
+
description: A tired, cranky module that throttles parallel-running Ruby scripts on a single machine.
|
37
|
+
email:
|
38
|
+
- code@papercavalier.com
|
24
39
|
executables: []
|
25
40
|
|
26
41
|
extensions: []
|
27
42
|
|
28
|
-
extra_rdoc_files:
|
29
|
-
|
30
|
-
- README.md
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
31
45
|
files:
|
32
|
-
- LICENSE
|
33
|
-
- lib/throttler.rb
|
34
46
|
- lib/throttler/timer.rb
|
47
|
+
- lib/throttler/version.rb
|
48
|
+
- lib/throttler.rb
|
49
|
+
- LICENSE
|
35
50
|
- README.md
|
36
51
|
- spec/fixtures/foo.rb
|
37
52
|
- spec/integration/blocks_with_long_execution_time_spec.rb
|
@@ -47,8 +62,8 @@ homepage: http://github.com/papercavalier/throttler
|
|
47
62
|
licenses: []
|
48
63
|
|
49
64
|
post_install_message:
|
50
|
-
rdoc_options:
|
51
|
-
|
65
|
+
rdoc_options: []
|
66
|
+
|
52
67
|
require_paths:
|
53
68
|
- lib
|
54
69
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -56,7 +71,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
71
|
requirements:
|
57
72
|
- - ">="
|
58
73
|
- !ruby/object:Gem::Version
|
59
|
-
hash: -3148749189245223368
|
60
74
|
segments:
|
61
75
|
- 0
|
62
76
|
version: "0"
|
@@ -70,11 +84,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
84
|
version: "0"
|
71
85
|
requirements: []
|
72
86
|
|
73
|
-
rubyforge_project:
|
87
|
+
rubyforge_project: throttler
|
74
88
|
rubygems_version: 1.3.7
|
75
89
|
signing_key:
|
76
90
|
specification_version: 3
|
77
|
-
summary:
|
91
|
+
summary: A tired, cranky throttler
|
78
92
|
test_files:
|
79
93
|
- spec/fixtures/foo.rb
|
80
94
|
- spec/integration/blocks_with_long_execution_time_spec.rb
|