bunny 1.0.0.pre3 → 1.0.0.pre4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -1
- data/ChangeLog.md +54 -0
- data/README.md +5 -5
- data/benchmarks/mutex_and_monitor.rb +42 -0
- data/bunny.gemspec +2 -2
- data/examples/guides/extensions/connection_blocked.rb +35 -0
- data/lib/bunny/channel.rb +16 -7
- data/lib/bunny/exceptions.rb +4 -1
- data/lib/bunny/reader_loop.rb +17 -3
- data/lib/bunny/session.rb +58 -6
- data/lib/bunny/transport.rb +10 -1
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_consume_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_nack_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_publish_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_qos_spec.rb +5 -8
- data/spec/higher_level_api/integration/basic_reject_spec.rb +16 -17
- data/spec/higher_level_api/integration/basic_return_spec.rb +1 -1
- data/spec/higher_level_api/integration/channel_close_spec.rb +6 -10
- data/spec/higher_level_api/integration/channel_flow_spec.rb +6 -9
- data/spec/higher_level_api/integration/channel_open_spec.rb +11 -20
- data/spec/higher_level_api/integration/confirm_select_spec.rb +1 -1
- data/spec/higher_level_api/integration/connection_spec.rb +1 -1
- data/spec/higher_level_api/integration/connection_stop_spec.rb +13 -0
- data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +1 -1
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +46 -1
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +1 -1
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +28 -0
- data/spec/higher_level_api/integration/merry_go_round_spec.rb +1 -1
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +1 -1
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +1 -1
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +1 -1
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_declare_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_delete_spec.rb +2 -2
- data/spec/higher_level_api/integration/queue_purge_spec.rb +1 -1
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +2 -2
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +1 -1
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +2 -2
- data/spec/higher_level_api/integration/tls_connection_spec.rb +2 -2
- data/spec/higher_level_api/integration/tx_commit_spec.rb +1 -1
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +1 -1
- data/spec/stress/connection_open_close_spec.rb +25 -2
- data/spec/unit/concurrent/condition_spec.rb +53 -46
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +48 -9
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1668fc7a45c060f60a853a68eab96a4f3a18b56
|
4
|
+
data.tar.gz: 36139657c1d1333fbc97cf070d588e4fe8bd2927
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dde418ea8694ed3c7755552d8f8eb43ca3afe3d8063ecf05e1fc359b8705fa6ef8c148a463d65426bbfa1dafea14979a4b0e9439296b106684b33dd590bf0d02
|
7
|
+
data.tar.gz: b825a7c0f8e3e0cdf1a44f46a4d6eac297a6f356f9e4ec153b3dc4301a499923eccf22e26c9a4079502d428f9a32887378f86669cd33cd9091e0597c00d9a639
|
data/.travis.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
bundler_args: --without development
|
2
2
|
before_script: "./bin/ci/before_build.sh"
|
3
|
-
script: "bundle exec rspec -
|
3
|
+
script: "bundle exec rspec -cfs spec"
|
4
4
|
rvm:
|
5
5
|
- "2.0"
|
6
6
|
- "1.9.3"
|
@@ -15,3 +15,6 @@ branches:
|
|
15
15
|
only:
|
16
16
|
- master
|
17
17
|
- 0.9.x-stable
|
18
|
+
matrix:
|
19
|
+
allow_failures:
|
20
|
+
- rvm: rbx-19mode
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,57 @@
|
|
1
|
+
## Changes between Bunny 1.0.0.pre3 and 1.0.0.pre4
|
2
|
+
|
3
|
+
### Default Paths for TLS/SSL CA's on Linux
|
4
|
+
|
5
|
+
Bunny now will use the following TLS/SSL CA's paths on Linux by default:
|
6
|
+
|
7
|
+
* `/etc/ssl/certs/ca-certificates.crt` on Ubuntu/Debian
|
8
|
+
* `/etc/ssl/certs/ca-bundle.crt` on Amazon Linux
|
9
|
+
* `/etc/ssl/ca-bundle.pem` on OpenSUSE
|
10
|
+
* `/etc/pki/tls/certs/ca-bundle.crt` on Fedora/RHEL
|
11
|
+
|
12
|
+
and will log a warning if no CA files are available via default paths
|
13
|
+
or `:tls_ca_certificates`.
|
14
|
+
|
15
|
+
Contributed by Carl Hörberg.
|
16
|
+
|
17
|
+
### Consumers Can Be Re-Registered From Bunny::Consumer#handle_cancellation
|
18
|
+
|
19
|
+
It is now possible to re-register a consumer (and use any other synchronous methods)
|
20
|
+
from `Bunny::Consumer#handle_cancellation`, which is now invoked in the channel's
|
21
|
+
thread pool.
|
22
|
+
|
23
|
+
|
24
|
+
### Bunny::Session#close Fixed for Single Threaded Connections
|
25
|
+
|
26
|
+
`Bunny::Session#close` with single threaded connections no longer fails
|
27
|
+
with a nil pointer exception.
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
## Changes between Bunny 1.0.0.pre2 and 1.0.0.pre3
|
32
|
+
|
33
|
+
This release has **breaking API changes**.
|
34
|
+
|
35
|
+
### Safe[r] basic.ack, basic.nack and basic.reject implementation
|
36
|
+
|
37
|
+
Previously if a channel was recovered (reopened) by automatic connection
|
38
|
+
recovery before a message was acknowledged or rejected, it would cause
|
39
|
+
any operation on the channel that uses delivery tags to fail and
|
40
|
+
cause the channel to be closed.
|
41
|
+
|
42
|
+
To avoid this issue, every channel keeps a counter of how many times
|
43
|
+
it has been reopened and marks delivery tags with them. Using a stale
|
44
|
+
tag to ack or reject a message will produce no method sent to RabbitMQ.
|
45
|
+
Note that unacknowledged messages will be requeued by RabbitMQ when connection
|
46
|
+
goes down anyway.
|
47
|
+
|
48
|
+
This involves an API change: `Bunny::DeliveryMetadata#delivery_tag` is now
|
49
|
+
and instance of a class that responds to `#tag` and `#to_i` and is accepted
|
50
|
+
by `Bunny::Channel#ack` and related methods.
|
51
|
+
|
52
|
+
Integers are still accepted by the same methods.
|
53
|
+
|
54
|
+
|
1
55
|
## Changes between Bunny 1.0.0.pre1 and 1.0.0.pre2
|
2
56
|
|
3
57
|
### Exclusivity Violation for Consumers Now Raises a Reasonable Exception
|
data/README.md
CHANGED
@@ -79,7 +79,7 @@ backwards compatible as possible but within reason.
|
|
79
79
|
|
80
80
|
### With Rubygems
|
81
81
|
|
82
|
-
To install Bunny
|
82
|
+
To install Bunny with RubyGems:
|
83
83
|
|
84
84
|
```
|
85
85
|
gem install bunny
|
@@ -87,17 +87,17 @@ gem install bunny
|
|
87
87
|
|
88
88
|
### Bundler Dependency
|
89
89
|
|
90
|
-
To use Bunny
|
90
|
+
To use Bunny in a project managed with Bundler:
|
91
91
|
|
92
92
|
``` ruby
|
93
|
-
gem "bunny", ">= 0.
|
93
|
+
gem "bunny", ">= 0.10.0"
|
94
94
|
```
|
95
95
|
|
96
96
|
|
97
|
-
## Quick Start
|
97
|
+
## Quick Start
|
98
98
|
|
99
99
|
Below is a small snippet that demonstrates how to publish
|
100
|
-
and synchronously consume ("pull API") messages with Bunny
|
100
|
+
and synchronously consume ("pull API") messages with Bunny.
|
101
101
|
|
102
102
|
For a 15 minute tutorial using more practical examples, see [Getting Started with RabbitMQ and Ruby using Bunny](http://rubybunny.info/articles/getting_started.html).
|
103
103
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "set"
|
6
|
+
require "thread"
|
7
|
+
require "benchmark"
|
8
|
+
require "monitor"
|
9
|
+
|
10
|
+
puts
|
11
|
+
puts "-" * 80
|
12
|
+
puts "Benchmarking on #{RUBY_DESCRIPTION}"
|
13
|
+
|
14
|
+
n = 2_000_000
|
15
|
+
mx = Mutex.new
|
16
|
+
mt = Monitor.new
|
17
|
+
|
18
|
+
# warm up the JIT, etc
|
19
|
+
puts "Doing a warmup run..."
|
20
|
+
n.times do |i|
|
21
|
+
mx.synchronize { 1 }
|
22
|
+
mt.synchronize { 1 }
|
23
|
+
end
|
24
|
+
|
25
|
+
t1 = Benchmark.realtime do
|
26
|
+
n.times do |i|
|
27
|
+
mx.synchronize { 1 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
r1 = (n.to_f/t1.to_f)
|
31
|
+
|
32
|
+
t2 = Benchmark.realtime do
|
33
|
+
n.times do |i|
|
34
|
+
mt.synchronize { 1 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
r2 = (n.to_f/t2.to_f)
|
38
|
+
|
39
|
+
puts "Mutex#synchronize, rate: #{(r1 / 1000).round(2)} KGHz"
|
40
|
+
puts "Monitor#synchronize, rate: #{(r2 / 1000).round(2)} KGHz"
|
41
|
+
puts
|
42
|
+
puts "-" * 80
|
data/bunny.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.version = Bunny::VERSION.dup
|
10
10
|
s.homepage = "http://rubybunny.info"
|
11
11
|
s.summary = "Popular easy to use Ruby client for RabbitMQ"
|
12
|
-
s.description = "Easy to use, feature complete Ruby client for RabbitMQ 2.0."
|
12
|
+
s.description = "Easy to use, feature complete Ruby client for RabbitMQ 2.0 and later versions."
|
13
13
|
s.license = "MIT"
|
14
14
|
|
15
15
|
# Sorted alphabetically.
|
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
map { |mail| Base64.decode64(mail) }
|
30
30
|
|
31
31
|
# Dependencies
|
32
|
-
s.add_dependency "amq-protocol", ">= 1.
|
32
|
+
s.add_dependency "amq-protocol", ">= 1.7.0"
|
33
33
|
|
34
34
|
# Files.
|
35
35
|
s.has_rdoc = true
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "bunny"
|
6
|
+
|
7
|
+
puts "=> Demonstrating connection.blocked"
|
8
|
+
puts
|
9
|
+
|
10
|
+
conn = Bunny.new
|
11
|
+
conn.start
|
12
|
+
|
13
|
+
ch = conn.create_channel
|
14
|
+
x = ch.fanout("amq.fanout")
|
15
|
+
|
16
|
+
# This example requires high memory watermark to be set
|
17
|
+
# really low to demonstrate blocking.
|
18
|
+
#
|
19
|
+
# rabbitmqctl set_vm_memory_high_watermark 0.00000001
|
20
|
+
#
|
21
|
+
# should do it.
|
22
|
+
|
23
|
+
conn.on_blocked do |connection_blocked|
|
24
|
+
puts "Connection is blocked. Reason: #{connection_blocked.reason}"
|
25
|
+
end
|
26
|
+
|
27
|
+
conn.on_unblocked do |connection_unblocked|
|
28
|
+
puts "Connection is unblocked."
|
29
|
+
end
|
30
|
+
|
31
|
+
x.publish("z" * 1024 * 1024 * 16)
|
32
|
+
|
33
|
+
sleep 120.0
|
34
|
+
puts "Disconnecting..."
|
35
|
+
conn.close
|
data/lib/bunny/channel.rb
CHANGED
@@ -843,6 +843,7 @@ module Bunny
|
|
843
843
|
|
844
844
|
@last_basic_consume_ok
|
845
845
|
end
|
846
|
+
alias consume basic_consume
|
846
847
|
|
847
848
|
# Registers a consumer for queue as {Bunny::Consumer} instance.
|
848
849
|
#
|
@@ -894,6 +895,7 @@ module Bunny
|
|
894
895
|
|
895
896
|
@last_basic_consume_ok
|
896
897
|
end
|
898
|
+
alias consume_with basic_consume_with
|
897
899
|
|
898
900
|
# Removes a consumer. Messages for this consumer will no longer be delivered. If the queue
|
899
901
|
# it was on is auto-deleted and this consumer was the last one, the queue will be deleted.
|
@@ -1538,10 +1540,17 @@ module Bunny
|
|
1538
1540
|
@continuations.push(method)
|
1539
1541
|
when AMQ::Protocol::Basic::Cancel then
|
1540
1542
|
if consumer = @consumers[method.consumer_tag]
|
1541
|
-
|
1543
|
+
@work_pool.submit do
|
1544
|
+
begin
|
1545
|
+
@consumers.delete(method.consumer_tag)
|
1546
|
+
consumer.handle_cancellation(method)
|
1547
|
+
rescue Exception => e
|
1548
|
+
@logger.error "Got excepton when notifying consumer #{method.consumer_tag} about cancellation!"
|
1549
|
+
end
|
1550
|
+
end
|
1551
|
+
else
|
1552
|
+
@logger.warn "No consumer for tag #{method.consumer_tag} on channel #{@id}!"
|
1542
1553
|
end
|
1543
|
-
|
1544
|
-
@consumers.delete(method.consumer_tag)
|
1545
1554
|
when AMQ::Protocol::Basic::CancelOk then
|
1546
1555
|
@continuations.push(method)
|
1547
1556
|
unregister_consumer(method.consumer_tag)
|
@@ -1847,12 +1856,12 @@ module Bunny
|
|
1847
1856
|
# @private
|
1848
1857
|
def guarding_against_stale_delivery_tags(tag, &block)
|
1849
1858
|
case tag
|
1850
|
-
|
1859
|
+
# if a fixnum was passed, execute unconditionally. MK.
|
1851
1860
|
when Fixnum then
|
1852
1861
|
block.call
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1862
|
+
# versioned delivery tags should be checked to avoid
|
1863
|
+
# sending out stale (invalid) tags after channel was reopened
|
1864
|
+
# during network failure recovery. MK.
|
1856
1865
|
when VersionedDeliveryTag then
|
1857
1866
|
if !tag.stale?(@recoveries_counter.get)
|
1858
1867
|
block.call
|
data/lib/bunny/exceptions.rb
CHANGED
@@ -55,7 +55,7 @@ module Bunny
|
|
55
55
|
when Exception then
|
56
56
|
e.message
|
57
57
|
end
|
58
|
-
super("Could not
|
58
|
+
super("Could not establish TCP connection to #{hostname}:#{port}: #{m}")
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -70,6 +70,9 @@ module Bunny
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
class ShutdownSignal < Exception
|
74
|
+
end
|
75
|
+
|
73
76
|
# Raised when RabbitMQ closes TCP connection before finishing connection
|
74
77
|
# sequence properly. This typically indicates an authentication issue.
|
75
78
|
class PossibleAuthenticationFailureError < Exception
|
data/lib/bunny/reader_loop.rb
CHANGED
@@ -19,7 +19,6 @@ module Bunny
|
|
19
19
|
|
20
20
|
def start
|
21
21
|
@thread = Thread.new(&method(:run_loop))
|
22
|
-
@thread.abort_on_exception = true
|
23
22
|
end
|
24
23
|
|
25
24
|
def resume
|
@@ -33,8 +32,10 @@ module Bunny
|
|
33
32
|
break if @stopping || @network_is_down
|
34
33
|
run_once
|
35
34
|
rescue Errno::EBADF => ebadf
|
35
|
+
break if @stopping
|
36
36
|
# ignored, happens when we loop after the transport has already been closed
|
37
37
|
rescue AMQ::Protocol::EmptyResponseError, IOError, SystemCallError => e
|
38
|
+
break if @stopping
|
38
39
|
log_exception(e)
|
39
40
|
|
40
41
|
@network_is_down = true
|
@@ -44,7 +45,10 @@ module Bunny
|
|
44
45
|
else
|
45
46
|
@session_thread.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
46
47
|
end
|
48
|
+
rescue ShutdownSignal => _
|
49
|
+
break
|
47
50
|
rescue Exception => e
|
51
|
+
break if @stopping
|
48
52
|
log_exception(e)
|
49
53
|
|
50
54
|
@network_is_down = true
|
@@ -86,9 +90,19 @@ module Bunny
|
|
86
90
|
@stopped
|
87
91
|
end
|
88
92
|
|
93
|
+
def raise(e)
|
94
|
+
@thread.raise(e) if @thread
|
95
|
+
end
|
96
|
+
|
97
|
+
def join
|
98
|
+
@thread.join if @thread
|
99
|
+
end
|
100
|
+
|
89
101
|
def kill
|
90
|
-
@thread
|
91
|
-
|
102
|
+
if @thread
|
103
|
+
@thread.kill
|
104
|
+
@thread.join
|
105
|
+
end
|
92
106
|
end
|
93
107
|
|
94
108
|
def log_exception(e)
|
data/lib/bunny/session.rb
CHANGED
@@ -54,7 +54,8 @@ module Bunny
|
|
54
54
|
:publisher_confirms => true,
|
55
55
|
:consumer_cancel_notify => true,
|
56
56
|
:exchange_exchange_bindings => true,
|
57
|
-
:"basic.nack" => true
|
57
|
+
:"basic.nack" => true,
|
58
|
+
:"connection.blocked" => true
|
58
59
|
},
|
59
60
|
:product => "Bunny",
|
60
61
|
:platform => ::RUBY_DESCRIPTION,
|
@@ -135,6 +136,7 @@ module Bunny
|
|
135
136
|
@continuation_timeout = opts.fetch(:continuation_timeout, DEFAULT_CONTINUATION_TIMEOUT)
|
136
137
|
|
137
138
|
@status = :not_connected
|
139
|
+
@blocked = false
|
138
140
|
|
139
141
|
# these are negotiated with the broker during the connection tuning phase
|
140
142
|
@client_frame_max = opts.fetch(:frame_max, DEFAULT_FRAME_MAX)
|
@@ -208,6 +210,9 @@ module Bunny
|
|
208
210
|
return self if connected?
|
209
211
|
|
210
212
|
@status = :connecting
|
213
|
+
# reset here for cases when automatic network recovery kicks in
|
214
|
+
# when we were blocked. MK.
|
215
|
+
@blocked = false
|
211
216
|
self.reset_continuations
|
212
217
|
|
213
218
|
begin
|
@@ -226,7 +231,7 @@ module Bunny
|
|
226
231
|
self.open_connection
|
227
232
|
|
228
233
|
@reader_loop = nil
|
229
|
-
self.start_reader_loop if
|
234
|
+
self.start_reader_loop if threaded?
|
230
235
|
|
231
236
|
@default_channel = self.create_channel
|
232
237
|
rescue Exception => e
|
@@ -342,6 +347,34 @@ module Bunny
|
|
342
347
|
@default_channel.exchange(*args)
|
343
348
|
end
|
344
349
|
|
350
|
+
# Defines a callback that will be executed when RabbitMQ blocks the connection
|
351
|
+
# because it is running low on memory or disk space (as configured via config file
|
352
|
+
# and/or rabbitmqctl).
|
353
|
+
#
|
354
|
+
# @yield [AMQ::Protocol::Connection::Blocked] connection.blocked method which provides a reason for blocking
|
355
|
+
#
|
356
|
+
# @api public
|
357
|
+
def on_blocked(&block)
|
358
|
+
@block_callback = block
|
359
|
+
end
|
360
|
+
|
361
|
+
# Defines a callback that will be executed when RabbitMQ unblocks the connection
|
362
|
+
# that was previously blocked, e.g. because the memory or disk space alarm has cleared.
|
363
|
+
#
|
364
|
+
# @see #on_blocked
|
365
|
+
# @api public
|
366
|
+
def on_unblocked(&block)
|
367
|
+
@unblock_callback = block
|
368
|
+
end
|
369
|
+
|
370
|
+
# @return [Boolean] true if the connection is currently blocked by RabbitMQ because it's running low on
|
371
|
+
# RAM, disk space, or other resource; false otherwise
|
372
|
+
# @see #on_blocked
|
373
|
+
# @see #on_unblocked
|
374
|
+
def blocked?
|
375
|
+
@blocked
|
376
|
+
end
|
377
|
+
|
345
378
|
|
346
379
|
#
|
347
380
|
# Implementation
|
@@ -418,6 +451,12 @@ module Bunny
|
|
418
451
|
ensure
|
419
452
|
@continuations.push(:__unblock__)
|
420
453
|
end
|
454
|
+
when AMQ::Protocol::Connection::Blocked then
|
455
|
+
@blocked = true
|
456
|
+
@block_callback.call(method) if @block_callback
|
457
|
+
when AMQ::Protocol::Connection::Unblocked then
|
458
|
+
@blocked = false
|
459
|
+
@unblock_callback.call(method) if @unblock_callback
|
421
460
|
when AMQ::Protocol::Channel::Close then
|
422
461
|
begin
|
423
462
|
ch = @channels[ch_number]
|
@@ -626,10 +665,23 @@ module Bunny
|
|
626
665
|
def maybe_shutdown_reader_loop
|
627
666
|
if @reader_loop
|
628
667
|
@reader_loop.stop
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
668
|
+
if threaded?
|
669
|
+
# this is the easiest way to wait until the loop
|
670
|
+
# is guaranteed to have terminated
|
671
|
+
@reader_loop.raise(ShutdownSignal)
|
672
|
+
# joining the thread here may take forever
|
673
|
+
# on JRuby because sun.nio.ch.KQueueArrayWrapper#kevent0 is
|
674
|
+
# a native method that cannot be (easily) interrupted.
|
675
|
+
# So we use this ugly hack or else our test suite takes forever
|
676
|
+
# to run on JRuby (a new connection is opened/closed per example). MK.
|
677
|
+
if RUBY_ENGINE == "jruby"
|
678
|
+
sleep 0.075
|
679
|
+
else
|
680
|
+
@reader_loop.join
|
681
|
+
end
|
682
|
+
else
|
683
|
+
# single threaded mode, nothing to do. MK.
|
684
|
+
end
|
633
685
|
end
|
634
686
|
|
635
687
|
@reader_loop = nil
|