bunny 1.0.0.pre3 → 1.0.0.pre4
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 +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
|