throttler 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +16 -0
- data/LICENSE +5 -5
- data/README.md +29 -15
- data/Rakefile +9 -0
- data/lib/throttler/throttle.rb +48 -0
- data/lib/throttler/version.rb +2 -2
- data/lib/throttler.rb +18 -11
- data/test/throttler_test.rb +20 -0
- data/throttler.gemspec +22 -0
- metadata +47 -78
- data/lib/throttler/timer.rb +0 -27
- data/spec/fixtures/foo.rb +0 -18
- data/spec/integration/blocks_with_long_execution_time_spec.rb +0 -33
- data/spec/integration/fibers_spec.rb +0 -29
- data/spec/integration/loop_spec.rb +0 -27
- data/spec/integration/processes_spec.rb +0 -22
- data/spec/integration/threads_spec.rb +0 -51
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/throttler/timer_spec.rb +0 -65
- data/spec/unit/throttler_spec.rb +0 -44
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
(The MIT License)
|
2
|
-
|
3
|
-
Copyright (c)
|
4
|
-
|
2
|
+
|
3
|
+
Copyright (c) 2012 Hakan Ensari
|
4
|
+
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
6
6
|
a copy of this software and associated documentation files (the
|
7
7
|
'Software'), to deal in the Software without restriction, including
|
@@ -9,10 +9,10 @@ without limitation the rights to use, copy, modify, merge, publish,
|
|
9
9
|
distribute, sublicense, and/or sell copies of the Software, and to
|
10
10
|
permit persons to whom the Software is furnished to do so, subject to
|
11
11
|
the following conditions:
|
12
|
-
|
12
|
+
|
13
13
|
The above copyright notice and this permission notice shall be
|
14
14
|
included in all copies or substantial portions of the Software.
|
15
|
-
|
15
|
+
|
16
16
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
17
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
18
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
data/README.md
CHANGED
@@ -1,26 +1,40 @@
|
|
1
1
|
Throttler
|
2
2
|
=========
|
3
3
|
|
4
|
-
|
4
|
+
[![travis] [1]] [2]
|
5
5
|
|
6
|
-
|
6
|
+
Throttler rate-limits code execution across threads or processes on a server.
|
7
7
|
|
8
|
-
|
9
|
-
-------
|
8
|
+
![Mapplethorpe][3]
|
10
9
|
|
11
|
-
|
10
|
+
Installation
|
11
|
+
------------
|
12
12
|
|
13
|
-
|
13
|
+
```ruby
|
14
|
+
# in your Gemfile
|
15
|
+
gem 'throttler'
|
16
|
+
```
|
14
17
|
|
15
|
-
|
16
|
-
include Throttler
|
18
|
+
Throttler works only on platforms that support file locking.
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
freq = 1.0
|
20
|
+
Usage
|
21
|
+
-----
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
The following background job ensures workers will not scrape a site faster than
|
24
|
+
once every second per IP address.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
class Scrape
|
28
|
+
def self.perform(site, ip_address, *ids)
|
29
|
+
# The block is syntactic sugar.
|
30
|
+
Throttler.limit 1.0, site, ip_address do
|
31
|
+
spider = Spider.new site, ip_address
|
32
|
+
spider.scrape *ids
|
26
33
|
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
[1]: https://secure.travis-ci.org/hakanensari/throttler.png
|
39
|
+
[2]: http://travis-ci.org/hakanensari/throttler
|
40
|
+
[3]: http://f.cl.ly/items/2S343U141D0N3b3h1K09/Mapplethorpe.png
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Throttler
|
2
|
+
class Throttle
|
3
|
+
class << self
|
4
|
+
attr_accessor :tmp_dir
|
5
|
+
end
|
6
|
+
|
7
|
+
@tmp_dir = '/tmp'
|
8
|
+
|
9
|
+
def initialize(namespace)
|
10
|
+
@namespace = namespace
|
11
|
+
@file = File.open(path, File::RDWR|File::CREAT)
|
12
|
+
end
|
13
|
+
|
14
|
+
def lock
|
15
|
+
@file.flock(File::LOCK_EX)
|
16
|
+
end
|
17
|
+
|
18
|
+
def path
|
19
|
+
"#{self.class.tmp_dir}/.lock-#{@namespace}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def hold(wait)
|
23
|
+
sleep [timestamp + wait - now, 0.0].max
|
24
|
+
timestamp!
|
25
|
+
end
|
26
|
+
|
27
|
+
def unlock
|
28
|
+
@file.flock(File::LOCK_UN)
|
29
|
+
@file.close
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def now
|
35
|
+
Time.now.to_f
|
36
|
+
end
|
37
|
+
|
38
|
+
def timestamp
|
39
|
+
@file.rewind
|
40
|
+
@file.gets.to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
def timestamp!
|
44
|
+
@file.rewind
|
45
|
+
@file.write now
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/throttler/version.rb
CHANGED
data/lib/throttler.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
|
-
require
|
1
|
+
require 'throttler/throttle'
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# A tired, cranky module that helps you throttle stuff in parallel-running Ruby
|
6
|
-
# scripts on a single machine. It gets the job done.
|
3
|
+
# Throttler rate-limits code execution.
|
7
4
|
module Throttler
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
# Ensures subsequent code, including any given block, is executed at most per
|
6
|
+
# every `wait` seconds.
|
7
|
+
#
|
8
|
+
# Optionally takes a splat of words to namespace the throttle.
|
9
|
+
def self.limit(wait, *words)
|
10
|
+
words << 'default' if words.empty?
|
11
|
+
namespace = words.join '-'
|
12
|
+
|
13
|
+
begin
|
14
|
+
throttle = Throttle.new namespace
|
15
|
+
throttle.lock
|
16
|
+
throttle.hold wait
|
17
|
+
ensure
|
18
|
+
throttle.unlock
|
19
|
+
end
|
20
|
+
|
14
21
|
yield if block_given?
|
15
22
|
end
|
16
23
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'throttler'
|
4
|
+
|
5
|
+
class Work
|
6
|
+
def self.perform
|
7
|
+
Throttler.limit 0.1
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ThrottlerTest < Test::Unit::TestCase
|
12
|
+
def test_throttling
|
13
|
+
time = Benchmark.realtime do
|
14
|
+
11.times { Process.fork { Work.perform } }
|
15
|
+
Process.waitall
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_equal 1, time.to_i
|
19
|
+
end
|
20
|
+
end
|
data/throttler.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'throttler/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'throttler'
|
7
|
+
s.version = Throttler::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Hakan Ensari', 'Piotr Łaszewski']
|
10
|
+
s.email = ['hakan.ensari@papercavalier.com']
|
11
|
+
s.homepage = 'https://github.com/hakanensari/throttler'
|
12
|
+
s.summary = 'Rate-limits code execution'
|
13
|
+
s.description = 'Throttler rate-limits code execution across threads or processes.'
|
14
|
+
|
15
|
+
s.add_development_dependency 'rake', '~> 0.9.2'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
end
|
22
|
+
|
metadata
CHANGED
@@ -1,101 +1,70 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: throttler
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 4
|
9
|
-
version: 0.2.4
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Hakan Ensari
|
13
|
-
-
|
9
|
+
- Piotr Łaszewski
|
14
10
|
autorequire:
|
15
11
|
bindir: bin
|
16
12
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
name: rspec
|
23
|
-
prerelease: false
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
13
|
+
date: 2012-03-16 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: &70196529042720 !ruby/object:Gem::Requirement
|
25
18
|
none: false
|
26
|
-
requirements:
|
19
|
+
requirements:
|
27
20
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
- 2
|
31
|
-
- 1
|
32
|
-
- 0
|
33
|
-
version: 2.1.0
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.2
|
34
23
|
type: :development
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70196529042720
|
26
|
+
description: Throttler rate-limits code execution across threads or processes.
|
27
|
+
email:
|
28
|
+
- hakan.ensari@papercavalier.com
|
39
29
|
executables: []
|
40
|
-
|
41
30
|
extensions: []
|
42
|
-
|
43
31
|
extra_rdoc_files: []
|
44
|
-
|
45
|
-
|
46
|
-
-
|
47
|
-
-
|
48
|
-
-
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- .travis.yml
|
35
|
+
- Gemfile
|
36
|
+
- Gemfile.lock
|
49
37
|
- LICENSE
|
50
38
|
- README.md
|
51
|
-
-
|
52
|
-
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
-
|
56
|
-
-
|
57
|
-
|
58
|
-
- spec/unit/throttler/timer_spec.rb
|
59
|
-
- spec/unit/throttler_spec.rb
|
60
|
-
has_rdoc: true
|
61
|
-
homepage: http://github.com/papercavalier/throttler
|
39
|
+
- Rakefile
|
40
|
+
- lib/throttler.rb
|
41
|
+
- lib/throttler/throttle.rb
|
42
|
+
- lib/throttler/version.rb
|
43
|
+
- test/throttler_test.rb
|
44
|
+
- throttler.gemspec
|
45
|
+
homepage: https://github.com/hakanensari/throttler
|
62
46
|
licenses: []
|
63
|
-
|
64
47
|
post_install_message:
|
65
48
|
rdoc_options: []
|
66
|
-
|
67
|
-
require_paths:
|
49
|
+
require_paths:
|
68
50
|
- lib
|
69
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
52
|
none: false
|
71
|
-
requirements:
|
72
|
-
- -
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
58
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
- 0
|
84
|
-
version: "0"
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
85
63
|
requirements: []
|
86
|
-
|
87
|
-
|
88
|
-
rubygems_version: 1.3.7
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.11
|
89
66
|
signing_key:
|
90
67
|
specification_version: 3
|
91
|
-
summary:
|
92
|
-
test_files:
|
93
|
-
-
|
94
|
-
- spec/integration/blocks_with_long_execution_time_spec.rb
|
95
|
-
- spec/integration/fibers_spec.rb
|
96
|
-
- spec/integration/loop_spec.rb
|
97
|
-
- spec/integration/processes_spec.rb
|
98
|
-
- spec/integration/threads_spec.rb
|
99
|
-
- spec/spec_helper.rb
|
100
|
-
- spec/unit/throttler/timer_spec.rb
|
101
|
-
- spec/unit/throttler_spec.rb
|
68
|
+
summary: Rate-limits code execution
|
69
|
+
test_files:
|
70
|
+
- test/throttler_test.rb
|
data/lib/throttler/timer.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Throttler #:nodoc:
|
2
|
-
class Timer
|
3
|
-
def initialize(scope)
|
4
|
-
path = "/tmp/.#{scope}"
|
5
|
-
@timer = File.open(path, File::RDWR|File::CREAT)
|
6
|
-
end
|
7
|
-
|
8
|
-
def lock
|
9
|
-
@timer.flock(File::LOCK_EX)
|
10
|
-
end
|
11
|
-
|
12
|
-
def timestamp
|
13
|
-
@timestamp ||= @timer.gets.to_f
|
14
|
-
end
|
15
|
-
|
16
|
-
def timestamp=(time)
|
17
|
-
@timer.rewind
|
18
|
-
@timer.write(time)
|
19
|
-
@timestamp = time
|
20
|
-
end
|
21
|
-
|
22
|
-
def unlock
|
23
|
-
@timer.flock(File::LOCK_UN)
|
24
|
-
@timer.close
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/spec/fixtures/foo.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
$:.push File.expand_path("../../../lib", __FILE__)
|
2
|
-
require "throttler"
|
3
|
-
|
4
|
-
class Foo
|
5
|
-
include Throttler
|
6
|
-
|
7
|
-
def bar
|
8
|
-
throttle("foo", 2.0) { }
|
9
|
-
end
|
10
|
-
|
11
|
-
def control; end
|
12
|
-
end
|
13
|
-
|
14
|
-
if ARGV.size == 0
|
15
|
-
Foo.new.bar
|
16
|
-
else
|
17
|
-
Foo.new.control
|
18
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require "fileutils"
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
describe "Throttler" do
|
5
|
-
before do
|
6
|
-
class Foo
|
7
|
-
include Throttler
|
8
|
-
|
9
|
-
def bar
|
10
|
-
throttle("foo") do
|
11
|
-
yield # so we can count
|
12
|
-
sleep 10
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
FileUtils.rm "/tmp/.foo", :force => true
|
18
|
-
end
|
19
|
-
|
20
|
-
it "throttles threads with long execution times" do
|
21
|
-
count = 0
|
22
|
-
|
23
|
-
threads = 10.times.collect do
|
24
|
-
Thread.new do
|
25
|
-
loop{ Foo.new.bar{ count += 1 } }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
sleep 3.25
|
29
|
-
threads.each { |t| Thread.kill(t) }
|
30
|
-
|
31
|
-
count.should eql 4
|
32
|
-
end
|
33
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require "benchmark"
|
2
|
-
require "fiber"
|
3
|
-
require "fileutils"
|
4
|
-
require "spec_helper"
|
5
|
-
|
6
|
-
describe "Throttler" do
|
7
|
-
before do
|
8
|
-
class Foo
|
9
|
-
include Throttler
|
10
|
-
|
11
|
-
def bar
|
12
|
-
throttle { }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
FileUtils.rm "/tmp/.throttler", :force => true
|
17
|
-
end
|
18
|
-
|
19
|
-
it "throttles fibers" do
|
20
|
-
time = Benchmark.realtime do
|
21
|
-
fib = Fiber.new do
|
22
|
-
loop{ Foo.new.bar; Fiber.yield }
|
23
|
-
end
|
24
|
-
3.times { fib.resume }
|
25
|
-
end
|
26
|
-
|
27
|
-
time.should be_within(0.1).of(2)
|
28
|
-
end
|
29
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require "benchmark"
|
2
|
-
require "fileutils"
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe "Throttler" do
|
6
|
-
before do
|
7
|
-
class Foo
|
8
|
-
include Throttler
|
9
|
-
|
10
|
-
def bar
|
11
|
-
throttle { }
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
FileUtils.rm "/tmp/.throttler", :force => true
|
16
|
-
end
|
17
|
-
|
18
|
-
it "throttles a loop" do
|
19
|
-
time = Benchmark.realtime do
|
20
|
-
3.times do
|
21
|
-
Foo.new.bar
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
time.should be_within(0.1).of(2)
|
26
|
-
end
|
27
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require "benchmark"
|
2
|
-
require "fileutils"
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
|
6
|
-
describe "Throttler" do
|
7
|
-
before do
|
8
|
-
FileUtils.rm "/tmp/.foo", :force => true
|
9
|
-
end
|
10
|
-
|
11
|
-
it "throttles concurrent processes" do
|
12
|
-
startup_time = Benchmark.realtime do
|
13
|
-
`ruby #{File.dirname(__FILE__) + "/../fixtures/foo.rb"} control`
|
14
|
-
end
|
15
|
-
|
16
|
-
time = Benchmark.realtime do
|
17
|
-
4.times{ `ruby #{File.dirname(__FILE__) + "/../fixtures/foo.rb"}` }
|
18
|
-
end
|
19
|
-
|
20
|
-
(time - startup_time).should be_within(0.5).of(6.0)
|
21
|
-
end
|
22
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require "fileutils"
|
2
|
-
require "spec_helper"
|
3
|
-
|
4
|
-
describe "Throttler" do
|
5
|
-
before do
|
6
|
-
class Foo
|
7
|
-
include Throttler
|
8
|
-
|
9
|
-
def bar
|
10
|
-
throttle { }
|
11
|
-
end
|
12
|
-
|
13
|
-
def baz
|
14
|
-
throttle("foo-prime"){ }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
%w{throttler foo-prime}.each do |file|
|
19
|
-
FileUtils.rm "/tmp/.#{file}", :force => true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
it "throttles threads" do
|
24
|
-
count = 0
|
25
|
-
threads = 10.times.collect do
|
26
|
-
Thread.new do
|
27
|
-
loop { Foo.new.bar; count += 1 }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
sleep 3.25
|
31
|
-
threads.each { |t| Thread.kill(t) }
|
32
|
-
|
33
|
-
count.should eql 4
|
34
|
-
end
|
35
|
-
|
36
|
-
it "throttles by scope" do
|
37
|
-
count = 0
|
38
|
-
threads = 10.times.collect do
|
39
|
-
Thread.new do
|
40
|
-
loop do
|
41
|
-
Foo.new.send(count % 2 == 0 ? :bar : :baz)
|
42
|
-
count += 1
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
sleep 3.25
|
47
|
-
threads.each { |t| Thread.kill(t) }
|
48
|
-
|
49
|
-
count.should eql 8
|
50
|
-
end
|
51
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "benchmark"
|
3
|
-
require "fileutils"
|
4
|
-
|
5
|
-
module Throttler
|
6
|
-
describe Timer do
|
7
|
-
before do
|
8
|
-
FileUtils.rm "/tmp/.foo", :force => true
|
9
|
-
end
|
10
|
-
|
11
|
-
let!(:timer) do
|
12
|
-
Timer.new("foo")
|
13
|
-
end
|
14
|
-
|
15
|
-
it "creates a file" do
|
16
|
-
File.exists?("/tmp/.foo").should be_true
|
17
|
-
end
|
18
|
-
|
19
|
-
context "#lock" do
|
20
|
-
it "locks the file" do
|
21
|
-
timer.lock
|
22
|
-
File.open("/tmp/.foo") do |f|
|
23
|
-
f.flock(File::LOCK_EX | File::LOCK_NB).should be_false
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "#timestamp" do
|
29
|
-
it "gets the timestamp" do
|
30
|
-
now = Time.now.to_f
|
31
|
-
File.open("/tmp/.foo", "w") { |f| f.write(now) }
|
32
|
-
timer.timestamp.should be_within(0.1).of(now)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "returns 0.0 when file is first created" do
|
36
|
-
timer.timestamp.should eql(0.0)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context "#timestamp=" do
|
41
|
-
it "sets the timestamp" do
|
42
|
-
now = Time.now.to_f
|
43
|
-
timer.timestamp= now
|
44
|
-
|
45
|
-
# We need to close the file first
|
46
|
-
timer.instance_variable_get(:@timer).close
|
47
|
-
|
48
|
-
File.open("/tmp/.foo") do |f|
|
49
|
-
f.gets.to_f.should be_within(0.1).of(now)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "#unlock" do
|
55
|
-
it "unlocks the file" do
|
56
|
-
timer.lock
|
57
|
-
timer.unlock
|
58
|
-
|
59
|
-
File.open("/tmp/.foo") do |f|
|
60
|
-
f.flock(File::LOCK_EX | File::LOCK_NB).should_not be_false
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
data/spec/unit/throttler_spec.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
require "benchmark"
|
2
|
-
require "fileutils"
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Throttler do
|
6
|
-
before do
|
7
|
-
class Foo
|
8
|
-
include Throttler
|
9
|
-
end
|
10
|
-
|
11
|
-
FileUtils.rm "/tmp/.throttler", :force => true
|
12
|
-
end
|
13
|
-
|
14
|
-
let!(:foo) do
|
15
|
-
Foo.new
|
16
|
-
end
|
17
|
-
|
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
|
-
|
24
|
-
File.open("/tmp/.throttler") do |f|
|
25
|
-
f.flock(File::LOCK_EX | File::LOCK_NB).should_not be_false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "by default" do
|
30
|
-
it "names scope as `throttler`" do
|
31
|
-
foo.throttle
|
32
|
-
FileTest.exists?("/tmp/.throttler").should be_true
|
33
|
-
end
|
34
|
-
|
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
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|