em-pg-client 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +4 -3
- data/HISTORY.md +11 -0
- data/README.md +2 -1
- data/Rakefile +30 -1
- data/benchmarks/single_row_mode.rb +8 -8
- data/lib/pg/em-version.rb +1 -1
- data/lib/pg/em.rb +137 -40
- data/lib/pg/em/client/connect_watcher.rb +32 -2
- data/lib/pg/em/connection_pool.rb +41 -9
- data/spec/em_client_autoreconnect.rb +45 -0
- data/spec/em_client_on_connect.rb +171 -0
- data/spec/em_connection_pool.rb +198 -0
- data/spec/em_synchrony_client_autoreconnect.rb +48 -0
- data/spec/pg_em_client_options.rb +39 -1
- data/spec/pg_em_connection_pool.rb +25 -1
- metadata +17 -27
@@ -78,14 +78,30 @@ module PG
|
|
78
78
|
# - +:lazy+ = false - should lazy allocate first connection
|
79
79
|
# - +:connection_class+ = {PG::EM::Client}
|
80
80
|
#
|
81
|
+
# For convenience the given block will be set as the +on_connect+ option.
|
82
|
+
#
|
83
|
+
# @yieldparam pg [Client] connected client instance on each newly
|
84
|
+
# created connection
|
85
|
+
# @yieldparam is_async [Boolean] always +true+ in a connection pool
|
86
|
+
# context
|
87
|
+
# @yieldparam is_reset [Boolean] always +false+ unless
|
88
|
+
# +async_autoreconnect+ options is +true+ and
|
89
|
+
# was actually re-connecting
|
90
|
+
#
|
81
91
|
# @raise [PG::Error]
|
82
92
|
# @raise [ArgumentError]
|
83
|
-
|
93
|
+
# @see Client#on_connect
|
94
|
+
def initialize(options = {}, &on_connect)
|
84
95
|
@available = []
|
85
96
|
@pending = []
|
86
97
|
@allocated = {}
|
98
|
+
@max_size = DEFAULT_SIZE
|
87
99
|
@connection_class = Client
|
88
100
|
|
101
|
+
if block_given?
|
102
|
+
options = {on_connect: on_connect}.merge(options)
|
103
|
+
end
|
104
|
+
|
89
105
|
lazy = false
|
90
106
|
@options = options.reject do |key, value|
|
91
107
|
case key.to_sym
|
@@ -101,9 +117,7 @@ module PG
|
|
101
117
|
end
|
102
118
|
end
|
103
119
|
|
104
|
-
@max_size
|
105
|
-
|
106
|
-
raise ArgumentError, "#{self.class}.new: pool size must be > 1" if @max_size < 1
|
120
|
+
raise ArgumentError, "#{self.class}.new: pool size must be >= 1" if @max_size < 1
|
107
121
|
|
108
122
|
# allocate first connection, unless we are lazy
|
109
123
|
hold unless lazy
|
@@ -179,6 +193,10 @@ module PG
|
|
179
193
|
# @return [Boolean] asynchronous auto re-connect status
|
180
194
|
# Set {Client#async_autoreconnect} on all present and future connections
|
181
195
|
# in this pool or read value from options
|
196
|
+
# @!attribute [rw] on_connect
|
197
|
+
# @return [Proc<Client,is_async,is_reset>] connect hook
|
198
|
+
# Set {Client#on_connect} on all present and future connections
|
199
|
+
# in this pool or read value from options
|
182
200
|
# @!attribute [rw] on_autoreconnect
|
183
201
|
# @return [Proc<Client, Error>] auto re-connect hook
|
184
202
|
# Set {Client#on_autoreconnect} on all present and future connections
|
@@ -186,6 +204,7 @@ module PG
|
|
186
204
|
%w[connect_timeout
|
187
205
|
query_timeout
|
188
206
|
async_autoreconnect
|
207
|
+
on_connect
|
189
208
|
on_autoreconnect].each do |name|
|
190
209
|
class_eval <<-EOD, __FILE__, __LINE__
|
191
210
|
def #{name}=(value)
|
@@ -194,11 +213,24 @@ module PG
|
|
194
213
|
@available.each(&b)
|
195
214
|
@allocated.each_value(&b)
|
196
215
|
end
|
197
|
-
|
198
|
-
def #{name}
|
199
|
-
@options[:#{name}] || @options['#{name}']
|
200
|
-
end
|
201
216
|
EOD
|
217
|
+
if name.start_with?('on_')
|
218
|
+
class_eval <<-EOD, __FILE__, __LINE__
|
219
|
+
def #{name}(&hook)
|
220
|
+
if block_given?
|
221
|
+
self.#{name} = hook
|
222
|
+
else
|
223
|
+
@options[:#{name}] || @options['#{name}']
|
224
|
+
end
|
225
|
+
end
|
226
|
+
EOD
|
227
|
+
else
|
228
|
+
class_eval <<-EOD, __FILE__, __LINE__
|
229
|
+
def #{name}
|
230
|
+
@options[:#{name}] || @options['#{name}']
|
231
|
+
end
|
232
|
+
EOD
|
233
|
+
end
|
202
234
|
DeferredOptions.class_eval <<-EOD, __FILE__, __LINE__
|
203
235
|
def #{name}=(value)
|
204
236
|
self[:#{name}=] = value
|
@@ -327,7 +359,7 @@ module PG
|
|
327
359
|
begin
|
328
360
|
id = fiber.object_id
|
329
361
|
# mark allocated pool for proper #size value
|
330
|
-
# the
|
362
|
+
# the connection is made asynchronously
|
331
363
|
@allocated[id] = opts = DeferredOptions.new
|
332
364
|
conn = @connection_class.new(@options)
|
333
365
|
ensure
|
@@ -285,6 +285,51 @@ describe 'pg-em autoreconnect with on_autoreconnect' do
|
|
285
285
|
end
|
286
286
|
end
|
287
287
|
|
288
|
+
it "should execute on_connect before on_autoreconnect after server restart" do
|
289
|
+
@client.on_connect.should be_nil
|
290
|
+
run_on_connect = false
|
291
|
+
@client.on_connect = proc do |client, is_async, is_reset|
|
292
|
+
client.should be_an_instance_of PG::EM::Client
|
293
|
+
is_async.should be_true
|
294
|
+
is_reset.should be_true
|
295
|
+
client.query_defer('SELECT pg_database_size(current_database());').callback {
|
296
|
+
run_on_connect = true
|
297
|
+
}
|
298
|
+
end
|
299
|
+
@client.on_autoreconnect = proc do |client, ex|
|
300
|
+
run_on_connect.should be_true
|
301
|
+
@on_autoreconnect.call(client, ex)
|
302
|
+
end
|
303
|
+
system($pgserver_cmd_stop).should be_true
|
304
|
+
system($pgserver_cmd_start).should be_true
|
305
|
+
@tested_proc.call
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should skip on_autoreconnect when on_connect failed after server restart" do
|
309
|
+
run_on_connect = false
|
310
|
+
run_on_autoreconnect = false
|
311
|
+
@client.on_connect = proc do |client, is_async, is_reset|
|
312
|
+
client.should be_an_instance_of PG::EM::Client
|
313
|
+
is_async.should be_true
|
314
|
+
is_reset.should be_true
|
315
|
+
client.query_defer('SELLECT 1;').errback {
|
316
|
+
run_on_connect = true
|
317
|
+
}
|
318
|
+
end
|
319
|
+
@client.on_autoreconnect = proc do |client, ex|
|
320
|
+
run_on_autoreconnect = true
|
321
|
+
end
|
322
|
+
system($pgserver_cmd_stop).should be_true
|
323
|
+
system($pgserver_cmd_start).should be_true
|
324
|
+
@client.exec_prepared_defer('get_db_size') do |ex|
|
325
|
+
ex.should be_an_instance_of PG::SyntaxError
|
326
|
+
@client.status.should be PG::CONNECTION_OK
|
327
|
+
run_on_connect.should be_true
|
328
|
+
run_on_autoreconnect.should be_false
|
329
|
+
EM.stop
|
330
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
331
|
+
end
|
332
|
+
|
288
333
|
before(:all) do
|
289
334
|
@tested_proc = proc do
|
290
335
|
@client.exec_prepared_defer('get_db_size') do |result|
|
@@ -0,0 +1,171 @@
|
|
1
|
+
$:.unshift "lib"
|
2
|
+
gem 'eventmachine', '~> 1.0.0'
|
3
|
+
gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'em-synchrony'
|
6
|
+
require 'pg/em'
|
7
|
+
module PGSpecMacros
|
8
|
+
def test_blocking
|
9
|
+
client = subject.new(options)
|
10
|
+
client.should be_an_instance_of subject
|
11
|
+
client.on_connect.should be on_connect
|
12
|
+
client.exec_prepared(query_name) do |result|
|
13
|
+
result.should be_an_instance_of PG::Result
|
14
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
15
|
+
end
|
16
|
+
client.reset
|
17
|
+
client.exec_prepared(query_name) do |result|
|
18
|
+
result.should be_an_instance_of PG::Result
|
19
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_blocking_error
|
24
|
+
expect do
|
25
|
+
subject.new(options)
|
26
|
+
end.to raise_error(on_connect_exception)
|
27
|
+
client = subject.new
|
28
|
+
client.should be_an_instance_of subject
|
29
|
+
client.on_connect = on_connect
|
30
|
+
expect do
|
31
|
+
client.reset
|
32
|
+
end.to raise_error(on_connect_exception)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
RSpec.configure do |config|
|
37
|
+
config.include(PGSpecMacros)
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_context 'test on_connect' do
|
41
|
+
|
42
|
+
it "should invoke on_connect after deferrable connect and reset" do
|
43
|
+
EM.run do
|
44
|
+
subject.connect_defer(options) do |client|
|
45
|
+
client.should be_an_instance_of subject
|
46
|
+
client.on_connect.should be on_connect
|
47
|
+
client.exec_prepared_defer(query_name) do |result|
|
48
|
+
result.should be_an_instance_of PG::Result
|
49
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
50
|
+
client.reset_defer do |client|
|
51
|
+
client.should be_an_instance_of subject
|
52
|
+
client.exec_prepared_defer(query_name) do |result|
|
53
|
+
result.should be_an_instance_of PG::Result
|
54
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
55
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
56
|
+
EM.stop
|
57
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
58
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
59
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should invoke on_connect after synchrony connect and reset" do
|
64
|
+
EM.synchrony do
|
65
|
+
test_blocking
|
66
|
+
EM.stop
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
shared_context 'test on_connect error' do
|
73
|
+
|
74
|
+
it "should fail on_connect with exception after deferrable connect and reset" do
|
75
|
+
EM.run do
|
76
|
+
subject.connect_defer(options) do |ex|
|
77
|
+
ex.should be_an_instance_of on_connect_exception
|
78
|
+
subject.connect_defer do |client|
|
79
|
+
client.should be_an_instance_of subject
|
80
|
+
client.on_connect = on_connect
|
81
|
+
client.reset_defer do |ex|
|
82
|
+
ex.should be_an_instance_of on_connect_exception
|
83
|
+
EM.stop
|
84
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
85
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
86
|
+
end.should be_a_kind_of ::EM::DefaultDeferrable
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should fail on_connect with exception after synchrony connect and reset" do
|
91
|
+
EM.synchrony do
|
92
|
+
test_blocking_error
|
93
|
+
EM.stop
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
shared_context 'test blocking' do
|
99
|
+
it "should invoke on_connect after blocking connect and reset" do
|
100
|
+
test_blocking
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
shared_context 'test blocking on_connect error' do
|
105
|
+
it "should fail on_connect with exception after blocking connect and reset" do
|
106
|
+
test_blocking_error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'on_connect option' do
|
111
|
+
subject { PG::EM::Client }
|
112
|
+
let(:query_name) { 'get_db_size' }
|
113
|
+
let(:query) { 'SELECT pg_database_size(current_database());' }
|
114
|
+
let(:options) { {on_connect: on_connect} }
|
115
|
+
let(:sleep_query){ 'SELECT pg_sleep(0.1)'}
|
116
|
+
let(:on_connect_exception) { Class.new(StandardError) }
|
117
|
+
|
118
|
+
|
119
|
+
describe 'with deferrable on_connect' do
|
120
|
+
let(:on_connect) { proc {|client, is_async|
|
121
|
+
is_async.should be_true
|
122
|
+
PG::EM::FeaturedDeferrable.new.tap do |df|
|
123
|
+
client.exec_defer(sleep_query).callback do
|
124
|
+
df.bind_status client.prepare_defer(query_name, query)
|
125
|
+
end.errback { df.fail on_connect_exception }
|
126
|
+
end
|
127
|
+
} }
|
128
|
+
|
129
|
+
include_context 'test on_connect'
|
130
|
+
end
|
131
|
+
|
132
|
+
describe 'with synchrony on_connect' do
|
133
|
+
let(:on_connect) { proc {|client, is_async|
|
134
|
+
is_async.should be_true
|
135
|
+
was_async = false
|
136
|
+
EM.next_tick { was_async = true }
|
137
|
+
client.exec(sleep_query)
|
138
|
+
client.prepare(query_name, query)
|
139
|
+
was_async.should be_true
|
140
|
+
} }
|
141
|
+
|
142
|
+
include_context 'test on_connect'
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'with blocking on_connect' do
|
146
|
+
let(:on_connect) { proc {|client, is_async|
|
147
|
+
is_async.should be_false
|
148
|
+
client.prepare(query_name, query)
|
149
|
+
} }
|
150
|
+
|
151
|
+
include_context 'test blocking'
|
152
|
+
end
|
153
|
+
|
154
|
+
describe 'with error raised in on_connect' do
|
155
|
+
let(:on_connect) { proc {|client|
|
156
|
+
raise on_connect_exception
|
157
|
+
} }
|
158
|
+
|
159
|
+
include_context 'test on_connect error'
|
160
|
+
include_context 'test blocking on_connect error'
|
161
|
+
end
|
162
|
+
|
163
|
+
describe 'with on_connect deferrable failure' do
|
164
|
+
let(:on_connect) { proc {|client|
|
165
|
+
EM::DefaultDeferrable.new.tap {|df| df.fail on_connect_exception.new }
|
166
|
+
} }
|
167
|
+
|
168
|
+
include_context 'test on_connect error'
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
$:.unshift "lib"
|
2
|
+
gem 'eventmachine', '~> 1.0.0'
|
3
|
+
gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'em-synchrony'
|
6
|
+
require 'em-synchrony/fiber_iterator'
|
7
|
+
require 'pg/em/connection_pool'
|
8
|
+
|
9
|
+
shared_context 'test on_connect' do
|
10
|
+
|
11
|
+
it 'should call prepared statement concurrently with synchrony' do
|
12
|
+
results = []
|
13
|
+
pool = subject.new(options)
|
14
|
+
pool.max_size.should eq concurrency
|
15
|
+
pool.size.should eq 1
|
16
|
+
start = Time.now
|
17
|
+
EM::Synchrony::FiberIterator.new((1..concurrency), concurrency).each do |index|
|
18
|
+
pool.exec_prepared(query_name) do |result|
|
19
|
+
result.should be_an_instance_of PG::Result
|
20
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
21
|
+
end
|
22
|
+
pool.query(sleep_query).should be_an_instance_of PG::Result
|
23
|
+
results << index
|
24
|
+
end
|
25
|
+
delta = Time.now - start
|
26
|
+
delta.should be_between(sleep_interval, sleep_interval * concurrency / 2)
|
27
|
+
results.sort.should eq (1..concurrency).to_a
|
28
|
+
pool.size.should eq concurrency
|
29
|
+
EM.stop
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should call prepared statement concurrently with deferrable' do
|
33
|
+
results = []
|
34
|
+
subject.connect_defer(options) do |pool|
|
35
|
+
pool.max_size.should eq concurrency
|
36
|
+
pool.size.should eq 1
|
37
|
+
start = Time.now
|
38
|
+
concurrency.times do |index|
|
39
|
+
pool.exec_prepared_defer(query_name) do |result|
|
40
|
+
result.should be_an_instance_of PG::Result
|
41
|
+
result[0]['pg_database_size'].to_i.should be > 0
|
42
|
+
pool.query_defer(sleep_query) do |result|
|
43
|
+
result.should be_an_instance_of PG::Result
|
44
|
+
results << index
|
45
|
+
if results.length == concurrency
|
46
|
+
delta = Time.now - start
|
47
|
+
delta.should be_between(sleep_interval, sleep_interval * concurrency / 2)
|
48
|
+
results.sort.should eq (0...concurrency).to_a
|
49
|
+
pool.size.should eq concurrency
|
50
|
+
EM.stop
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
shared_context 'test on_connect error' do
|
60
|
+
|
61
|
+
it "should fail on_connect with exception after synchrony connect" do
|
62
|
+
expect do
|
63
|
+
subject.new(options)
|
64
|
+
end.to raise_error(on_connect_exception)
|
65
|
+
client = subject.new(options.merge(lazy: true))
|
66
|
+
client.should be_an_instance_of subject
|
67
|
+
expect do
|
68
|
+
client.query(sleep_query)
|
69
|
+
end.to raise_error(on_connect_exception)
|
70
|
+
EM.stop
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should fail on_connect with exception after deferrable connect" do
|
74
|
+
subject.connect_defer(options) do |ex|
|
75
|
+
ex.should be_an_instance_of on_connect_exception
|
76
|
+
pool = subject.new(options.merge(lazy: true))
|
77
|
+
pool.should be_an_instance_of subject
|
78
|
+
pool.query_defer(sleep_query) do |ex|
|
79
|
+
ex.should be_an_instance_of on_connect_exception
|
80
|
+
EM.stop
|
81
|
+
end.should be_an_instance_of PG::EM::FeaturedDeferrable
|
82
|
+
end.should be_an_instance_of PG::EM::FeaturedDeferrable
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'connection pool' do
|
88
|
+
subject { PG::EM::ConnectionPool }
|
89
|
+
|
90
|
+
describe 'on_connect' do
|
91
|
+
let(:query_name) { 'get_db_size' }
|
92
|
+
let(:query) { 'SELECT pg_database_size(current_database());' }
|
93
|
+
let(:concurrency) { 10 }
|
94
|
+
let(:options) { {size: concurrency, on_connect: on_connect} }
|
95
|
+
let(:sleep_interval) { 0.1 }
|
96
|
+
let(:sleep_query) { "SELECT pg_sleep(#{sleep_interval})"}
|
97
|
+
let(:on_connect_exception) { Class.new(StandardError) }
|
98
|
+
let(:on_connect) { proc {} }
|
99
|
+
|
100
|
+
around(:each) do |testcase|
|
101
|
+
EM.synchrony do
|
102
|
+
begin
|
103
|
+
testcase.call
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should setup block as on_connect client option' do
|
109
|
+
connect_hook = false
|
110
|
+
pool = subject.new { connect_hook = true }
|
111
|
+
connect_hook.should be_true
|
112
|
+
pool.should be_an_instance_of subject
|
113
|
+
pool.on_connect.should be_an_instance_of Proc
|
114
|
+
EM.stop
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should prefer on_connect from options' do
|
118
|
+
connect_hook = false
|
119
|
+
pool = subject.new(options) { connect_hook = true }
|
120
|
+
connect_hook.should be_false
|
121
|
+
pool.should be_an_instance_of subject
|
122
|
+
pool.on_connect.should be on_connect
|
123
|
+
EM.stop
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'with deferrable on_connect' do
|
127
|
+
let(:on_connect) { proc {|client, is_async|
|
128
|
+
is_async.should be_true
|
129
|
+
PG::EM::FeaturedDeferrable.new.tap do |df|
|
130
|
+
client.exec_defer(sleep_query).callback do
|
131
|
+
df.bind_status client.prepare_defer(query_name, query)
|
132
|
+
end.errback { df.fail on_connect_exception }
|
133
|
+
end
|
134
|
+
} }
|
135
|
+
|
136
|
+
include_context 'test on_connect'
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'with synchrony on_connect' do
|
140
|
+
let(:on_connect) { proc {|client, is_async|
|
141
|
+
is_async.should be_true
|
142
|
+
was_async = false
|
143
|
+
EM.next_tick { was_async = true }
|
144
|
+
client.exec(sleep_query)
|
145
|
+
client.prepare(query_name, query)
|
146
|
+
was_async.should be_true
|
147
|
+
} }
|
148
|
+
|
149
|
+
include_context 'test on_connect'
|
150
|
+
end
|
151
|
+
|
152
|
+
describe 'with error raised in on_connect' do
|
153
|
+
let(:on_connect) { proc {|client|
|
154
|
+
raise on_connect_exception
|
155
|
+
} }
|
156
|
+
|
157
|
+
include_context 'test on_connect error'
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'with on_connect deferrable failure' do
|
161
|
+
let(:on_connect) { proc {|client|
|
162
|
+
EM::DefaultDeferrable.new.tap {|df| df.fail on_connect_exception.new }
|
163
|
+
} }
|
164
|
+
|
165
|
+
include_context 'test on_connect error'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '#transaction' do
|
170
|
+
let(:concurrency) { 2 }
|
171
|
+
let(:options) { {size: concurrency} }
|
172
|
+
let(:query) { 'SELECT pg_database_size(current_database());' }
|
173
|
+
|
174
|
+
around(:each) do |testcase|
|
175
|
+
EM.synchrony do
|
176
|
+
begin
|
177
|
+
@pool = subject.new(options)
|
178
|
+
testcase.call
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should lock transaction connection to fiber' do
|
184
|
+
@pool.transaction do |pg|
|
185
|
+
@pool.hold {|c| c.should be pg }
|
186
|
+
Fiber.new do
|
187
|
+
@pool.size.should eq 1
|
188
|
+
@pool.hold {|c| c.should_not be pg }
|
189
|
+
@pool.size.should eq 2
|
190
|
+
EM.stop
|
191
|
+
end.resume
|
192
|
+
@pool.hold {|c| c.should be pg }
|
193
|
+
@pool.size.should eq 2
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|