bunny 1.0.0.pre1 → 1.0.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|