bunny 2.1.0 → 2.2.0
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 +15 -0
- data/README.md +1 -9
- data/bunny.gemspec +1 -7
- data/lib/bunny/consumer_work_pool.rb +12 -2
- data/lib/bunny/session.rb +64 -20
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/connection_spec.rb +53 -14
- metadata +3 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4513453ba83efb33a882a0360116c2d652deaeca
|
4
|
+
data.tar.gz: a5b1deb516b9a0798f02b394d78eabc3022e96ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71f26786c44ac4580a48cacb604dbeed272bab27005bbb3d4dc0816e10d02679e23adcd671898a8a8f12727c0a63fec16a15dddf1764f16cd13bec8d8a867cd8
|
7
|
+
data.tar.gz: 3ac225508d9a2bc13b1e24f98bb879e8a4ce500340abff9362e28c1fe9e106eff44a5d6b818df65a432eb3f0d48db9ff6db4760c91041b16e9558ffc092dd6fe
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## Changes between Bunny 2.1.0 and 2.2.0
|
2
|
+
|
3
|
+
### Add :addresses to connect options
|
4
|
+
|
5
|
+
Before this the connection options only allowed multiple hosts, an
|
6
|
+
address is a combination of a host and a port. This makes it possible to
|
7
|
+
specify different hosts with different ports.
|
8
|
+
|
9
|
+
### Recover from connection.close by default
|
10
|
+
|
11
|
+
Bunny will now try to reconnect also when server sent connection.close is
|
12
|
+
received, e.g. when a server is restarting (but also when the connection is
|
13
|
+
force closed by the server). This is in-line with how many other clients behave.
|
14
|
+
The old default was `recover_from_connection_close: false`.
|
15
|
+
|
1
16
|
## Changes between Bunny 2.0.0 and 2.1.0
|
2
17
|
|
3
18
|
Bunny 2.1.0 has an **important breaking change**. It is highly
|
data/README.md
CHANGED
@@ -68,14 +68,6 @@ Bunny `1.4.x` and earlier supports RabbitMQ 2.x and 3.x.
|
|
68
68
|
Bunny is a mature library (started in early 2009) with
|
69
69
|
a stable public API.
|
70
70
|
|
71
|
-
Before version 0.9, **a lot** of functionality was missing. Version
|
72
|
-
0.9 can be considered to be a "second birthday" for Bunny as it was
|
73
|
-
rewritten from scratch with over a dozen of preview releases over the
|
74
|
-
course of about a year.
|
75
|
-
|
76
|
-
We (the maintainers) made our best effort to keep the new version as
|
77
|
-
backwards compatible as possible but within reason.
|
78
|
-
|
79
71
|
|
80
72
|
## Installation & Bundler Dependency
|
81
73
|
|
@@ -96,7 +88,7 @@ gem install bunny
|
|
96
88
|
To use Bunny in a project managed with Bundler:
|
97
89
|
|
98
90
|
``` ruby
|
99
|
-
gem "bunny", ">= 2.0
|
91
|
+
gem "bunny", ">= 2.1.0"
|
100
92
|
```
|
101
93
|
|
102
94
|
|
data/bunny.gemspec
CHANGED
@@ -21,13 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Michael S. Klishin",
|
22
22
|
"Stefan Kaes"]
|
23
23
|
|
24
|
-
s.email = [
|
25
|
-
"Y2VsbGRlZUBnbWFpbC5jb20=\n",
|
26
|
-
"ZXJpY0A1c3RvcHMuY29t\n",
|
27
|
-
"c3Rhc3RueUAxMDFpZGVhcy5jeg==\n",
|
28
|
-
"bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n",
|
29
|
-
"c2thZXNAcmFpbHNleHByZXNzLmRl\n"].
|
30
|
-
map { |mail| Base64.decode64(mail) }
|
24
|
+
s.email = ["michael.s.klishin@gmail.com"]
|
31
25
|
|
32
26
|
# Dependencies
|
33
27
|
s.add_dependency "amq-protocol", ">= 2.0.0"
|
@@ -19,6 +19,7 @@ module Bunny
|
|
19
19
|
def initialize(size = 1)
|
20
20
|
@size = size
|
21
21
|
@queue = ::Queue.new
|
22
|
+
@paused = false
|
22
23
|
end
|
23
24
|
|
24
25
|
|
@@ -41,6 +42,14 @@ module Bunny
|
|
41
42
|
@running
|
42
43
|
end
|
43
44
|
|
45
|
+
def backlog
|
46
|
+
@queue.length
|
47
|
+
end
|
48
|
+
|
49
|
+
def busy?
|
50
|
+
!@queue.empty?
|
51
|
+
end
|
52
|
+
|
44
53
|
def shutdown
|
45
54
|
@running = false
|
46
55
|
|
@@ -57,12 +66,12 @@ module Bunny
|
|
57
66
|
|
58
67
|
def pause
|
59
68
|
@running = false
|
60
|
-
|
61
|
-
@threads.each { |t| t.stop }
|
69
|
+
@paused = true
|
62
70
|
end
|
63
71
|
|
64
72
|
def resume
|
65
73
|
@running = true
|
74
|
+
@paused = false
|
66
75
|
|
67
76
|
@threads.each { |t| t.run }
|
68
77
|
end
|
@@ -78,6 +87,7 @@ module Bunny
|
|
78
87
|
def run_loop
|
79
88
|
catch(:terminate) do
|
80
89
|
loop do
|
90
|
+
Thread.stop if @paused
|
81
91
|
callable = @queue.pop
|
82
92
|
|
83
93
|
begin
|
data/lib/bunny/session.rb
CHANGED
@@ -95,6 +95,7 @@ module Bunny
|
|
95
95
|
#
|
96
96
|
# @option connection_string_or_opts [String] :host ("127.0.0.1") Hostname or IP address to connect to
|
97
97
|
# @option connection_string_or_opts [Array<String>] :hosts (["127.0.0.1"]) list of hostname or IP addresses to select hostname from when connecting
|
98
|
+
# @option connection_string_or_opts [Array<String>] :addresses (["127.0.0.1:5672"]) list of addresses to select hostname and port from when connecting
|
98
99
|
# @option connection_string_or_opts [Integer] :port (5672) Port RabbitMQ listens on
|
99
100
|
# @option connection_string_or_opts [String] :username ("guest") Username
|
100
101
|
# @option connection_string_or_opts [String] :password ("guest") Password
|
@@ -113,8 +114,9 @@ module Bunny
|
|
113
114
|
# @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
|
114
115
|
# @option connection_string_or_opts [IO, String] :logfile DEPRECATED: use :log_file instead. The file or path to use when creating a logger. Defaults to STDOUT.
|
115
116
|
# @option connection_string_or_opts [Integer] :log_level The log level to use when creating a logger. Defaults to LOGGER::WARN
|
116
|
-
# @option connection_string_or_opts [Boolean] :automatically_recover Should automatically recover from network failures?
|
117
|
-
# @option connection_string_or_opts [Integer] :recovery_attempts Max number of recovery attempts
|
117
|
+
# @option connection_string_or_opts [Boolean] :automatically_recover (true) Should automatically recover from network failures?
|
118
|
+
# @option connection_string_or_opts [Integer] :recovery_attempts (nil) Max number of recovery attempts, nil means forever, 0 means never
|
119
|
+
# @option connection_string_or_opts [Boolean] :recover_from_connection_close (true) Recover from server-sent connection.close
|
118
120
|
#
|
119
121
|
# @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
|
120
122
|
# @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
|
@@ -135,10 +137,9 @@ module Bunny
|
|
135
137
|
@default_hosts_shuffle_strategy = Proc.new { |hosts| hosts.shuffle }
|
136
138
|
|
137
139
|
@opts = opts
|
138
|
-
@
|
139
|
-
@
|
140
|
+
@addresses = self.addresses_from(opts)
|
141
|
+
@address_index = 0
|
140
142
|
|
141
|
-
@port = self.port_from(opts)
|
142
143
|
@user = self.username_from(opts)
|
143
144
|
@pass = self.password_from(opts)
|
144
145
|
@vhost = self.vhost_from(opts)
|
@@ -148,6 +149,8 @@ module Bunny
|
|
148
149
|
log_level = opts[:log_level] || ENV["BUNNY_LOG_LEVEL"] || Logger::WARN
|
149
150
|
@logger = opts.fetch(:logger, init_default_logger(log_file, log_level))
|
150
151
|
|
152
|
+
validate_connection_options(opts)
|
153
|
+
|
151
154
|
# should automatic recovery from network failures be used?
|
152
155
|
@automatically_recover = if opts[:automatically_recover].nil? && opts[:automatic_recovery].nil?
|
153
156
|
true
|
@@ -156,7 +159,7 @@ module Bunny
|
|
156
159
|
end
|
157
160
|
@recovery_attempts = opts[:recovery_attempts]
|
158
161
|
@network_recovery_interval = opts.fetch(:network_recovery_interval, DEFAULT_NETWORK_RECOVERY_INTERVAL)
|
159
|
-
@recover_from_connection_close = opts.fetch(:recover_from_connection_close,
|
162
|
+
@recover_from_connection_close = opts.fetch(:recover_from_connection_close, true)
|
160
163
|
# in ms
|
161
164
|
@continuation_timeout = opts.fetch(:continuation_timeout, DEFAULT_CONTINUATION_TIMEOUT)
|
162
165
|
|
@@ -183,7 +186,7 @@ module Bunny
|
|
183
186
|
# the non-reentrant Ruby mutexes. MK.
|
184
187
|
@transport_mutex = @mutex_impl.new
|
185
188
|
@status_mutex = @mutex_impl.new
|
186
|
-
@
|
189
|
+
@address_index_mutex = @mutex_impl.new
|
187
190
|
|
188
191
|
@channels = Hash.new
|
189
192
|
|
@@ -193,6 +196,16 @@ module Bunny
|
|
193
196
|
self.initialize_transport
|
194
197
|
end
|
195
198
|
|
199
|
+
def validate_connection_options(options)
|
200
|
+
if options[:hosts] && options[:addresses]
|
201
|
+
raise ArgumentError, "Connection options can't contain hosts and addresses at the same time"
|
202
|
+
end
|
203
|
+
|
204
|
+
if (options[:host] || options[:hostname]) && (options[:hosts] || options[:addresses])
|
205
|
+
@logger.warn "The connection options contain both a host and an array of hosts, the single host is ignored."
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
196
209
|
# @return [String] RabbitMQ hostname (or IP address) used
|
197
210
|
def hostname; self.host; end
|
198
211
|
# @return [String] Username used
|
@@ -223,11 +236,15 @@ module Bunny
|
|
223
236
|
end
|
224
237
|
|
225
238
|
def host
|
226
|
-
@transport ? @transport.host : @
|
239
|
+
@transport ? @transport.host : host_from_address(@addresses[@address_index])
|
227
240
|
end
|
228
241
|
|
229
|
-
def
|
230
|
-
@
|
242
|
+
def port
|
243
|
+
@transport ? @transport.port : port_from_address(@addresses[@address_index])
|
244
|
+
end
|
245
|
+
|
246
|
+
def reset_address_index
|
247
|
+
@address_index_mutex.synchronize { @address_index = 0 }
|
231
248
|
end
|
232
249
|
|
233
250
|
# @private
|
@@ -293,7 +310,7 @@ module Bunny
|
|
293
310
|
raise
|
294
311
|
end
|
295
312
|
rescue HostListDepleted
|
296
|
-
self.
|
313
|
+
self.reset_address_index
|
297
314
|
@status_mutex.synchronize { @status = :not_connected }
|
298
315
|
raise TCPConnectionFailedForAllHosts
|
299
316
|
end
|
@@ -659,7 +676,7 @@ module Bunny
|
|
659
676
|
recover_channels
|
660
677
|
end
|
661
678
|
rescue HostListDepleted
|
662
|
-
|
679
|
+
reset_address_index
|
663
680
|
retry
|
664
681
|
rescue TCPConnectionFailedForAllHosts, TCPConnectionFailed, AMQ::Protocol::EmptyResponseError => e
|
665
682
|
@logger.warn "TCP connection failed, reconnecting in #{@network_recovery_interval} seconds"
|
@@ -744,10 +761,23 @@ module Bunny
|
|
744
761
|
end
|
745
762
|
|
746
763
|
# @private
|
747
|
-
def
|
748
|
-
options.fetch(:hosts_shuffle_strategy, @default_hosts_shuffle_strategy)
|
749
|
-
|
750
|
-
|
764
|
+
def addresses_from(options)
|
765
|
+
shuffle_strategy = options.fetch(:hosts_shuffle_strategy, @default_hosts_shuffle_strategy)
|
766
|
+
|
767
|
+
addresses = options[:host] || options[:hostname] || options[:addresses] ||
|
768
|
+
options[:hosts] || ["#{DEFAULT_HOST}:#{port_from(options)}"]
|
769
|
+
addresses = [addresses] unless addresses.is_a? Array
|
770
|
+
|
771
|
+
addresses.map! do |address|
|
772
|
+
host_with_port?(address) ? address : "#{address}:#{port_from(@opts)}"
|
773
|
+
end
|
774
|
+
|
775
|
+
shuffle_strategy.call addresses
|
776
|
+
end
|
777
|
+
|
778
|
+
# @private
|
779
|
+
def host_with_port?(address)
|
780
|
+
address.include? ':'
|
751
781
|
end
|
752
782
|
|
753
783
|
# @private
|
@@ -761,6 +791,16 @@ module Bunny
|
|
761
791
|
options.fetch(:port, fallback)
|
762
792
|
end
|
763
793
|
|
794
|
+
# @private
|
795
|
+
def host_from_address(address)
|
796
|
+
address.split(":")[0]
|
797
|
+
end
|
798
|
+
|
799
|
+
# @private
|
800
|
+
def port_from_address(address)
|
801
|
+
address.split(":")[1].to_i
|
802
|
+
end
|
803
|
+
|
764
804
|
# @private
|
765
805
|
def vhost_from(options)
|
766
806
|
options[:virtual_host] || options[:vhost] || DEFAULT_VHOST
|
@@ -946,7 +986,7 @@ module Bunny
|
|
946
986
|
# @api public
|
947
987
|
def to_s
|
948
988
|
oid = ("0x%x" % (self.object_id << 1))
|
949
|
-
"#<#{self.class.name}:#{oid} #{@user}@#{host}:#{
|
989
|
+
"#<#{self.class.name}:#{oid} #{@user}@#{host}:#{port}, vhost=#{@vhost}, addresses=[#{@addresses.join(',')}]>"
|
950
990
|
end
|
951
991
|
|
952
992
|
def inspect
|
@@ -1109,10 +1149,14 @@ module Bunny
|
|
1109
1149
|
|
1110
1150
|
# @private
|
1111
1151
|
def initialize_transport
|
1112
|
-
if
|
1113
|
-
@
|
1152
|
+
if address = @addresses[ @address_index ]
|
1153
|
+
@address_index_mutex.synchronize { @address_index += 1 }
|
1114
1154
|
@transport.close rescue nil # Let's make sure the previous transport socket is closed
|
1115
|
-
@transport = Transport.new(self,
|
1155
|
+
@transport = Transport.new(self,
|
1156
|
+
host_from_address(address),
|
1157
|
+
port_from_address(address),
|
1158
|
+
@opts.merge(:session_thread => @origin_thread)
|
1159
|
+
)
|
1116
1160
|
|
1117
1161
|
# Reset the cached progname for the logger only when no logger was provided
|
1118
1162
|
@default_logger.progname = self.to_s
|
data/lib/bunny/version.rb
CHANGED
@@ -19,7 +19,6 @@ describe Bunny::Session do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
22
|
it "handles amqp:// URIs w/o path part" do
|
24
23
|
session = described_class.new("amqp://127.0.0.1")
|
25
24
|
session.start
|
@@ -32,7 +31,6 @@ describe Bunny::Session do
|
|
32
31
|
session.close
|
33
32
|
end
|
34
33
|
|
35
|
-
|
36
34
|
context "when URI ends in a slash" do
|
37
35
|
it "parses vhost as an empty string" do
|
38
36
|
session = described_class.new("amqp://127.0.0.1/")
|
@@ -50,9 +48,6 @@ describe Bunny::Session do
|
|
50
48
|
end
|
51
49
|
end
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
51
|
context "initialized with all defaults" do
|
57
52
|
it "provides a way to fine tune socket options" do
|
58
53
|
conn = Bunny.new
|
@@ -156,7 +151,7 @@ describe Bunny::Session do
|
|
156
151
|
let(:hosts) { [host] }
|
157
152
|
let(:subject) { described_class.new(:hosts => hosts) }
|
158
153
|
|
159
|
-
it "uses hostname =
|
154
|
+
it "uses hostname = 192.168.1.10" do
|
160
155
|
expect(subject.host).to eq host
|
161
156
|
expect(subject.hostname).to eq host
|
162
157
|
end
|
@@ -171,6 +166,58 @@ describe Bunny::Session do
|
|
171
166
|
end
|
172
167
|
end
|
173
168
|
|
169
|
+
context "initialized with :addresses => [...]" do
|
170
|
+
after :each do
|
171
|
+
subject.close if subject.open?
|
172
|
+
end
|
173
|
+
|
174
|
+
let(:host) { "192.168.1.10" }
|
175
|
+
let(:port) { 5673 }
|
176
|
+
let(:address) { "#{host}:#{port}" }
|
177
|
+
let(:addresses) { [address] }
|
178
|
+
let(:subject) { described_class.new(:addresses => addresses) }
|
179
|
+
|
180
|
+
it "uses hostname = 192.168.1.10" do
|
181
|
+
expect(subject.host).to eq host
|
182
|
+
expect(subject.hostname).to eq host
|
183
|
+
end
|
184
|
+
|
185
|
+
it "uses port 5673" do
|
186
|
+
expect(subject.port).to eq port
|
187
|
+
end
|
188
|
+
|
189
|
+
it "uses username = guest" do
|
190
|
+
expect(subject.username).to eq username
|
191
|
+
expect(subject.user).to eq username
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "initialized with conflicting hosts and addresses" do
|
196
|
+
let(:host) { "192.168.1.10" }
|
197
|
+
let(:port) { 5673 }
|
198
|
+
let(:address) { "#{host}:#{port}" }
|
199
|
+
let(:io) { StringIO.new }
|
200
|
+
let(:logger) { ::Logger.new(io) }
|
201
|
+
|
202
|
+
it "raises an argument error when there is are hosts and an address" do
|
203
|
+
expect { described_class.new(addresses: [address], hosts: [host]) }.to raise_error(ArgumentError)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "logs a warning when there is a single host and an array" do
|
207
|
+
described_class.new(addresses: [address], host: host, logger: logger)
|
208
|
+
expect(io.string).to include 'WARN -- : The connection options contain '\
|
209
|
+
'both a host and an array of hosts, the single host is ignored.'
|
210
|
+
end
|
211
|
+
|
212
|
+
it "converts hosts in addresses to addresses" do
|
213
|
+
strategy = Proc.new { |addresses| addresses }
|
214
|
+
session = described_class.new(addresses: [address,host ], hosts_shuffle_strategy: strategy)
|
215
|
+
strategy = Proc.new { |addresses| addresses }
|
216
|
+
|
217
|
+
expect(session.to_s).to include 'addresses=[192.168.1.10:5673,192.168.1.10:5672]'
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
174
221
|
context "initialized with :channel_max => 4096" do
|
175
222
|
after :each do
|
176
223
|
subject.close if subject.open?
|
@@ -223,7 +270,6 @@ describe Bunny::Session do
|
|
223
270
|
end
|
224
271
|
end
|
225
272
|
|
226
|
-
|
227
273
|
context "initialized with :host => 127.0.0.1 and non-default credentials" do
|
228
274
|
after :each do
|
229
275
|
subject.close if subject.open?
|
@@ -276,7 +322,6 @@ describe Bunny::Session do
|
|
276
322
|
end
|
277
323
|
end
|
278
324
|
|
279
|
-
|
280
325
|
context "initialized with :host => 127.0.0.1 and non-default credentials (take 2)" do
|
281
326
|
after :each do
|
282
327
|
subject.close if subject.open?
|
@@ -324,8 +369,6 @@ describe Bunny::Session do
|
|
324
369
|
end
|
325
370
|
end
|
326
371
|
|
327
|
-
|
328
|
-
|
329
372
|
context "initialized with :host => 127.0.0.1 and non-default credentials (take 2)" do
|
330
373
|
after :each do
|
331
374
|
subject.close if subject.open?
|
@@ -362,8 +405,6 @@ describe Bunny::Session do
|
|
362
405
|
end
|
363
406
|
end
|
364
407
|
|
365
|
-
|
366
|
-
|
367
408
|
context "initialized with :host => 127.0.0.1 and INVALID credentials" do
|
368
409
|
let(:host) { "127.0.0.1" }
|
369
410
|
# see ./bin/ci/before_build
|
@@ -390,7 +431,6 @@ describe Bunny::Session do
|
|
390
431
|
end
|
391
432
|
end
|
392
433
|
|
393
|
-
|
394
434
|
context "initialized with unreachable host or port" do
|
395
435
|
it "fails to connect" do
|
396
436
|
expect do
|
@@ -422,7 +462,6 @@ describe Bunny::Session do
|
|
422
462
|
end
|
423
463
|
end
|
424
464
|
|
425
|
-
|
426
465
|
context "initialized with a custom logger object" do
|
427
466
|
let(:io) { StringIO.new }
|
428
467
|
let(:logger) { ::Logger.new(io) }
|
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.
|
4
|
+
version: 2.2.0
|
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: 2015-
|
15
|
+
date: 2015-09-05 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -31,11 +31,7 @@ dependencies:
|
|
31
31
|
description: Easy to use, feature complete Ruby client for RabbitMQ 3.3 and later
|
32
32
|
versions.
|
33
33
|
email:
|
34
|
-
-
|
35
|
-
- eric@5stops.com
|
36
|
-
- stastny@101ideas.cz
|
37
|
-
- michael@novemberain.com
|
38
|
-
- skaes@railsexpress.de
|
34
|
+
- michael.s.klishin@gmail.com
|
39
35
|
executables: []
|
40
36
|
extensions: []
|
41
37
|
extra_rdoc_files:
|