throttler 0.2.4 → 0.3.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.
- 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
|