hot_tub 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,103 +0,0 @@
1
- require 'uri'
2
- module HotTub
3
- class Session
4
- include HotTub::KnownClients
5
- # A HotTub::Session is a synchronized hash used to separate pools/clients by their domain.
6
- # Excon and EmHttpRequest clients are initialized to a specific domain, so we sometimes need a way to
7
- # manage multiple pools like when a process need to connect to various AWS resources. You can use any client
8
- # you choose, but make sure you client is threadsafe.
9
- # Example:
10
- #
11
- # sessions = HotTub::Session.new { |url| Excon.new(url) }
12
- #
13
- # sessions.run("http://wwww.yahoo.com") do |conn|
14
- # p conn.head.status
15
- # end
16
- #
17
- # sessions.run("https://wwww.google.com") do |conn|
18
- # p conn.head.status
19
- # end
20
- #
21
- # Example with Pool:
22
- # You can initialize a HotTub::Pool with each client by passing :with_pool as true and any pool options
23
- # sessions = HotTub::Session.new(:with_pool => true, :size => 12) { EM::HttpRequest.new("http://somewebservice.com") }
24
- #
25
- # sessions.run("http://wwww.yahoo.com") do |conn|
26
- # p conn.head.response_header.status
27
- # end
28
- #
29
- # sessions.run("https://wwww.google.com") do |conn|
30
- # p conn.head.response_header.status
31
- # end
32
- #
33
- #
34
- def initialize(options={},&client_block)
35
- raise ArgumentError, "HotTub::Sessions requre a block on initialization that accepts a single argument" unless block_given?
36
- @options = options || {}
37
- @client_block = client_block
38
- @sessions = Hash.new
39
- @mutex = (em_client? ? EM::Synchrony::Thread::Mutex.new : Mutex.new)
40
- HotTub.hot_at_exit( em_client? ) {close_all}
41
- end
42
-
43
- # Synchronizes initialization of our sessions
44
- # expects a url string or URI
45
- def sessions(url)
46
- key = to_key(url)
47
- return @sessions[key] if @sessions[key]
48
- @mutex.synchronize do
49
- if @options[:with_pool]
50
- @sessions[key] = HotTub::Pool.new(@options) { @client_block.call(url) }
51
- else
52
- @sessions[key] = @client_block.call(url) if @sessions[key].nil?
53
- end
54
- @sessions[key]
55
- end
56
- end
57
-
58
- def run(url,&block)
59
- session = sessions(url)
60
- return session.run(&block) if session.is_a?(HotTub::Pool)
61
- block.call(sessions(url))
62
- end
63
-
64
- # Calls close on all pools/clients in sessions
65
- def close_all
66
- @sessions.each do |key,clnt|
67
- if clnt.is_a?(HotTub::Pool)
68
- clnt.close_all
69
- else
70
- begin
71
- close_client(clnt)
72
- rescue => e
73
- HotTub.logger.error "There was an error close one of your HotTub::Session clients: #{e}"
74
- end
75
- end
76
- @mutex.synchronize do
77
- @sessions[key] = nil
78
- end
79
- end
80
- end
81
-
82
- private
83
-
84
- def em_client?
85
- begin
86
- (HotTub.em_synchrony? && @client_block.call("http://moc").is_a?(EventMachine::HttpConnection))
87
- rescue
88
- false
89
- end
90
- end
91
-
92
- def to_key(url)
93
- if url.is_a?(String)
94
- uri = URI(url)
95
- elsif url.is_a?(URI)
96
- uri = url
97
- else
98
- raise ArgumentError, "you must pass a string or a URI object"
99
- end
100
- "#{uri.scheme}://#{uri.host}:#{uri.port}"
101
- end
102
- end
103
- end
data/spec/session_spec.rb DELETED
@@ -1,213 +0,0 @@
1
- require 'spec_helper'
2
- require 'hot_tub/session'
3
- require 'uri'
4
- require 'time'
5
- unless HotTub.jruby?
6
- require "em-synchrony"
7
- require "em-synchrony/em-http"
8
- end
9
- describe HotTub::Session do
10
-
11
- context 'initialized without a block' do
12
- it "should raise error if block is not supplied" do
13
- lambda {HotTub::Session.new}.should raise_error(ArgumentError)
14
- end
15
- end
16
- context 'initialized with a block' do
17
- before(:each) do
18
- @url = "https://www.somewebsite.com"
19
- @uri = URI(@url)
20
- @sessions = HotTub::Session.new { |url| MocClient.new(url) }
21
- end
22
-
23
- describe '#to_url' do
24
- context "passed URL string" do
25
- it "should return key with URI scheme-domain" do
26
- @sessions.send(:to_key,@url).should eql("#{@uri.scheme}://#{@uri.host}:#{@uri.port}")
27
- end
28
- end
29
-
30
- context "passed URI" do
31
- it "should return key with URI scheme-domain" do
32
- @sessions.send(:to_key,@uri).should eql("#{@uri.scheme}://#{@uri.host}:#{@uri.port}")
33
- end
34
- end
35
-
36
- context "invalid argument" do
37
- it "should raise an ArgumentError" do
38
- lambda { @sessions.send(:to_key, nil) }.should raise_error(ArgumentError)
39
- end
40
- it "should raise URI::InvalidURIError with bad url" do
41
- lambda { @sessions.send(:to_key,"bad url") }.should raise_error(URI::InvalidURIError)
42
- end
43
- end
44
- end
45
-
46
- describe '#sessions' do
47
- context 'HotTub::Pool as client' do
48
- it "should add a new client for the url" do
49
- with_pool_options = HotTub::Session.new { |url| HotTub::Pool.new(:size => 13) { MocClient.new(url) } }
50
- with_pool_options.sessions(@url)
51
- sessions = with_pool_options.instance_variable_get(:@sessions)
52
- sessions.length.should eql(1)
53
- sessions.first[1].should be_a(HotTub::Pool)
54
- end
55
- end
56
-
57
- context 'other clients' do
58
- it "should add a new client for the url" do
59
- no_pool = HotTub::Session.new { |url| Excon.new(url) }
60
- no_pool.sessions(@url)
61
- sessions = no_pool.instance_variable_get(:@sessions)
62
- sessions.length.should eql(1)
63
- sessions.first[1].should be_a(Excon::Connection)
64
- end
65
- end
66
-
67
- context "passed URL string" do
68
- it "should set key with URI scheme-domain" do
69
- @sessions.sessions(@url)
70
- sessions = @sessions.instance_variable_get(:@sessions)
71
- sessions["#{@uri.scheme}://#{@uri.host}:#{@uri.port}"].should be_a(MocClient)
72
- end
73
- end
74
- context "passed URI" do
75
- it "should set key with URI scheme-domain" do
76
- @sessions.sessions(@uri)
77
- sessions = @sessions.instance_variable_get(:@sessions)
78
- sessions["#{@uri.scheme}://#{@uri.host}:#{@uri.port}"].should be_a(MocClient)
79
- end
80
- end
81
-
82
- context "with_pool" do
83
- it "should initialize a new HotTub::Pool" do
84
- session_with_pool = HotTub::Session.new({:with_pool => true}) { |url| MocClient.new(url) }
85
- pool = session_with_pool.sessions(@url)
86
- pool.should be_a(HotTub::Pool)
87
- end
88
- end
89
- end
90
-
91
- describe '#run' do
92
- it "should work" do
93
- url = HotTub::Server.url
94
- sessions = HotTub::Session.new { |url| Excon.new(url) }
95
- result = nil
96
- sessions.run(url) do |conn|
97
- result = conn.get.status
98
- end
99
- result.should eql(200)
100
- end
101
-
102
- context "with_pool" do
103
- it "should pass run to pool" do
104
- url = HotTub::Server.url
105
- session_with_pool = HotTub::Session.new({:with_pool => true}) { |url| Excon.new(url) }
106
- result = nil
107
- session_with_pool.run(url) do |conn|
108
- result = conn.get.status
109
- end
110
- result.should eql(200)
111
- end
112
- end
113
- end
114
-
115
- context 'threads' do
116
- it "should work" do
117
- url = HotTub::Server.url
118
- url2 = HotTub::Server2.url
119
- session = HotTub::Session.new(:with_pool => true) { |url| Excon.new(url)}
120
- failed = false
121
- start_time = Time.now
122
- stop_time = nil
123
- threads = []
124
- lambda {
125
- 10.times.each do
126
- threads << Thread.new do
127
- # MocClient is not thread safe so lets initialize a new instance for each
128
- session.run(url) { |clnt| Thread.current[:result] = clnt.get.status }
129
- session.run(url2) { |clnt| Thread.current[:result] = clnt.get.status }
130
- end
131
- end
132
- threads.each do |t|
133
- t.join
134
- end
135
- stop_time = Time.now
136
- }.should_not raise_error # make sure we're thread safe
137
- # Some extra checks just to make sure...
138
- results = threads.collect{ |t| t[:result]}
139
- results.length.should eql(10) # make sure all threads are present
140
- results.uniq.should eql([results.first]) # make sure we got the same results
141
- ((stop_time.to_i - start_time.to_i) < (results.length * MocClient.sleep_time)).should be_true # make sure IO is running parallel
142
- session.instance_variable_get(:@sessions).keys.length.should eql(2) # make sure sessions were created
143
- end
144
- end
145
-
146
- unless HotTub.jruby?
147
-
148
- describe "em_client?" do
149
-
150
- context 'EM::HttpRequest as client' do
151
- before(:each) do
152
- @session = HotTub::Session.new {|url| EM::HttpRequest.new(url)}
153
- end
154
- context "EM::Synchrony is present" do
155
- it "should be true" do
156
- HotTub.stub(:em_synchrony?).and_return(true)
157
- @session.send(:em_client?).should be_true
158
- end
159
- end
160
- context "EM::Synchrony is not present" do
161
- it "should be false" do
162
- HotTub.stub(:em_synchrony?).and_return(false)
163
- @session.send(:em_client?).should be_false
164
- end
165
- end
166
- end
167
- context 'client is not EM::HttpRequest' do
168
- it "should be false" do
169
- session = HotTub::Session.new {|url| MocClient.new}
170
- session.send(:em_client?).should be_false
171
- end
172
- end
173
- end
174
-
175
- context 'fibers' do
176
- it "should work" do
177
- EM.synchrony do
178
- sessions = HotTub::Session.new(:with_pool => true) {|url| EM::HttpRequest.new(url)}
179
- failed = false
180
- fibers = []
181
- lambda {
182
- 10.times.each do
183
- fibers << Fiber.new do
184
- sessions.run(@url) {|connection|
185
- s = connection.head(:keepalive => true).response_header.status
186
- failed = true unless s == 200}
187
- end
188
- end
189
- fibers.each do |f|
190
- f.resume
191
- end
192
- loop do
193
- done = true
194
- fibers.each do |f|
195
- done = false if f.alive?
196
- end
197
- if done
198
- break
199
- else
200
- EM::Synchrony.sleep(0.01)
201
- end
202
- end
203
- }.should_not raise_error
204
- sessions.instance_variable_get(:@sessions).keys.length.should eql(1)
205
- (sessions.sessions(@url).instance_variable_get(:@pool).length >= 5).should be_true #make sure work got done
206
- failed.should be_false # Make sure our requests worked
207
- EM.stop
208
- end
209
- end
210
- end
211
- end
212
- end
213
- end