em-pg-client 0.3.2 → 0.3.3
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.
- 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
|