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