throttler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009 Paper Cavalier
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ Throttler
2
+ =========
3
+
4
+ ![Mapplethorpe](http://github.com/papercavalier/throttler/raw/master/mapplethorpe_chains.jpg)
5
+
6
+ Throttle concurrency.
7
+
8
+ include Throttler
9
+
10
+ 100.times do
11
+ Thread.new do
12
+ loop do
13
+ throttle("foo") do
14
+ count += 1
15
+ end
16
+ end
17
+ end
18
+ end
19
+ sleep 2.2
20
+
21
+ count.should eql 3
22
+
23
+ Use case
24
+ --------
25
+
26
+ Imagine multiple workers hitting the Amazon API on the same IP address. You gotta do something about it.
data/lib/throttler.rb ADDED
@@ -0,0 +1,23 @@
1
+ # Throttler
2
+ module Throttler
3
+ require "fileutils"
4
+
5
+ def throttle(name, interval=1.0)
6
+ path = "/tmp/.#{name}"
7
+
8
+ FileUtils.touch path unless File.exist? path
9
+
10
+ file = File.open(path, "r+")
11
+ file.flock(File::LOCK_EX)
12
+
13
+ last = file.gets.to_f || Time.now.to_f - interval
14
+ sleep [last + interval - Time.now.to_f, 0.0].max
15
+
16
+ yield if block_given?
17
+
18
+ file.rewind
19
+ file.write(Time.now.to_f)
20
+ file.flock(File::LOCK_UN)
21
+ file.close
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../../lib/throttler"
2
+
3
+ class Foo
4
+ include Throttler
5
+
6
+ def bar
7
+ throttle("bar") { noop }
8
+ end
9
+
10
+ def noop; end
11
+ end
12
+
13
+ Foo.new.bar
@@ -0,0 +1,4 @@
1
+ require "rspec"
2
+ require File.expand_path("../../lib/throttler", __FILE__)
3
+
4
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each{ |f| require f }
@@ -0,0 +1,78 @@
1
+ require "benchmark"
2
+ require "fileutils"
3
+ require "spec_helper"
4
+
5
+ class Foo
6
+ include Throttler
7
+
8
+ def bar
9
+ throttle("bar"){ noop }
10
+ end
11
+
12
+ def baz
13
+ throttle("baz"){ noop }
14
+ end
15
+
16
+ def noop; end
17
+ end
18
+
19
+ describe Throttler do
20
+ before do
21
+ FileUtils.rm "/tmp/.bar", :force => true
22
+ FileUtils.rm "/tmp/.baz", :force => true
23
+ end
24
+
25
+ it "throttles a loop" do
26
+ time = Benchmark.realtime do
27
+ 3.times do
28
+ Foo.new.bar
29
+ end
30
+ end
31
+
32
+ time.should be_close 2, 0.01
33
+ end
34
+
35
+ it "throttles threads" do
36
+ count = 0
37
+ threads = 10.times.collect do
38
+ Thread.new do
39
+ foo = Foo.new
40
+ loop do
41
+ foo.bar
42
+ count += 1
43
+ end
44
+ end
45
+ end
46
+ sleep 2.2
47
+ threads.each { |t| Thread.kill(t) }
48
+
49
+ count.should eql 3
50
+ end
51
+
52
+ it "throttles concurrently-running scripts" do
53
+ time = Benchmark.realtime do
54
+ 3.times do
55
+ `ruby #{File.dirname(__FILE__) + "/fixtures/foo.rb"}`
56
+ end
57
+ end
58
+
59
+ time.should be > 2.0
60
+ end
61
+
62
+ it "throttles by name" do
63
+ count = 0
64
+ threads = 10.times.collect do
65
+ Thread.new do
66
+ foo = Foo.new
67
+ loop do
68
+ count % 2 == 0 ? foo.bar : foo.baz
69
+ count += 1
70
+ end
71
+ end
72
+ end
73
+ sleep 2.2
74
+ threads.each { |t| Thread.kill(t) }
75
+
76
+ count.should eql 6
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: throttler
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Hakan Ensari
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-23 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Throttles the frequency at which concurrently-running instances of a Ruby block are executed.
23
+ email: code@papercavalier.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - LICENSE
30
+ - README.md
31
+ files:
32
+ - LICENSE
33
+ - lib/throttler.rb
34
+ - README.md
35
+ - spec/fixtures/foo.rb
36
+ - spec/spec_helper.rb
37
+ - spec/throttler_spec.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/papercavalier/throttler
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ hash: 3
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.7
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Throttles the frequency at which concurrently-running instances of a Ruby block are executed.
72
+ test_files:
73
+ - spec/fixtures/foo.rb
74
+ - spec/spec_helper.rb
75
+ - spec/throttler_spec.rb