bunny 2.7.0 → 2.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f37583fb4c93085f91f358da46737f7e7e75db6a
4
- data.tar.gz: 0e76e67996978dffa4c80a3b91225c494e2d2b55
3
+ metadata.gz: 3f58b34695f1799decb5818ead7efbf21448656d
4
+ data.tar.gz: 4c8db08cd4581da8eab1bdd0afd81693d4042a55
5
5
  SHA512:
6
- metadata.gz: 01caa52176c8bec67e35c26964bc4e2c8aa5eaddea0503bc6c6b6b8b2b289894343baa260f68367fb00e80985accd0e48c17587916968cc75af78611e760c752
7
- data.tar.gz: ad6bf5194d91d866f340cc7688ac863d4062fed845a47c67794961f746dac8cd243fd634d5c552b3add73c1845f4f66a981cc51bbb88a62c22406f1a01a9666c
6
+ metadata.gz: 941c64ca6a10063df82456aec1f5dd4a44d5df67c6d9e74a73cfc41821b1b3d29f2ddfe260ea31434adb0697d5136d6cbc28e5a84e8adaca2b83d8897fb8d164
7
+ data.tar.gz: a3056eae41a6600aeed337094851c1f5f16e0f80e7b8170e2a7a18d22ac2caabdb0cf0ce69637c1f9f0ecdee7e693d1e9cf84dbc66ebfdd866bd6602a6b84a67
@@ -30,8 +30,10 @@ these. TLS (x509 PEM) certificates include a hostname-specific fields,
30
30
  the tests allow for expecting hostname overriding using the `BUNNY_RABBITMQ_HOSTNAME`
31
31
  environment variables (default value is `127.0.0.1`).
32
32
 
33
- Server, CA and client certificates can be found under `spec/tls`. They are supposed to be
34
- generated with [tls-gen](github.com/michaelklishin/tls-gen) or similar in the target environment.
33
+ Server, CA and client certificates can be found under `spec/tls`.
34
+ The location can be overridden via the `BUNNY_CERTIFICATE_DIR` environment variable.
35
+ It is supposed to target [tls-gen](https://github.com/michaelklishin/tls-gen)'s basic profile
36
+ output (result) directory on the host where specs are to be executed.
35
37
 
36
38
  Next up you'll need to prepare your node for the specs (just once):
37
39
 
@@ -1,8 +1,52 @@
1
- ## Changes between Bunny 2.7.0 and 2.8.0 (unreleased)
1
+ ## Changes between Bunny 2.7.1 and 2.7.2 (unreleased)
2
2
 
3
3
  No changes yet.
4
4
 
5
5
 
6
+ ## Changes between Bunny 2.7.0 and 2.7.1 (Sep 25th, 2017)
7
+
8
+ ### Sensible Socket Read Timeouts When RabbitMQ is Configured to Disabled Heartbeats
9
+
10
+ Bunny now correctly handles scenarios where server is configured
11
+ to disable heartbeats (which is a terrible idea, don't do it!)
12
+
13
+ GitHub issue: [#519](https://github.com/ruby-amqp/bunny/issues/519).
14
+
15
+ ### Bunny::Channel#basic_get Usability
16
+
17
+ `Bunny::Channel#basic_get` invoked with a non-existent queue now
18
+ throws a channel exception instead of a generic operation timeout.
19
+
20
+ GitHub issue: [#518](https://github.com/ruby-amqp/bunny/issues/518).
21
+
22
+ ### Spec Suite Improvements
23
+
24
+ `BUNNY_CERTIFICATE_DIR` environment variable now can be used
25
+ to override local CA and client certificate/key pair directory.
26
+ The directory is expected to be the result directory generated
27
+ by the basic [tls-gen](http://github.com/michaelklishin/tls-gen) profile.
28
+
29
+ TLSv1.0 is no longer used in tests because it's being disabled by default
30
+ by more and more installations as it has known vulnerabilities
31
+ and is no longer considered to be acceptable by several compliance
32
+ standards (e.g. PCI DSS).
33
+
34
+ ### Improved Synchronisation for channel.close Handlers
35
+
36
+ `channel.close` handler will now acquire a lock . This avoids concurrency
37
+ hazards in some rare scenarios when a channel is closed due a protocol
38
+ exception by the server and concurrently opened by user code
39
+ at the same time.
40
+
41
+ ### More Meaningful Error Messages in Bunny::Session#create_channel
42
+
43
+ Sometimes users attempt to open a channel on a connection that
44
+ isn't connected yet because `Bunny::Session#start` was never invoked.
45
+
46
+ `Bunny::Session#create_channel` will now provide a more sensible exception message
47
+ in those cases.
48
+
49
+
6
50
  ## Changes between Bunny 2.6.0 and 2.7.0 (May 11th, 2017)
7
51
 
8
52
  ### amq-protocol Update
data/README.md CHANGED
@@ -88,7 +88,7 @@ gem install bunny
88
88
  To use Bunny in a project managed with Bundler:
89
89
 
90
90
  ``` ruby
91
- gem "bunny", ">= 2.6.5"
91
+ gem "bunny", ">= 2.7.0"
92
92
  ```
93
93
 
94
94
 
@@ -602,7 +602,12 @@ module Bunny
602
602
  # we implement them). So we return a triple of nils immediately which apps should be
603
603
  # able to handle anyway as "got no message, no need to act". MK.
604
604
  last_basic_get_response = if @connection.open?
605
- wait_on_basic_get_continuations
605
+ begin
606
+ wait_on_basic_get_continuations
607
+ rescue Timeout::Error => e
608
+ raise_if_continuation_resulted_in_a_channel_error!
609
+ raise e
610
+ end
606
611
  else
607
612
  [nil, nil, nil]
608
613
  end
@@ -101,16 +101,18 @@ module Bunny
101
101
  # @option connection_string_or_opts [String] :username ("guest") Username
102
102
  # @option connection_string_or_opts [String] :password ("guest") Password
103
103
  # @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
104
- # @option connection_string_or_opts [Integer] :heartbeat (600) Heartbeat interval. 0 means no heartbeat.
104
+ # @option connection_string_or_opts [Integer, Symbol] :heartbeat (:server) Heartbeat interval. :server means use the default suggested by RabbitMQ. 0 means no heartbeat (not recommended).
105
105
  # @option connection_string_or_opts [Integer] :network_recovery_interval (4) Recovery interval periodic network recovery will use. This includes initial pause after network failure.
106
106
  # @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
107
107
  # @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
108
108
  # @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
109
109
  # @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
110
110
  # @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
111
- # @option connection_string_or_opts [Keyword] :tls_version (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
111
+ # @option connection_string_or_opts [Symbol] :tls_version (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
112
112
  # @option connection_string_or_opts [Integer] :continuation_timeout (15000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
113
- # @option connection_string_or_opts [Integer] :connection_timeout (5) Timeout in seconds for connecting to the server.
113
+ # @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
114
+ # @option connection_string_or_opts [Integer] :read_timeout (30) TCP socket read timeout in seconds.
115
+ # @option connection_string_or_opts [Integer] :write_timeout (30) TCP socket write timeout in seconds.
114
116
  # @option connection_string_or_opts [Proc] :hosts_shuffle_strategy A Proc that reorders a list of host strings, defaults to Array#shuffle
115
117
  # @option connection_string_or_opts [Logger] :logger The logger. If missing, one is created using :log_file and :log_level.
116
118
  # @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
@@ -346,6 +348,7 @@ module Bunny
346
348
  def create_channel(n = nil, consumer_pool_size = 1, consumer_pool_abort_on_exception = false, consumer_pool_shutdown_timeout = 60)
347
349
  raise ArgumentError, "channel number 0 is reserved in the protocol and cannot be used" if 0 == n
348
350
  raise ConnectionAlreadyClosed if manually_closed?
351
+ raise RuntimeError, "this connection is not open. Was Bunny::Session#start invoked? Is automatic recovery enabled?" if !connected?
349
352
 
350
353
  @channel_mutex.synchronize do
351
354
  if n && (ch = @channels[n])
@@ -540,6 +543,16 @@ module Bunny
540
543
  end
541
544
  end
542
545
 
546
+ # @private
547
+ def find_channel(number)
548
+ @channels[number]
549
+ end
550
+
551
+ # @private
552
+ def synchronised_find_channel(number)
553
+ @channel_mutex.synchronize { @channels[number] }
554
+ end
555
+
543
556
  # @private
544
557
  def close_all_channels
545
558
  @channel_mutex.synchronize do
@@ -606,15 +619,20 @@ module Bunny
606
619
  @unblock_callback.call(method) if @unblock_callback
607
620
  when AMQ::Protocol::Channel::Close then
608
621
  begin
609
- ch = @channels[ch_number]
622
+ ch = synchronised_find_channel(ch_number)
623
+ # this includes sending a channel.close-ok and
624
+ # potentially invoking a user-provided callback,
625
+ # avoid doing that while holding a mutex lock. MK.
610
626
  ch.handle_method(method)
611
627
  ensure
628
+ # synchronises on @channel_mutex under the hood
612
629
  self.unregister_channel(ch)
613
630
  end
614
631
  when AMQ::Protocol::Basic::GetEmpty then
615
- @channels[ch_number].handle_basic_get_empty(method)
632
+ ch = find_channel(ch_number)
633
+ ch.handle_basic_get_empty(method)
616
634
  else
617
- if ch = @channels[ch_number]
635
+ if ch = find_channel(ch_number)
618
636
  ch.handle_method(method)
619
637
  else
620
638
  @logger.warn "Channel #{ch_number} is not open on this connection!"
@@ -1161,11 +1179,18 @@ module Bunny
1161
1179
 
1162
1180
  # We set the read_write_timeout to twice the heartbeat value
1163
1181
  # This allows us to miss a single heartbeat before we time out the socket.
1164
- @transport.read_timeout = if heartbeat_disabled?(@client_heartbeat)
1182
+ #
1183
+ # Since RabbitMQ can be configured to disable heartbeats (bad idea but technically
1184
+ # possible nonetheless), we need to take both client and server values into
1185
+ # consideration when deciding about using the heartbeat value for read timeouts.
1186
+ @transport.read_timeout = if heartbeat_disabled?(@client_heartbeat) || heartbeat_disabled?(@heartbeat)
1187
+ @logger.debug { "Will use default socket read timeout of #{Transport::DEFAULT_READ_TIMEOUT}" }
1165
1188
  Transport::DEFAULT_READ_TIMEOUT
1166
1189
  else
1167
1190
  # pad to account for edge cases. MK.
1168
- @heartbeat * 2.2
1191
+ n = @heartbeat * 2.2
1192
+ @logger.debug { "Will use socket read timeout of #{n}" }
1193
+ n
1169
1194
  end
1170
1195
 
1171
1196
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Bunny
4
4
  # @return [String] Version of the library
5
- VERSION = "2.7.0"
5
+ VERSION = "2.7.1"
6
6
  end
@@ -54,3 +54,27 @@ describe Bunny::Queue, "#pop" do
54
54
  end
55
55
  end
56
56
  end
57
+
58
+
59
+ describe Bunny::Channel, "#basic_get" do
60
+ let(:connection) do
61
+ c = Bunny.new(username: "bunny_gem", password: "bunny_password", vhost: "bunny_testbed",
62
+ automatically_recover: false, continuation_timeout: 3000)
63
+ c.start
64
+ c
65
+ end
66
+
67
+ after :each do
68
+ connection.close if connection.open?
69
+ end
70
+
71
+ context "with a non-existent queue" do
72
+ it "throws a NOT_FOUND" do
73
+ ch = connection.create_channel
74
+
75
+ expect do
76
+ ch.basic_get "non_existent_#{rand.to_s}"
77
+ end.to raise_error(Bunny::NotFound)
78
+ end
79
+ end
80
+ end
@@ -2,10 +2,14 @@
2
2
  require "spec_helper"
3
3
 
4
4
  unless ENV["CI"]
5
+ CERTIFICATE_DIR=ENV.fetch("BUNNY_CERTIFICATE_DIR", "./spec/tls")
6
+ puts "Will use certificates from #{CERTIFICATE_DIR}"
7
+
5
8
  shared_examples_for "successful TLS connection" do
6
9
  it "succeeds" do
7
- expect(connection).to be_tls
8
- ch = connection.create_channel
10
+ expect(subject).to be_tls
11
+ ch = subject.create_channel
12
+ ch.confirm_select
9
13
 
10
14
  q = ch.queue("", exclusive: true)
11
15
  x = ch.default_exchange
@@ -15,7 +19,7 @@ unless ENV["CI"]
15
19
  publish("xyzzy", routing_key: q.name).
16
20
  publish("xyzzy", routing_key: q.name)
17
21
 
18
- sleep 0.5
22
+ x.wait_for_confirms
19
23
  expect(q.message_count).to eq 4
20
24
 
21
25
  i = 0
@@ -41,9 +45,9 @@ unless ENV["CI"]
41
45
  :vhost => "bunny_testbed",
42
46
  :tls => true,
43
47
  :verify_peer => verify_peer,
44
- :tls_cert => "spec/tls/client_certificate.pem",
45
- :tls_key => "spec/tls/client_key.pem",
46
- :tls_ca_certificates => ["./spec/tls/ca_certificate.pem"])
48
+ :tls_cert => "#{CERTIFICATE_DIR}/client_certificate.pem",
49
+ :tls_key => "#{CERTIFICATE_DIR}/client_key.pem",
50
+ :tls_ca_certificates => ["#{CERTIFICATE_DIR}/ca_certificate.pem"])
47
51
  end
48
52
 
49
53
  context "peer verification is off" do
@@ -58,6 +62,10 @@ unless ENV["CI"]
58
62
  subject.start
59
63
  expect(subject.transport.socket.hostname).to_not be_empty
60
64
  end
65
+
66
+ after :each do
67
+ subject.close
68
+ end
61
69
  end
62
70
 
63
71
  context "peer verification is on" do
@@ -70,21 +78,21 @@ unless ENV["CI"]
70
78
  end
71
79
 
72
80
  describe "TLS connection to RabbitMQ with client certificates" do
73
- let(:connection) do
81
+ let(:subject) do
74
82
  c = Bunny.new(username: "bunny_gem",
75
83
  password: "bunny_password",
76
84
  vhost: "bunny_testbed",
77
85
  tls: true,
78
- tls_cert: "spec/tls/client_certificate.pem",
79
- tls_key: "spec/tls/client_key.pem",
80
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
86
+ tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
87
+ tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
88
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
81
89
  verify_peer: false)
82
90
  c.start
83
91
  c
84
92
  end
85
93
 
86
94
  after :each do
87
- connection.close
95
+ subject.close
88
96
  end
89
97
 
90
98
  include_examples "successful TLS connection"
@@ -92,19 +100,19 @@ unless ENV["CI"]
92
100
 
93
101
 
94
102
  describe "TLS connection to RabbitMQ without client certificates" do
95
- let(:connection) do
103
+ let(:subject) do
96
104
  c = Bunny.new(username: "bunny_gem",
97
105
  password: "bunny_password",
98
106
  vhost: "bunny_testbed",
99
107
  tls: true,
100
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
108
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
101
109
  verify_peer: false)
102
110
  c.start
103
111
  c
104
112
  end
105
113
 
106
114
  after :each do
107
- connection.close
115
+ subject.close
108
116
  end
109
117
 
110
118
  include_examples "successful TLS connection"
@@ -112,18 +120,18 @@ unless ENV["CI"]
112
120
 
113
121
 
114
122
  describe "TLS connection to RabbitMQ with a connection string" do
115
- let(:connection) do
123
+ let(:subject) do
116
124
  c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname}/bunny_testbed",
117
- tls_cert: "spec/tls/client_certificate.pem",
118
- tls_key: "spec/tls/client_key.pem",
119
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
125
+ tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
126
+ tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
127
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
120
128
  verify_peer: false)
121
129
  c.start
122
130
  c
123
131
  end
124
132
 
125
133
  after :each do
126
- connection.close
134
+ subject.close
127
135
  end
128
136
 
129
137
  include_examples "successful TLS connection"
@@ -131,16 +139,16 @@ unless ENV["CI"]
131
139
 
132
140
 
133
141
  describe "TLS connection to RabbitMQ with a connection string and w/o client certificate and key" do
134
- let(:connection) do
142
+ let(:subject) do
135
143
  c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname}/bunny_testbed",
136
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
144
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
137
145
  verify_peer: verify_peer)
138
146
  c.start
139
147
  c
140
148
  end
141
149
 
142
150
  after :each do
143
- connection.close
151
+ subject.close
144
152
  end
145
153
 
146
154
  context "peer verification is off" do
@@ -150,7 +158,7 @@ unless ENV["CI"]
150
158
 
151
159
  it "sends the SNI details" do
152
160
  # https://github.com/ruby-amqp/bunny/issues/440
153
- expect(connection.transport.socket.hostname).to_not be_empty
161
+ expect(subject.transport.socket.hostname).to_not be_empty
154
162
  end
155
163
  end
156
164
 
@@ -161,54 +169,54 @@ unless ENV["CI"]
161
169
 
162
170
  it "sends the SNI details" do
163
171
  # https://github.com/ruby-amqp/bunny/issues/440
164
- expect(connection.transport.socket.hostname).to_not be_empty
172
+ expect(subject.transport.socket.hostname).to_not be_empty
165
173
  end
166
174
  end
167
175
  end
168
176
 
169
177
 
170
178
  describe "TLS connection to RabbitMQ with client certificates provided inline" do
171
- let(:connection) do
179
+ let(:subject) do
172
180
  c = Bunny.new(username: "bunny_gem",
173
181
  password: "bunny_password",
174
182
  vhost: "bunny_testbed",
175
183
  tls: true,
176
- tls_cert: File.read("./spec/tls/client_certificate.pem"),
177
- tls_key: File.read("./spec/tls/client_key.pem"),
178
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
184
+ tls_cert: File.read("#{CERTIFICATE_DIR}/client_certificate.pem"),
185
+ tls_key: File.read("#{CERTIFICATE_DIR}/client_key.pem"),
186
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
179
187
  verify_peer: false)
180
188
  c.start
181
189
  c
182
190
  end
183
191
 
184
192
  after :each do
185
- connection.close
193
+ subject.close
186
194
  end
187
195
 
188
196
  include_examples "successful TLS connection"
189
197
  end
190
198
 
191
- describe "TLS connection to RabbitMQ with tls_version TLSv1 specified" do
192
- let(:connection) do
199
+ describe "TLS connection to RabbitMQ with tls_version TLSv1.1 specified" do
200
+ let(:subject) do
193
201
  c = Bunny.new(username: "bunny_gem",
194
202
  password: "bunny_password",
195
203
  vhost: "bunny_testbed",
196
204
  tls: true,
197
- tls_protocol: :TLSv1,
198
- tls_ca_certificates: ["./spec/tls/ca_certificate.pem"],
205
+ tls_protocol: :TLSv1_1,
206
+ tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
199
207
  verify_peer: false)
200
208
  c.start
201
209
  c
202
210
  end
203
211
 
204
212
  after :each do
205
- connection.close
213
+ subject.close
206
214
  end
207
215
 
208
216
  include_examples "successful TLS connection"
209
217
 
210
- it "connects using TLSv1" do
211
- expect(connection.transport.socket.ssl_version).to eq "TLSv1"
218
+ it "connects using TLSv1.1" do
219
+ expect(subject.transport.socket.ssl_version).to eq "TLSv1.1"
212
220
  end
213
221
  end
214
222
  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: 2.7.0
4
+ version: 2.7.1
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: 2017-05-10 00:00:00.000000000 Z
15
+ date: 2017-09-24 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: amq-protocol
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  version: '0'
232
232
  requirements: []
233
233
  rubyforge_project:
234
- rubygems_version: 2.6.11
234
+ rubygems_version: 2.6.13
235
235
  signing_key:
236
236
  specification_version: 4
237
237
  summary: Popular easy to use Ruby client for RabbitMQ