hot_tub 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ - ruby-head
8
+ - jruby-head
data/Gemfile CHANGED
@@ -2,10 +2,10 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in http_hot_tub.gemspec
4
4
  gemspec
5
+ gem 'rake'
5
6
 
6
7
  group :development do
7
8
  platform :ruby do
8
- gem 'debugger'
9
9
  gem 'eventmachine'
10
10
  gem 'em-http-request', '~> 1.0', :require => 'em-http'
11
11
  gem 'em-synchrony', '~> 1.0', :require => ['em-synchrony', 'em-synchrony/em-http']
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # HotTub
1
+ # HotTub [![Build Status](https://travis-ci.org/JoshMcKin/hot_tub.png?branch=master)](https://travis-ci.org/JoshMcKin/hot_tub)
2
2
  A simple thread-safe connection pooling gem. Supports [HTTPClient](https://github.com/nahi/httpclient) (default) and
3
3
  [EM-Http-Requests](https://github.com/igrigorik/em-http-request) via [EM-Synchrony](https://github.com/igrigorik/em-synchrony).
4
4
  There are a couple Ruby connection pool libraries out there but HotTub differs from most in that its connections are lazy
5
- (created only when necessary), accomidates libraries that do not clean their dirty connections automatically, and manages unexpected usage increases by opening new connections rather than just blocking or throwings exception (never_block), although never_block can be disabled.
5
+ (created only when necessary), accomidates libraries that do not clean their dirty connections automatically, and manages unexpected usage increases by opening new connections rather than just blocking or throwing exceptions (never_block), although never_block can be disabled.
6
6
 
7
7
  ## Installation
8
8
 
@@ -69,6 +69,7 @@ seperate pools for you various domains based on URI.
69
69
  # Assuming EM is running
70
70
  require 'hot_tub/clients/em_http_request_client'
71
71
  class EMClass
72
+ # Our client block must accept the url argument
72
73
  @@sessons = HotTub::Sessions.new {|url| HotTub::EmHttpRequestClient.new(url,{:connect_timeout => 5}) }
73
74
  def async_post_results(query = {})
74
75
  @@sessons.run("http://somewebservice.com") do |connection|
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ task :default => :spec
5
+ RSpec::Core::RakeTask.new
@@ -12,7 +12,6 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{A simple thread-safe http connection pooling gem.}
13
13
  s.description = %q{A simple thread-safe http connection pooling gem. Http client options include HTTPClient and EM-Http-Request}
14
14
 
15
-
16
15
  s.rubyforge_project = "hot_tub"
17
16
  s.add_runtime_dependency "httpclient"
18
17
  s.add_development_dependency "rspec"
data/lib/hot_tub/pool.rb CHANGED
@@ -55,21 +55,19 @@ module HotTub
55
55
  # end
56
56
  #
57
57
  def initialize(options={},&client_block)
58
+ at_exit { close_all } # close connections at exit
58
59
  @client_block = (block_given? ? client_block : lambda { HTTPClient.new })
59
60
  @options = {
60
61
  :size => 5,
61
- :never_block => true,
62
- :blocking_timeout => 10,
63
- :close => nil,
64
- :clean => nil
62
+ :never_block => true, # Return new client if we run out
63
+ :blocking_timeout => 10, # in seconds
64
+ :close => nil, # => lambda {|clnt| clnt.close}
65
+ :clean => nil # => lambda {|clnt| clnt.clean}
65
66
  }.merge(options)
66
67
  @pool = []
67
68
  @current_size = 0
68
69
  @clients = []
69
70
  @mutex = (HotTub.em? ? EM::Synchrony::Thread::Mutex.new : Mutex.new)
70
- @blocking_timeout = @options[:blocking_timeout]
71
- @never_block = @options[:never_block]
72
- @size = @options[:size]
73
71
  end
74
72
 
75
73
  # Hand off to client.run
@@ -104,7 +102,7 @@ module HotTub
104
102
  # Returns an instance of the client for this pool.
105
103
  def client
106
104
  clnt = nil
107
- alarm = (Time.now + @blocking_timeout)
105
+ alarm = (Time.now + @options[:blocking_timeout])
108
106
  # block until we get an available client or raise Timeout::Error
109
107
  while clnt.nil?
110
108
  raise_alarm if alarm <= Time.now
@@ -123,7 +121,6 @@ module HotTub
123
121
  end
124
122
  end
125
123
 
126
-
127
124
  # Attempts to close the provided client, checking the options first for a close block
128
125
  # then checking the known clients
129
126
  def close_client(clnt)
@@ -142,7 +139,7 @@ module HotTub
142
139
  # Safely add client back to pool
143
140
  def push(clnt)
144
141
  @mutex.synchronize do
145
- if @pool.length < @size
142
+ if @pool.length < @options[:size]
146
143
  @pool << clnt
147
144
  else
148
145
  @clients.delete(clnt)
@@ -157,7 +154,7 @@ module HotTub
157
154
  @mutex.synchronize do
158
155
  add if add?
159
156
  clnt = @pool.pop
160
- if (clnt.nil? && @never_block)
157
+ if (clnt.nil? && @options[:never_block])
161
158
  HotTub.logger.info "Adding never_block client for #{@client.class.name}."
162
159
  clnt = new_client
163
160
  end
@@ -175,7 +172,7 @@ module HotTub
175
172
  # Only want to add a client if the pool is empty in keeping with
176
173
  # a lazy model.
177
174
  def add?
178
- (@pool.length == 0 && @current_size <= @size)
175
+ (@pool.length == 0 && @current_size <= @options[:size])
179
176
  end
180
177
 
181
178
  def add
@@ -49,15 +49,17 @@ module HotTub
49
49
  # Synchronize access to our key hash
50
50
  # expects a url string or URI
51
51
  def sessions(url)
52
+ if url.is_a?(String)
53
+ uri = URI(url)
54
+ elsif url.is_a?(URI)
55
+ uri = url
56
+ else
57
+ raise ArgumentError, "you must pass a string or a URI object"
58
+ end
59
+ key = "#{uri.scheme}-#{uri.host}"
60
+ return @sessions[key] if @sessions[key]
52
61
  @mutex.synchronize do
53
- if url.is_a?(String)
54
- uri = URI(url)
55
- elsif url.is_a?(URI)
56
- uri = url
57
- else
58
- raise ArgumentError, "you must pass a string or a URI object"
59
- end
60
- @sessions["#{uri.scheme}-#{uri.host}"] ||= HotTub::Pool.new(@options) { @client_block.call(url) }
62
+ @sessions[key] ||= HotTub::Pool.new(@options) { @client_block.call(url) }
61
63
  end
62
64
  end
63
65
 
@@ -1,3 +1,3 @@
1
1
  module HotTub
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/spec/pool_spec.rb CHANGED
@@ -11,11 +11,11 @@ describe HotTub::Pool do
11
11
  end
12
12
 
13
13
  it "should have :size of 5" do
14
- @pool.instance_variable_get(:@size).should eql(5)
14
+ @pool.instance_variable_get(:@options)[:size].should eql(5)
15
15
  end
16
16
 
17
17
  it "should have :blocking_timeout of 0.5" do
18
- @pool.instance_variable_get(:@blocking_timeout).should eql(10)
18
+ @pool.instance_variable_get(:@options)[:blocking_timeout].should eql(10)
19
19
  end
20
20
 
21
21
  it "should have default :client" do
@@ -23,7 +23,7 @@ describe HotTub::Pool do
23
23
  end
24
24
 
25
25
  it "should be true" do
26
- @pool.instance_variable_get(:@never_block).should be_true
26
+ @pool.instance_variable_get(:@options)[:never_block].should be_true
27
27
  end
28
28
  end
29
29
 
@@ -33,11 +33,11 @@ describe HotTub::Pool do
33
33
  end
34
34
 
35
35
  it "should have :size of 5" do
36
- @pool.instance_variable_get(:@size).should eql(10)
36
+ @pool.instance_variable_get(:@options)[:size].should eql(10)
37
37
  end
38
38
 
39
39
  it "should have :blocking_timeout of 0.5" do
40
- @pool.instance_variable_get(:@blocking_timeout).should eql(1.0)
40
+ @pool.instance_variable_get(:@options)[:blocking_timeout].should eql(1.0)
41
41
  end
42
42
 
43
43
  it "should have defult :client" do
@@ -45,7 +45,7 @@ describe HotTub::Pool do
45
45
  end
46
46
 
47
47
  it "should be true" do
48
- @pool.instance_variable_get(:@never_block).should be_false
48
+ @pool.instance_variable_get(:@options)[:never_block].should be_false
49
49
  end
50
50
  end
51
51
 
@@ -116,8 +116,7 @@ describe HotTub::Pool do
116
116
 
117
117
  describe '#client' do
118
118
  it "should raise HotTub::BlockingTimeout if an available is not found in time"do
119
- @pool.instance_variable_set(:@never_block,false)
120
- @pool.instance_variable_set(:@blocking_timeout,0.1)
119
+ @pool.instance_variable_set(:@options, {:never_block => false, :blocking_timeout => 0.1})
121
120
  @pool.stub(:pop).and_return(nil)
122
121
  lambda { puts @pool.send(:client) }.should raise_error(HotTub::BlockingTimeout)
123
122
  end
@@ -135,7 +134,7 @@ describe HotTub::Pool do
135
134
  end
136
135
 
137
136
  it "should be false pool has reached pool_size" do
138
- @pool.instance_variable_set(:@pool_data,{:current_size => 5})
137
+ @pool.instance_variable_set(:@options,{:size => 5})
139
138
  @pool.instance_variable_set(:@pool,["connection","connection","connection","connection","connection"])
140
139
  @pool.send(:add?).should be_false
141
140
  end
data/spec/session_spec.rb CHANGED
@@ -94,4 +94,30 @@ describe HotTub::Session do
94
94
  status.should eql(200)
95
95
  end
96
96
  end
97
+
98
+ context 'thread safety' do
99
+ it "should work" do
100
+ url = "https://www.google.com/"
101
+ url2 = "https://www.yahoo.com/"
102
+ session = HotTub::Session.new({:size => 20}) { |a_url| HTTPClient.new}
103
+ failed = false
104
+ lambda {
105
+ threads = []
106
+ 20.times.each do
107
+ threads << Thread.new do
108
+ session.run(url){|connection| failed = true unless connection.head(url).status == 200}
109
+ session.run(url2){|connection| failed = true unless connection.head(url).status == 200}
110
+ end
111
+ end
112
+ sleep(0.01)
113
+ threads.each do |t|
114
+ t.join
115
+ end
116
+ }.should_not raise_error
117
+ session.instance_variable_get(:@sessions).keys.length.should eql(2) # make sure work got done
118
+ session.instance_variable_get(:@sessions).values.first.instance_variable_get(:@pool).length.should eql(20) # make sure work got done
119
+ session.instance_variable_get(:@sessions).values.last.instance_variable_get(:@pool).length.should eql(20) # make sure work got done
120
+ failed.should be_false # Make sure our requests woked
121
+ end
122
+ end
97
123
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot_tub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-31 00:00:00.000000000 Z
12
+ date: 2013-04-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httpclient
@@ -53,11 +53,12 @@ extra_rdoc_files: []
53
53
  files:
54
54
  - .gitignore
55
55
  - .rspec
56
+ - .travis.yml
56
57
  - Gemfile
57
58
  - LICENSE.txt
58
59
  - README.md
59
60
  - Rakefile
60
- - http_hot_tub.gemspec
61
+ - hot_tub.gemspec
61
62
  - lib/hot_tub.rb
62
63
  - lib/hot_tub/pool.rb
63
64
  - lib/hot_tub/session.rb
@@ -78,12 +79,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
78
79
  - - ! '>='
79
80
  - !ruby/object:Gem::Version
80
81
  version: '0'
82
+ segments:
83
+ - 0
84
+ hash: 518626986870371684
81
85
  required_rubygems_version: !ruby/object:Gem::Requirement
82
86
  none: false
83
87
  requirements:
84
88
  - - ! '>='
85
89
  - !ruby/object:Gem::Version
86
90
  version: '0'
91
+ segments:
92
+ - 0
93
+ hash: 518626986870371684
87
94
  requirements: []
88
95
  rubyforge_project: hot_tub
89
96
  rubygems_version: 1.8.25