bunny 1.0.0.pre1 → 1.0.0.pre2
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/ChangeLog.md +41 -0
- data/lib/bunny/channel.rb +4 -3
- data/lib/bunny/channel_id_allocator.rb +2 -1
- data/lib/bunny/concurrent/condition.rb +2 -1
- data/lib/bunny/heartbeat_sender.rb +1 -1
- data/lib/bunny/reader_loop.rb +6 -0
- data/lib/bunny/session.rb +44 -15
- data/lib/bunny/transport.rb +14 -3
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/connection_stop_spec.rb +13 -0
- data/spec/higher_level_api/integration/tls_connection_spec.rb +43 -1
- data/spec/stress/connection_open_close_spec.rb +17 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b675d7cc26c0951af3fda991f438c8bbc3cb03c5
|
4
|
+
data.tar.gz: 0cdf2879b75d769676c3dce890bd1d7213a96448
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e881cb1d9695f16102ca8a08bdd9191a38cc044c16e4c1f89a32b2331d0abd6d58a00abc731e3c809d9cd538a1d243eca9029074da228ee28400c2307e7deb4f
|
7
|
+
data.tar.gz: 8390a12a2595bd1f7b65dd83c31686117081aa0672c258935e07c040ccf89222a1160e29cab0d519c24483f13adc24b3d8a5af41598b584d43c6913e1965d18e
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
## Changes between Bunny 1.0.0.pre1 and 1.0.0.pre2
|
2
|
+
|
3
|
+
### Reentrant Mutex Implementation
|
4
|
+
|
5
|
+
Bunny now allows mutex impl to be configurable, uses reentrant Monitor
|
6
|
+
by default.
|
7
|
+
|
8
|
+
Non-reentrant mutexes is a major PITA and may affect code that
|
9
|
+
uses Bunny.
|
10
|
+
|
11
|
+
Avg. publishing throughput with Monitor drops slightly from
|
12
|
+
5.73 Khz to 5.49 Khz (about 4% decrease), which is reasonable
|
13
|
+
for Bunny.
|
14
|
+
|
15
|
+
Apps that need these 4% can configure what mutex implementation
|
16
|
+
is used on per-connection basis.
|
17
|
+
|
18
|
+
### Eliminated Race Condition in Bunny::Session#close
|
19
|
+
|
20
|
+
`Bunny::Session#close` had a race condition that caused (non-deterministic)
|
21
|
+
exceptions when connection transport was closed before connection
|
22
|
+
reader loop was guaranteed to have stopped.
|
23
|
+
|
24
|
+
### connection.close Raises Exceptions on Connection Thread
|
25
|
+
|
26
|
+
Connection-level exceptions (including when a connection is closed via
|
27
|
+
management UI or `rabbitmqctl`) will now be raised on the connection
|
28
|
+
thread so they
|
29
|
+
|
30
|
+
* can be handled by applications
|
31
|
+
* do not start connection recovery, which may be uncalled for
|
32
|
+
|
33
|
+
### Client TLS Certificates are Optional
|
34
|
+
|
35
|
+
Bunny will no longer require client TLS certificates. Note that CA certificate
|
36
|
+
list is still necessary.
|
37
|
+
|
38
|
+
If RabbitMQ TLS configuration requires peer verification, client certificate
|
39
|
+
and private key are mandatory.
|
40
|
+
|
41
|
+
|
1
42
|
## Changes between Bunny 0.9.0 and 1.0.0.pre1
|
2
43
|
|
3
44
|
### Publishing Over Closed Connections
|
data/lib/bunny/channel.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "thread"
|
3
|
+
require "monitor"
|
3
4
|
require "set"
|
4
5
|
|
5
6
|
require "bunny/consumer_work_pool"
|
@@ -173,10 +174,10 @@ module Bunny
|
|
173
174
|
@work_pool = work_pool
|
174
175
|
|
175
176
|
# synchronizes frameset delivery. MK.
|
176
|
-
@publishing_mutex =
|
177
|
-
@consumer_mutex =
|
177
|
+
@publishing_mutex = @connection.mutex_impl.new
|
178
|
+
@consumer_mutex = @connection.mutex_impl.new
|
178
179
|
|
179
|
-
@unconfirmed_set_mutex =
|
180
|
+
@unconfirmed_set_mutex = @connection.mutex_impl.new
|
180
181
|
|
181
182
|
self.reset_continuations
|
182
183
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "thread"
|
2
|
+
require "monitor"
|
2
3
|
require "amq/int_allocator"
|
3
4
|
|
4
5
|
module Bunny
|
@@ -18,7 +19,7 @@ module Bunny
|
|
18
19
|
# @param [Integer] max_channel Max allowed channel id
|
19
20
|
def initialize(max_channel = ((1 << 16) - 1))
|
20
21
|
@allocator = AMQ::IntAllocator.new(1, max_channel)
|
21
|
-
@mutex =
|
22
|
+
@mutex = Monitor.new
|
22
23
|
end
|
23
24
|
|
24
25
|
|
data/lib/bunny/reader_loop.rb
CHANGED
@@ -51,6 +51,8 @@ module Bunny
|
|
51
51
|
@session_thread.raise(Bunny::NetworkFailure.new("caught an unexpected exception in the network loop: #{e.message}", e))
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
@stopped = true
|
54
56
|
end
|
55
57
|
|
56
58
|
def run_once
|
@@ -80,6 +82,10 @@ module Bunny
|
|
80
82
|
@stopping = true
|
81
83
|
end
|
82
84
|
|
85
|
+
def stopped?
|
86
|
+
@stopped
|
87
|
+
end
|
88
|
+
|
83
89
|
def kill
|
84
90
|
@thread.kill
|
85
91
|
@thread.join
|
data/lib/bunny/session.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "socket"
|
2
2
|
require "thread"
|
3
|
+
require "monitor"
|
3
4
|
|
4
5
|
require "bunny/transport"
|
5
6
|
require "bunny/channel_id_allocator"
|
@@ -144,11 +145,14 @@ module Bunny
|
|
144
145
|
@mechanism = opts.fetch(:auth_mechanism, "PLAIN")
|
145
146
|
@credentials_encoder = credentials_encoder_for(@mechanism)
|
146
147
|
@locale = @opts.fetch(:locale, DEFAULT_LOCALE)
|
148
|
+
|
149
|
+
@mutex_impl = @opts.fetch(:mutex_impl, Monitor)
|
150
|
+
|
147
151
|
# mutex for the channel id => channel hash
|
148
|
-
@channel_mutex =
|
152
|
+
@channel_mutex = @mutex_impl.new
|
149
153
|
# transport operations/continuations mutex. A workaround for
|
150
154
|
# the non-reentrant Ruby mutexes. MK.
|
151
|
-
@transport_mutex =
|
155
|
+
@transport_mutex = @mutex_impl.new
|
152
156
|
@channels = Hash.new
|
153
157
|
|
154
158
|
@origin_thread = Thread.current
|
@@ -186,6 +190,9 @@ module Bunny
|
|
186
190
|
@threaded
|
187
191
|
end
|
188
192
|
|
193
|
+
# @private
|
194
|
+
attr_reader :mutex_impl
|
195
|
+
|
189
196
|
def configure_socket(&block)
|
190
197
|
raise ArgumentError, "No block provided!" if block.nil?
|
191
198
|
|
@@ -259,8 +266,13 @@ module Bunny
|
|
259
266
|
close_all_channels
|
260
267
|
|
261
268
|
Bunny::Timer.timeout(@transport.disconnect_timeout, ClientTimeout) do
|
262
|
-
self.close_connection(
|
269
|
+
self.close_connection(true)
|
263
270
|
end
|
271
|
+
|
272
|
+
maybe_shutdown_reader_loop
|
273
|
+
close_transport
|
274
|
+
|
275
|
+
@status = :closed
|
264
276
|
end
|
265
277
|
end
|
266
278
|
alias stop close
|
@@ -370,13 +382,15 @@ module Bunny
|
|
370
382
|
|
371
383
|
# @private
|
372
384
|
def close_connection(sync = true)
|
373
|
-
@transport.
|
385
|
+
if @transport.open?
|
386
|
+
@transport.send_frame(AMQ::Protocol::Connection::Close.encode(200, "Goodbye", 0, 0))
|
374
387
|
|
375
|
-
|
376
|
-
|
388
|
+
maybe_shutdown_heartbeat_sender
|
389
|
+
@status = :not_connected
|
377
390
|
|
378
|
-
|
379
|
-
|
391
|
+
if sync
|
392
|
+
@last_connection_close_ok = wait_on_continuations
|
393
|
+
end
|
380
394
|
end
|
381
395
|
end
|
382
396
|
|
@@ -392,16 +406,11 @@ module Bunny
|
|
392
406
|
@last_connection_error = instantiate_connection_level_exception(method)
|
393
407
|
@continuations.push(method)
|
394
408
|
|
395
|
-
raise
|
409
|
+
@origin_thread.raise(@last_connection_error)
|
396
410
|
when AMQ::Protocol::Connection::CloseOk then
|
397
411
|
@last_connection_close_ok = method
|
398
412
|
begin
|
399
413
|
@continuations.clear
|
400
|
-
|
401
|
-
reader_loop.stop
|
402
|
-
@reader_loop = nil
|
403
|
-
|
404
|
-
@transport.close
|
405
414
|
rescue StandardError => e
|
406
415
|
@logger.error e.class.name
|
407
416
|
@logger.error e.message
|
@@ -615,7 +624,27 @@ module Bunny
|
|
615
624
|
|
616
625
|
# @private
|
617
626
|
def maybe_shutdown_reader_loop
|
618
|
-
|
627
|
+
if @reader_loop
|
628
|
+
@reader_loop.stop
|
629
|
+
# We don't need to kill the loop but
|
630
|
+
# this is the easiest way to wait until the loop
|
631
|
+
# is guaranteed to have terminated
|
632
|
+
@reader_loop.kill
|
633
|
+
end
|
634
|
+
|
635
|
+
@reader_loop = nil
|
636
|
+
end
|
637
|
+
|
638
|
+
# @private
|
639
|
+
def close_transport
|
640
|
+
begin
|
641
|
+
@transport.close
|
642
|
+
rescue StandardError => e
|
643
|
+
@logger.error "Exception when closing transport:"
|
644
|
+
@logger.error e.class.name
|
645
|
+
@logger.error e.message
|
646
|
+
@logger.error e.backtrace
|
647
|
+
end
|
619
648
|
end
|
620
649
|
|
621
650
|
# @private
|
data/lib/bunny/transport.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "socket"
|
2
2
|
require "thread"
|
3
|
+
require "monitor"
|
3
4
|
|
4
5
|
begin
|
5
6
|
require "openssl"
|
@@ -49,7 +50,7 @@ module Bunny
|
|
49
50
|
@connect_timeout = nil if @connect_timeout == 0
|
50
51
|
@disconnect_timeout = @read_write_timeout || @connect_timeout
|
51
52
|
|
52
|
-
@writes_mutex =
|
53
|
+
@writes_mutex = @session.mutex_impl.new
|
53
54
|
|
54
55
|
maybe_initialize_socket
|
55
56
|
prepare_tls_context if @tls_enabled
|
@@ -311,14 +312,24 @@ module Bunny
|
|
311
312
|
end
|
312
313
|
|
313
314
|
def initialize_tls_context(ctx)
|
314
|
-
ctx.cert = OpenSSL::X509::Certificate.new(@tls_certificate)
|
315
|
-
ctx.key = OpenSSL::PKey::RSA.new(@tls_key)
|
315
|
+
ctx.cert = OpenSSL::X509::Certificate.new(@tls_certificate) if @tls_certificate
|
316
|
+
ctx.key = OpenSSL::PKey::RSA.new(@tls_key) if @tls_key
|
316
317
|
ctx.cert_store = if @tls_certificate_store
|
317
318
|
@tls_certificate_store
|
318
319
|
else
|
319
320
|
initialize_tls_certificate_store(@tls_ca_certificates)
|
320
321
|
end
|
321
322
|
|
323
|
+
if !@tls_certificate
|
324
|
+
@logger.warn <<-MSG
|
325
|
+
Using TLS but no client certificate is provided! If RabbitMQ is configured to verify peer
|
326
|
+
certificate, connection upgrade will fail!
|
327
|
+
MSG
|
328
|
+
end
|
329
|
+
if @tls_certificate && !@tls_key
|
330
|
+
@logger.warn "Using TLS but no client private key is provided!"
|
331
|
+
end
|
332
|
+
|
322
333
|
# setting TLS/SSL version only works correctly when done
|
323
334
|
# vis set_params. MK.
|
324
335
|
ctx.set_params(:ssl_version => @opts.fetch(:tls_protocol, DEFAULT_TLS_PROTOCOL))
|
data/lib/bunny/version.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
4
|
unless ENV["CI"]
|
5
|
-
describe "TLS connection to RabbitMQ" do
|
5
|
+
describe "TLS connection to RabbitMQ with client certificates" do
|
6
6
|
let(:connection) do
|
7
7
|
c = Bunny.new(:user => "bunny_gem",
|
8
8
|
:password => "bunny_password",
|
@@ -44,4 +44,46 @@ unless ENV["CI"]
|
|
44
44
|
ch.close
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
|
49
|
+
describe "TLS connection to RabbitMQ without client certificates" do
|
50
|
+
let(:connection) do
|
51
|
+
c = Bunny.new(:user => "bunny_gem",
|
52
|
+
:password => "bunny_password",
|
53
|
+
:vhost => "bunny_testbed",
|
54
|
+
:tls => true,
|
55
|
+
:tls_ca_certificates => ["./spec/tls/cacert.pem"])
|
56
|
+
c.start
|
57
|
+
c
|
58
|
+
end
|
59
|
+
|
60
|
+
after :all do
|
61
|
+
connection.close
|
62
|
+
end
|
63
|
+
|
64
|
+
it "provides the same API as a regular connection" do
|
65
|
+
ch = connection.create_channel
|
66
|
+
|
67
|
+
q = ch.queue("", :exclusive => true)
|
68
|
+
x = ch.default_exchange
|
69
|
+
|
70
|
+
x.publish("xyzzy", :routing_key => q.name).
|
71
|
+
publish("xyzzy", :routing_key => q.name).
|
72
|
+
publish("xyzzy", :routing_key => q.name).
|
73
|
+
publish("xyzzy", :routing_key => q.name)
|
74
|
+
|
75
|
+
sleep 0.5
|
76
|
+
q.message_count.should == 4
|
77
|
+
|
78
|
+
i = 0
|
79
|
+
q.subscribe do |delivery_info, _, payload|
|
80
|
+
i += 1
|
81
|
+
end
|
82
|
+
sleep 1.0
|
83
|
+
i.should == 4
|
84
|
+
q.message_count.should == 0
|
85
|
+
|
86
|
+
ch.close
|
87
|
+
end
|
88
|
+
end
|
47
89
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
unless RUBY_ENGINE == "jruby"
|
4
|
+
describe Bunny::Session do
|
5
|
+
4000.times do |i|
|
6
|
+
it "can be closed (take #{i})" do
|
7
|
+
c = Bunny.new(:automatically_recover => false)
|
8
|
+
c.start
|
9
|
+
ch = c.create_channel
|
10
|
+
|
11
|
+
c.should be_connected
|
12
|
+
c.stop
|
13
|
+
c.should be_closed
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Duncan
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2013-07-
|
15
|
+
date: 2013-07-26 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- spec/higher_level_api/integration/channel_open_spec.rb
|
138
138
|
- spec/higher_level_api/integration/confirm_select_spec.rb
|
139
139
|
- spec/higher_level_api/integration/connection_spec.rb
|
140
|
+
- spec/higher_level_api/integration/connection_stop_spec.rb
|
140
141
|
- spec/higher_level_api/integration/consistent_hash_exchange_spec.rb
|
141
142
|
- spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb
|
142
143
|
- spec/higher_level_api/integration/dead_lettering_spec.rb
|
@@ -172,6 +173,7 @@ files:
|
|
172
173
|
- spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb
|
173
174
|
- spec/stress/concurrent_consumers_stress_spec.rb
|
174
175
|
- spec/stress/concurrent_publishers_stress_spec.rb
|
176
|
+
- spec/stress/connection_open_close_spec.rb
|
175
177
|
- spec/stress/long_running_consumer_spec.rb
|
176
178
|
- spec/tls/cacert.pem
|
177
179
|
- spec/tls/client_cert.pem
|
@@ -223,6 +225,7 @@ test_files:
|
|
223
225
|
- spec/higher_level_api/integration/channel_open_spec.rb
|
224
226
|
- spec/higher_level_api/integration/confirm_select_spec.rb
|
225
227
|
- spec/higher_level_api/integration/connection_spec.rb
|
228
|
+
- spec/higher_level_api/integration/connection_stop_spec.rb
|
226
229
|
- spec/higher_level_api/integration/consistent_hash_exchange_spec.rb
|
227
230
|
- spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb
|
228
231
|
- spec/higher_level_api/integration/dead_lettering_spec.rb
|
@@ -258,6 +261,7 @@ test_files:
|
|
258
261
|
- spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb
|
259
262
|
- spec/stress/concurrent_consumers_stress_spec.rb
|
260
263
|
- spec/stress/concurrent_publishers_stress_spec.rb
|
264
|
+
- spec/stress/connection_open_close_spec.rb
|
261
265
|
- spec/stress/long_running_consumer_spec.rb
|
262
266
|
- spec/tls/cacert.pem
|
263
267
|
- spec/tls/client_cert.pem
|