bunny 2.0.0.rc1 → 2.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -6
- data/ChangeLog.md +35 -2
- data/Gemfile +0 -2
- data/README.md +3 -1
- data/lib/bunny/channel.rb +27 -28
- data/lib/bunny/cruby/socket.rb +13 -16
- data/lib/bunny/cruby/ssl_socket.rb +2 -7
- data/lib/bunny/session.rb +16 -7
- data/lib/bunny/timeout.rb +1 -12
- data/lib/bunny/transport.rb +3 -3
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/basic_ack_spec.rb +132 -0
- data/spec/higher_level_api/integration/basic_nack_spec.rb +5 -2
- data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -89
- data/spec/higher_level_api/integration/basic_reject_spec.rb +79 -1
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +19 -0
- data/spec/spec_helper.rb +0 -13
- metadata +2 -5
- data/lib/bunny/system_timer.rb +0 -20
- data/spec/unit/system_timer_spec.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0c99fb0a3faf8edcc73da84f74ce724e77b71a1
|
4
|
+
data.tar.gz: 4c50a4aa3b4b6bb70ae4f9f8d4305914c24e9f1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 717ee6c9d892e4d930464b2122ffbd2059420553c4b3f3ec670d6b66331d9885feeac96eb0edf7f2da1fcf11ef77bc05e3b2beacfbb7f96a19a7e780b2fb3ea5
|
7
|
+
data.tar.gz: 3b24edbe00fbbb46a20592bb5cc28bc5f00fa6fb05180a5b91405f2534c9c4a8d8e3b0b9ab12e1f6213a501f3cc2cab374e00a3bc3a31ba79281efa7e9e0a8d1
|
data/.travis.yml
CHANGED
@@ -3,13 +3,11 @@ bundler_args: --without development
|
|
3
3
|
before_script: "./bin/ci/before_build"
|
4
4
|
script: "bundle exec rspec -cf documentation spec"
|
5
5
|
rvm:
|
6
|
-
- "2.
|
6
|
+
- "2.2"
|
7
|
+
- "2.1"
|
7
8
|
- "2.0"
|
8
|
-
- "1.9.3"
|
9
9
|
- "jruby"
|
10
|
-
- "1.9.2"
|
11
10
|
- "rbx"
|
12
|
-
- "1.8.7"
|
13
11
|
notifications:
|
14
12
|
email: michael@rabbitmq.com
|
15
13
|
services:
|
@@ -21,6 +19,4 @@ branches:
|
|
21
19
|
matrix:
|
22
20
|
allow_failures:
|
23
21
|
- rvm: rbx
|
24
|
-
- rvm: "1.9.2"
|
25
|
-
- rvm: "1.8.7"
|
26
22
|
- rvm: jruby
|
data/ChangeLog.md
CHANGED
@@ -1,4 +1,21 @@
|
|
1
|
-
## Changes between Bunny 1.7.0 and
|
1
|
+
## Changes between Bunny 1.7.0 and 2.0.0
|
2
|
+
|
3
|
+
Bunny `2.0` doesn't have any breaking API changes
|
4
|
+
but drops Ruby 1.8 and 1.9 (both EOL'ed) support,
|
5
|
+
hence the version.
|
6
|
+
|
7
|
+
### Minimum Required Ruby Version is 2.0
|
8
|
+
|
9
|
+
Bunny `2.0` requires Ruby 2.0 or later.
|
10
|
+
|
11
|
+
## Non-Blocking Writes
|
12
|
+
|
13
|
+
Bunny now uses non-blocking socket writes, uses a reduced
|
14
|
+
number of writes for message publishing (frames are batched
|
15
|
+
into a single write), and handles TCP back pressure from
|
16
|
+
RabbitMQ better.
|
17
|
+
|
18
|
+
Contributed by Irina Bednova and Michael Klishin.
|
2
19
|
|
3
20
|
### Reduced Timeout Use
|
4
21
|
|
@@ -6,7 +23,23 @@
|
|
6
23
|
numerous issues, including starting a new "interruptor" thread per operation,
|
7
24
|
which is far from efficient.
|
8
25
|
|
9
|
-
Contributed by Joe Eli McIlvain.
|
26
|
+
Contributed by Joe Eli McIlvain and Carl Hörberg.
|
27
|
+
|
28
|
+
### Capped Number of Connection Recovery Attempts
|
29
|
+
|
30
|
+
`:recovery_attempts` is a new option that limits the number of
|
31
|
+
connection recovery attempts performed by Bunny. `nil` means
|
32
|
+
"no limit".
|
33
|
+
|
34
|
+
Contributed by Irina Bednova.
|
35
|
+
|
36
|
+
### Bunny::Channel#basic_ack and Related Methods Improvements
|
37
|
+
|
38
|
+
`Bunny::Channel#basic_ack`, `Bunny::Channel#basic_nack`, and `Bunny::Channel#basic_reject`
|
39
|
+
now adjust delivery tags between connection recoveries, as well as have a default value for
|
40
|
+
the second argument.
|
41
|
+
|
42
|
+
Contributed by Wayne Conrad.
|
10
43
|
|
11
44
|
### Logger Output Remains Consistent
|
12
45
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -48,13 +48,15 @@ Specific examples:
|
|
48
48
|
|
49
49
|
Modern Bunny versions support
|
50
50
|
|
51
|
-
* CRuby 2.2, 2.1, 2.0
|
51
|
+
* CRuby 2.2, 2.1, 2.0
|
52
52
|
* Rubinius 2.0+
|
53
53
|
|
54
54
|
Bunny works sufficiently well on JRuby but there are known
|
55
55
|
JRuby bugs that cause high CPU burn. JRuby users should
|
56
56
|
use [March Hare](http://rubymarchhare.info).
|
57
57
|
|
58
|
+
Bunny `1.7.x` was the last version to support CRuby 1.9.3 and 1.8.7
|
59
|
+
|
58
60
|
|
59
61
|
## Supported RabbitMQ Versions
|
60
62
|
|
data/lib/bunny/channel.rb
CHANGED
@@ -468,9 +468,7 @@ module Bunny
|
|
468
468
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
469
469
|
# @api public
|
470
470
|
def reject(delivery_tag, requeue = false)
|
471
|
-
|
472
|
-
basic_reject(delivery_tag.to_i, requeue)
|
473
|
-
end
|
471
|
+
basic_reject(delivery_tag.to_i, requeue)
|
474
472
|
end
|
475
473
|
|
476
474
|
# Acknowledges a message. Acknowledged messages are completely removed from the queue.
|
@@ -481,9 +479,7 @@ module Bunny
|
|
481
479
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
482
480
|
# @api public
|
483
481
|
def ack(delivery_tag, multiple = false)
|
484
|
-
|
485
|
-
basic_ack(delivery_tag.to_i, multiple)
|
486
|
-
end
|
482
|
+
basic_ack(delivery_tag.to_i, multiple)
|
487
483
|
end
|
488
484
|
alias acknowledge ack
|
489
485
|
|
@@ -498,9 +494,7 @@ module Bunny
|
|
498
494
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
499
495
|
# @api public
|
500
496
|
def nack(delivery_tag, multiple = false, requeue = false)
|
501
|
-
|
502
|
-
basic_nack(delivery_tag.to_i, multiple, requeue)
|
503
|
-
end
|
497
|
+
basic_nack(delivery_tag.to_i, multiple, requeue)
|
504
498
|
end
|
505
499
|
|
506
500
|
# @endgroup
|
@@ -570,7 +564,7 @@ module Bunny
|
|
570
564
|
opts[:mandatory],
|
571
565
|
false,
|
572
566
|
@connection.frame_max)
|
573
|
-
@connection.
|
567
|
+
@connection.send_frameset(frames, self)
|
574
568
|
|
575
569
|
self
|
576
570
|
end
|
@@ -707,11 +701,13 @@ module Bunny
|
|
707
701
|
# @see Bunny::Channel#basic_nack
|
708
702
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
709
703
|
# @api public
|
710
|
-
def basic_reject(delivery_tag, requeue)
|
711
|
-
|
712
|
-
|
704
|
+
def basic_reject(delivery_tag, requeue = false)
|
705
|
+
guarding_against_stale_delivery_tags(delivery_tag) do
|
706
|
+
raise_if_no_longer_open!
|
707
|
+
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
713
708
|
|
714
|
-
|
709
|
+
nil
|
710
|
+
end
|
715
711
|
end
|
716
712
|
|
717
713
|
# Acknowledges a delivery (message).
|
@@ -727,7 +723,7 @@ module Bunny
|
|
727
723
|
# ch = conn.create_channel
|
728
724
|
# q.subscribe do |delivery_info, properties, payload|
|
729
725
|
# # requeue the message
|
730
|
-
# ch.basic_ack(delivery_info.delivery_tag)
|
726
|
+
# ch.basic_ack(delivery_info.delivery_tag.to_i)
|
731
727
|
# end
|
732
728
|
#
|
733
729
|
# @example Ack a message fetched via basic.get
|
@@ -737,7 +733,7 @@ module Bunny
|
|
737
733
|
# ch = conn.create_channel
|
738
734
|
# # we assume the queue exists and has messages
|
739
735
|
# delivery_info, properties, payload = ch.basic_get("bunny.examples.queue3", :manual_ack => true)
|
740
|
-
# ch.basic_ack(delivery_info.delivery_tag)
|
736
|
+
# ch.basic_ack(delivery_info.delivery_tag.to_i)
|
741
737
|
#
|
742
738
|
# @example Ack multiple messages fetched via basic.get
|
743
739
|
# conn = Bunny.new
|
@@ -749,16 +745,17 @@ module Bunny
|
|
749
745
|
# _, _, payload2 = ch.basic_get("bunny.examples.queue3", :manual_ack => true)
|
750
746
|
# delivery_info, properties, payload3 = ch.basic_get("bunny.examples.queue3", :manual_ack => true)
|
751
747
|
# # ack all fetched messages up to payload3
|
752
|
-
# ch.basic_ack(delivery_info.delivery_tag, true)
|
748
|
+
# ch.basic_ack(delivery_info.delivery_tag.to_i, true)
|
753
749
|
#
|
754
750
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
755
|
-
# @see #basic_ack_known_delivery_tag
|
756
751
|
# @api public
|
757
|
-
def basic_ack(delivery_tag, multiple)
|
758
|
-
|
759
|
-
|
752
|
+
def basic_ack(delivery_tag, multiple = false)
|
753
|
+
guarding_against_stale_delivery_tags(delivery_tag) do
|
754
|
+
raise_if_no_longer_open!
|
755
|
+
@connection.send_frame(AMQ::Protocol::Basic::Ack.encode(@id, delivery_tag, multiple))
|
760
756
|
|
761
|
-
|
757
|
+
nil
|
758
|
+
end
|
762
759
|
end
|
763
760
|
|
764
761
|
# Rejects or requeues messages just like {Bunny::Channel#basic_reject} but can do so
|
@@ -815,13 +812,15 @@ module Bunny
|
|
815
812
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
816
813
|
# @api public
|
817
814
|
def basic_nack(delivery_tag, multiple = false, requeue = false)
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
815
|
+
guarding_against_stale_delivery_tags(delivery_tag) do
|
816
|
+
raise_if_no_longer_open!
|
817
|
+
@connection.send_frame(AMQ::Protocol::Basic::Nack.encode(@id,
|
818
|
+
delivery_tag,
|
819
|
+
multiple,
|
820
|
+
requeue))
|
823
821
|
|
824
|
-
|
822
|
+
nil
|
823
|
+
end
|
825
824
|
end
|
826
825
|
|
827
826
|
# Registers a consumer for queue. Delivered messages will be handled with the block
|
data/lib/bunny/cruby/socket.rb
CHANGED
@@ -6,27 +6,24 @@ module Bunny
|
|
6
6
|
#
|
7
7
|
# Heavily inspired by Dalli by Mike Perham.
|
8
8
|
# @private
|
9
|
-
|
9
|
+
module Socket
|
10
10
|
attr_accessor :options
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
|
15
|
-
|
16
|
-
# IO::WaitWritable is 1.9+ only
|
17
|
-
WRITE_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
|
18
|
-
WRITE_RETRY_EXCEPTION_CLASSES << IO::WaitWritable if IO.const_defined?(:WaitWritable)
|
12
|
+
READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable]
|
13
|
+
WRITE_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
|
19
14
|
|
20
15
|
def self.open(host, port, options = {})
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
|
27
|
-
sock.options = {:host => host, :port => port}.merge(options)
|
28
|
-
sock
|
16
|
+
socket = ::Socket.tcp(host, port, nil, nil,
|
17
|
+
connect_timeout: options[:connect_timeout])
|
18
|
+
if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
|
19
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
29
20
|
end
|
21
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
|
22
|
+
socket.extend self
|
23
|
+
socket.options = { :host => host, :port => port }.merge(options)
|
24
|
+
socket
|
25
|
+
rescue Errno::ETIMEDOUT
|
26
|
+
raise ClientTimeout
|
30
27
|
end
|
31
28
|
|
32
29
|
# Reads given number of bytes with an optional timeout
|
@@ -8,13 +8,8 @@ module Bunny
|
|
8
8
|
# methods found in Bunny::Socket.
|
9
9
|
class SSLSocket < OpenSSL::SSL::SSLSocket
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
|
14
|
-
|
15
|
-
# IO::WaitWritable is 1.9+ only
|
16
|
-
WRITE_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
|
17
|
-
WRITE_RETRY_EXCEPTION_CLASSES << IO::WaitWritable if IO.const_defined?(:WaitWritable)
|
11
|
+
READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable]
|
12
|
+
WRITE_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
|
18
13
|
|
19
14
|
# Reads given number of bytes with an optional timeout
|
20
15
|
#
|
data/lib/bunny/session.rb
CHANGED
@@ -46,11 +46,7 @@ module Bunny
|
|
46
46
|
CONNECT_TIMEOUT = Transport::DEFAULT_CONNECTION_TIMEOUT
|
47
47
|
|
48
48
|
# @private
|
49
|
-
DEFAULT_CONTINUATION_TIMEOUT =
|
50
|
-
8000
|
51
|
-
else
|
52
|
-
4000
|
53
|
-
end
|
49
|
+
DEFAULT_CONTINUATION_TIMEOUT = 15000
|
54
50
|
|
55
51
|
# RabbitMQ client metadata
|
56
52
|
DEFAULT_CLIENT_PROPERTIES = {
|
@@ -117,6 +113,8 @@ module Bunny
|
|
117
113
|
# @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
|
118
114
|
# @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.
|
119
115
|
# @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
|
120
118
|
#
|
121
119
|
# @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
|
122
120
|
# @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
|
@@ -156,6 +154,7 @@ module Bunny
|
|
156
154
|
else
|
157
155
|
opts[:automatically_recover] || opts[:automatic_recovery]
|
158
156
|
end
|
157
|
+
@recovery_attempts = opts[:recovery_attempts]
|
159
158
|
@network_recovery_interval = opts.fetch(:network_recovery_interval, DEFAULT_NETWORK_RECOVERY_INTERVAL)
|
160
159
|
@recover_from_connection_close = opts.fetch(:recover_from_connection_close, false)
|
161
160
|
# in ms
|
@@ -665,10 +664,18 @@ module Bunny
|
|
665
664
|
rescue TCPConnectionFailedForAllHosts, TCPConnectionFailed, AMQ::Protocol::EmptyResponseError => e
|
666
665
|
@logger.warn "TCP connection failed, reconnecting in #{@network_recovery_interval} seconds"
|
667
666
|
sleep @network_recovery_interval
|
668
|
-
|
667
|
+
if should_retry_recovery?
|
668
|
+
@recovery_attempts -= 1 if @recovery_attempts
|
669
|
+
retry if recoverable_network_failure?(e)
|
670
|
+
end
|
669
671
|
end
|
670
672
|
end
|
671
673
|
|
674
|
+
# @private
|
675
|
+
def should_retry_recovery?
|
676
|
+
@recovery_attempts.nil? || @recovery_attempts > 1
|
677
|
+
end
|
678
|
+
|
672
679
|
# @private
|
673
680
|
def recover_channels
|
674
681
|
# default channel is reopened right after connection
|
@@ -898,7 +905,9 @@ module Bunny
|
|
898
905
|
# If we synchronize on the channel, however, this is both thread safe and pretty fine-grained
|
899
906
|
# locking. Note that "single frame" methods do not need this kind of synchronization. MK.
|
900
907
|
channel.synchronize do
|
901
|
-
|
908
|
+
# see rabbitmq/rabbitmq-server#156
|
909
|
+
data = frames.reduce("") { |acc, frame| acc << frame.encode }
|
910
|
+
@transport.write(data)
|
902
911
|
signal_activity!
|
903
912
|
end
|
904
913
|
end # send_frameset(frames)
|
data/lib/bunny/timeout.rb
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
module Bunny
|
2
|
-
|
3
|
-
# Ruby 1.8) and SystemTimer (the gem)
|
4
|
-
Timeout = if RUBY_VERSION < "1.9"
|
5
|
-
begin
|
6
|
-
require "bunny/system_timer"
|
7
|
-
Bunny::SystemTimer
|
8
|
-
rescue LoadError
|
9
|
-
Timeout
|
10
|
-
end
|
11
|
-
else
|
12
|
-
Timeout
|
13
|
-
end
|
2
|
+
Timeout = ::Timeout
|
14
3
|
|
15
4
|
# Backwards compatibility
|
16
5
|
# @private
|
data/lib/bunny/transport.rb
CHANGED
@@ -20,10 +20,10 @@ module Bunny
|
|
20
20
|
#
|
21
21
|
|
22
22
|
# Default TCP connection timeout
|
23
|
-
DEFAULT_CONNECTION_TIMEOUT =
|
23
|
+
DEFAULT_CONNECTION_TIMEOUT = 30.0
|
24
24
|
|
25
|
-
DEFAULT_READ_TIMEOUT =
|
26
|
-
DEFAULT_WRITE_TIMEOUT =
|
25
|
+
DEFAULT_READ_TIMEOUT = 30.0
|
26
|
+
DEFAULT_WRITE_TIMEOUT = 30.0
|
27
27
|
|
28
28
|
attr_reader :session, :host, :port, :socket, :connect_timeout, :read_timeout, :write_timeout, :disconnect_timeout
|
29
29
|
attr_reader :tls_context
|
data/lib/bunny/version.rb
CHANGED
@@ -23,12 +23,60 @@ describe Bunny::Channel, "#ack" do
|
|
23
23
|
delivery_details, properties, content = q.pop(:manual_ack => true)
|
24
24
|
|
25
25
|
ch.ack(delivery_details.delivery_tag, true)
|
26
|
+
ch.close
|
27
|
+
|
28
|
+
ch = connection.create_channel
|
29
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
26
30
|
expect(q.message_count).to eq 0
|
31
|
+
ch.close
|
32
|
+
end
|
33
|
+
end
|
27
34
|
|
35
|
+
context "with a valid (known) delivery tag (multiple = true)" do
|
36
|
+
it "acknowledges a message" do
|
37
|
+
ch = connection.create_channel
|
38
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
39
|
+
x = ch.default_exchange
|
40
|
+
|
41
|
+
x.publish("bunneth", :routing_key => q.name)
|
42
|
+
x.publish("bunneth", :routing_key => q.name)
|
43
|
+
sleep 0.5
|
44
|
+
expect(q.message_count).to eq 2
|
45
|
+
delivery_details_1, _properties, _content = q.pop(:manual_ack => true)
|
46
|
+
delivery_details_2, _properties, _content = q.pop(:manual_ack => true)
|
47
|
+
|
48
|
+
ch.ack(delivery_details_2.delivery_tag, true)
|
49
|
+
ch.close
|
50
|
+
|
51
|
+
ch = connection.create_channel
|
52
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
53
|
+
expect(q.message_count).to eq 0
|
28
54
|
ch.close
|
29
55
|
end
|
30
56
|
end
|
31
57
|
|
58
|
+
context "with a valid (known) delivery tag (multiple = false)" do
|
59
|
+
it "acknowledges a message" do
|
60
|
+
ch = connection.create_channel
|
61
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
62
|
+
x = ch.default_exchange
|
63
|
+
|
64
|
+
x.publish("bunneth", :routing_key => q.name)
|
65
|
+
x.publish("bunneth", :routing_key => q.name)
|
66
|
+
sleep 0.5
|
67
|
+
expect(q.message_count).to eq 2
|
68
|
+
delivery_details_1, _properties, _content = q.pop(:manual_ack => true)
|
69
|
+
delivery_details_2, _properties, _content = q.pop(:manual_ack => true)
|
70
|
+
|
71
|
+
ch.ack(delivery_details_2.delivery_tag, false)
|
72
|
+
ch.close
|
73
|
+
|
74
|
+
ch = connection.create_channel
|
75
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
76
|
+
expect(q.message_count).to eq 1
|
77
|
+
ch.close
|
78
|
+
end
|
79
|
+
end
|
32
80
|
|
33
81
|
context "with a valid (known) delivery tag and automatic ack mode" do
|
34
82
|
it "results in a channel exception" do
|
@@ -90,8 +138,92 @@ describe Bunny::Channel, "#ack" do
|
|
90
138
|
$stderr = orig_stderr
|
91
139
|
|
92
140
|
ch.ack(delivery_details.delivery_tag, true)
|
141
|
+
ch.close
|
142
|
+
|
143
|
+
ch = connection.create_channel
|
144
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
145
|
+
expect(q.message_count).to eq 0
|
146
|
+
ch.close
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe Bunny::Channel, "#basic_ack" do
|
152
|
+
let(:connection) do
|
153
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
154
|
+
c.start
|
155
|
+
c
|
156
|
+
end
|
157
|
+
|
158
|
+
after :each do
|
159
|
+
connection.close if connection.open?
|
160
|
+
end
|
161
|
+
|
162
|
+
context "with a valid (known) delivery tag (multiple = true)" do
|
163
|
+
it "acknowledges a message" do
|
164
|
+
ch = connection.create_channel
|
165
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
166
|
+
x = ch.default_exchange
|
167
|
+
|
168
|
+
x.publish("bunneth", :routing_key => q.name)
|
169
|
+
x.publish("bunneth", :routing_key => q.name)
|
170
|
+
sleep 0.5
|
171
|
+
expect(q.message_count).to eq 2
|
172
|
+
delivery_details_1, _properties, _content = q.pop(:manual_ack => true)
|
173
|
+
delivery_details_2, _properties, _content = q.pop(:manual_ack => true)
|
174
|
+
|
175
|
+
ch.basic_ack(delivery_details_2.delivery_tag.to_i, true)
|
176
|
+
ch.close
|
177
|
+
|
178
|
+
ch = connection.create_channel
|
179
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
93
180
|
expect(q.message_count).to eq 0
|
181
|
+
ch.close
|
182
|
+
end
|
183
|
+
end
|
94
184
|
|
185
|
+
context "with a valid (known) delivery tag (multiple = false)" do
|
186
|
+
it "acknowledges a message" do
|
187
|
+
ch = connection.create_channel
|
188
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
189
|
+
x = ch.default_exchange
|
190
|
+
|
191
|
+
x.publish("bunneth", :routing_key => q.name)
|
192
|
+
x.publish("bunneth", :routing_key => q.name)
|
193
|
+
sleep 0.5
|
194
|
+
expect(q.message_count).to eq 2
|
195
|
+
delivery_details_1, _properties, _content = q.pop(:manual_ack => true)
|
196
|
+
delivery_details_2, _properties, _content = q.pop(:manual_ack => true)
|
197
|
+
|
198
|
+
ch.basic_ack(delivery_details_2.delivery_tag.to_i, false)
|
199
|
+
ch.close
|
200
|
+
|
201
|
+
ch = connection.create_channel
|
202
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
203
|
+
expect(q.message_count).to eq 1
|
204
|
+
ch.close
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with a valid (known) delivery tag (multiple = default)" do
|
209
|
+
it "acknowledges a message" do
|
210
|
+
ch = connection.create_channel
|
211
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
212
|
+
x = ch.default_exchange
|
213
|
+
|
214
|
+
x.publish("bunneth", :routing_key => q.name)
|
215
|
+
x.publish("bunneth", :routing_key => q.name)
|
216
|
+
sleep 0.5
|
217
|
+
expect(q.message_count).to eq 2
|
218
|
+
delivery_details_1, _properties, _content = q.pop(:manual_ack => true)
|
219
|
+
delivery_details_2, _properties, _content = q.pop(:manual_ack => true)
|
220
|
+
|
221
|
+
ch.basic_ack(delivery_details_2.delivery_tag.to_i)
|
222
|
+
ch.close
|
223
|
+
|
224
|
+
ch = connection.create_channel
|
225
|
+
q = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
|
226
|
+
expect(q.message_count).to eq 1
|
95
227
|
ch.close
|
96
228
|
end
|
97
229
|
end
|
@@ -27,9 +27,12 @@ describe Bunny::Channel, "#nack" do
|
|
27
27
|
|
28
28
|
subject.nack(delivery_info.delivery_tag, false, false)
|
29
29
|
sleep(0.5)
|
30
|
-
expect(q.message_count).to eq 0
|
31
|
-
|
32
30
|
subject.close
|
31
|
+
|
32
|
+
ch = connection.create_channel
|
33
|
+
q = ch.queue("bunny.basic.nack.with-requeue-false", :exclusive => true)
|
34
|
+
expect(q.message_count).to eq 0
|
35
|
+
ch.close
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
@@ -1,94 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
if RUBY_VERSION <= "1.9"
|
4
|
-
describe "Publishing a message to the default exchange" do
|
5
|
-
let(:connection) do
|
6
|
-
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
7
|
-
c.start
|
8
|
-
c
|
9
|
-
end
|
10
|
-
|
11
|
-
after :each do
|
12
|
-
connection.close if connection.open?
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
context "with all default delivery and message properties" do
|
17
|
-
it "routes messages to a queue with the same name as the routing key" do
|
18
|
-
expect(connection).to be_threaded
|
19
|
-
ch = connection.create_channel
|
20
|
-
|
21
|
-
q = ch.queue("", :exclusive => true)
|
22
|
-
x = ch.default_exchange
|
23
|
-
|
24
|
-
x.publish("xyzzy", :routing_key => q.name).
|
25
|
-
publish("xyzzy", :routing_key => q.name).
|
26
|
-
publish("xyzzy", :routing_key => q.name).
|
27
|
-
publish("xyzzy", :routing_key => q.name)
|
28
|
-
|
29
|
-
sleep(1)
|
30
|
-
expect(q.message_count).to eq 4
|
31
|
-
|
32
|
-
ch.close
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
context "with all default delivery and message properties" do
|
38
|
-
it "routes the messages and preserves all the metadata" do
|
39
|
-
expect(connection).to be_threaded
|
40
|
-
ch = connection.create_channel
|
41
|
-
|
42
|
-
q = ch.queue("", :exclusive => true)
|
43
|
-
x = ch.default_exchange
|
44
|
-
|
45
|
-
x.publish("xyzzy", :routing_key => q.name, :persistent => true)
|
46
|
-
|
47
|
-
sleep(1)
|
48
|
-
expect(q.message_count).to eq 1
|
49
|
-
|
50
|
-
envelope, headers, payload = q.pop
|
51
|
-
|
52
|
-
expect(payload).to eq "xyzzy"
|
53
|
-
|
54
|
-
expect(headers[:content_type]).to eq "application/octet-stream"
|
55
|
-
expect(headers[:delivery_mode]).to eq 2
|
56
|
-
expect(headers[:priority]).to eq 0
|
57
|
-
|
58
|
-
ch.close
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
context "with all default delivery and message properties on a single-threaded connection" do
|
64
|
-
let(:connection) do
|
65
|
-
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :threaded => false)
|
66
|
-
c.start
|
67
|
-
c
|
68
|
-
end
|
69
|
-
|
70
|
-
it "routes messages to a queue with the same name as the routing key" do
|
71
|
-
expect(connection).not_to be_threaded
|
72
|
-
ch = connection.create_channel
|
73
|
-
|
74
|
-
q = ch.queue("", :exclusive => true)
|
75
|
-
x = ch.default_exchange
|
76
|
-
|
77
|
-
x.publish("xyzzy", :routing_key => q.name).
|
78
|
-
publish("xyzzy", :routing_key => q.name).
|
79
|
-
publish("xyzzy", :routing_key => q.name).
|
80
|
-
publish("xyzzy", :routing_key => q.name)
|
81
|
-
|
82
|
-
sleep(1)
|
83
|
-
expect(q.message_count).to eq 4
|
84
|
-
|
85
|
-
ch.close
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
3
|
describe "Published message" do
|
93
4
|
let(:connection) do
|
94
5
|
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
@@ -43,8 +43,11 @@ describe Bunny::Channel, "#reject" do
|
|
43
43
|
|
44
44
|
ch.reject(delivery_info.delivery_tag, false)
|
45
45
|
sleep(0.5)
|
46
|
-
|
46
|
+
ch.close
|
47
47
|
|
48
|
+
ch = connection.create_channel
|
49
|
+
q = ch.queue("bunny.basic.reject.with-requeue-false", :exclusive => true)
|
50
|
+
expect(q.message_count).to eq 0
|
48
51
|
ch.close
|
49
52
|
end
|
50
53
|
end
|
@@ -72,3 +75,78 @@ describe Bunny::Channel, "#reject" do
|
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
78
|
+
|
79
|
+
describe Bunny::Channel, "#basic_reject" do
|
80
|
+
let(:connection) do
|
81
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
|
82
|
+
c.start
|
83
|
+
c
|
84
|
+
end
|
85
|
+
|
86
|
+
after :each do
|
87
|
+
connection.close if connection.open?
|
88
|
+
end
|
89
|
+
|
90
|
+
context "with requeue = true" do
|
91
|
+
it "requeues a message" do
|
92
|
+
ch = connection.create_channel
|
93
|
+
q = ch.queue("bunny.basic.reject.manual-acks", :exclusive => true)
|
94
|
+
x = ch.default_exchange
|
95
|
+
|
96
|
+
x.publish("bunneth", :routing_key => q.name)
|
97
|
+
sleep(0.5)
|
98
|
+
expect(q.message_count).to eq 1
|
99
|
+
delivery_info, _, _ = q.pop(:manual_ack => true)
|
100
|
+
|
101
|
+
ch.basic_reject(delivery_info.delivery_tag.to_i, true)
|
102
|
+
sleep(0.5)
|
103
|
+
expect(q.message_count).to eq 1
|
104
|
+
|
105
|
+
ch.close
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "with requeue = false" do
|
110
|
+
it "rejects a message" do
|
111
|
+
ch = connection.create_channel
|
112
|
+
q = ch.queue("bunny.basic.reject.with-requeue-false", :exclusive => true)
|
113
|
+
x = ch.default_exchange
|
114
|
+
|
115
|
+
x.publish("bunneth", :routing_key => q.name)
|
116
|
+
sleep(0.5)
|
117
|
+
expect(q.message_count).to eq 1
|
118
|
+
delivery_info, _, _ = q.pop(:manual_ack => true)
|
119
|
+
|
120
|
+
ch.basic_reject(delivery_info.delivery_tag.to_i, false)
|
121
|
+
sleep(0.5)
|
122
|
+
ch.close
|
123
|
+
|
124
|
+
ch = connection.create_channel
|
125
|
+
q = ch.queue("bunny.basic.reject.with-requeue-false", :exclusive => true)
|
126
|
+
expect(q.message_count).to eq 0
|
127
|
+
ch.close
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "with requeue = default" do
|
132
|
+
it "rejects a message" do
|
133
|
+
ch = connection.create_channel
|
134
|
+
q = ch.queue("bunny.basic.reject.with-requeue-false", :exclusive => true)
|
135
|
+
x = ch.default_exchange
|
136
|
+
|
137
|
+
x.publish("bunneth", :routing_key => q.name)
|
138
|
+
sleep(0.5)
|
139
|
+
expect(q.message_count).to eq 1
|
140
|
+
delivery_info, _, _ = q.pop(:manual_ack => true)
|
141
|
+
|
142
|
+
ch.basic_reject(delivery_info.delivery_tag.to_i)
|
143
|
+
sleep(0.5)
|
144
|
+
ch.close
|
145
|
+
|
146
|
+
ch = connection.create_channel
|
147
|
+
q = ch.queue("bunny.basic.reject.with-requeue-false", :exclusive => true)
|
148
|
+
expect(q.message_count).to eq 0
|
149
|
+
ch.close
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -52,6 +52,16 @@ unless ENV["CI"]
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
def with_recovery_attempts_limited_to(attempts = 3, &block)
|
56
|
+
c = Bunny.new(:recover_from_connection_close => true, :network_recovery_interval => 0.2, :recovery_attempts => attempts)
|
57
|
+
begin
|
58
|
+
c.start
|
59
|
+
block.call(c)
|
60
|
+
ensure
|
61
|
+
c.close
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
55
65
|
def ensure_queue_recovery(ch, q)
|
56
66
|
q.purge
|
57
67
|
x = ch.default_exchange
|
@@ -353,5 +363,14 @@ unless ENV["CI"]
|
|
353
363
|
end
|
354
364
|
end
|
355
365
|
end
|
366
|
+
|
367
|
+
it "tries to recover for a given number of attempts" do
|
368
|
+
with_recovery_attempts_limited_to(2) do |c|
|
369
|
+
close_all_connections!
|
370
|
+
expect(c).to receive(:start).exactly(2).times.and_raise(Bunny::TCPConnectionFailed.new("test"))
|
371
|
+
|
372
|
+
wait_for_recovery
|
373
|
+
end
|
374
|
+
end
|
356
375
|
end
|
357
376
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,19 +14,6 @@ require "rabbitmq/http/client"
|
|
14
14
|
require "amq/protocol/version"
|
15
15
|
puts "Using Ruby #{RUBY_VERSION}, amq-protocol #{AMQ::Protocol::VERSION}"
|
16
16
|
|
17
|
-
#
|
18
|
-
# Ruby version-specific
|
19
|
-
#
|
20
|
-
|
21
|
-
case RUBY_VERSION
|
22
|
-
when "1.8.7" then
|
23
|
-
class Array
|
24
|
-
alias sample choice
|
25
|
-
end
|
26
|
-
when "1.8.6" then
|
27
|
-
raise "Ruby 1.8.6 is not supported. Sorry, pal. Time to move on beyond One True Ruby. Yes, time flies by."
|
28
|
-
end
|
29
|
-
|
30
17
|
module RabbitMQ
|
31
18
|
module Control
|
32
19
|
|
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.0.0.
|
4
|
+
version: 2.0.0.rc2
|
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-06-
|
15
|
+
date: 2015-06-26 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -128,7 +128,6 @@ files:
|
|
128
128
|
- lib/bunny/session.rb
|
129
129
|
- lib/bunny/socket.rb
|
130
130
|
- lib/bunny/ssl_socket.rb
|
131
|
-
- lib/bunny/system_timer.rb
|
132
131
|
- lib/bunny/test_kit.rb
|
133
132
|
- lib/bunny/timeout.rb
|
134
133
|
- lib/bunny/transport.rb
|
@@ -212,7 +211,6 @@ files:
|
|
212
211
|
- spec/unit/concurrent/condition_spec.rb
|
213
212
|
- spec/unit/concurrent/linked_continuation_queue_spec.rb
|
214
213
|
- spec/unit/concurrent/synchronized_sorted_set_spec.rb
|
215
|
-
- spec/unit/system_timer_spec.rb
|
216
214
|
- spec/unit/version_delivery_tag_spec.rb
|
217
215
|
homepage: http://rubybunny.info
|
218
216
|
licenses:
|
@@ -315,6 +313,5 @@ test_files:
|
|
315
313
|
- spec/unit/concurrent/condition_spec.rb
|
316
314
|
- spec/unit/concurrent/linked_continuation_queue_spec.rb
|
317
315
|
- spec/unit/concurrent/synchronized_sorted_set_spec.rb
|
318
|
-
- spec/unit/system_timer_spec.rb
|
319
316
|
- spec/unit/version_delivery_tag_spec.rb
|
320
317
|
has_rdoc: true
|
data/lib/bunny/system_timer.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8; mode: ruby -*-
|
2
|
-
|
3
|
-
require "system_timer"
|
4
|
-
|
5
|
-
module Bunny
|
6
|
-
# Used for Ruby before 1.9
|
7
|
-
class SystemTimer
|
8
|
-
# Executes a block of code, raising if the execution does not finish
|
9
|
-
# in the alloted period of time, in seconds.
|
10
|
-
def self.timeout(seconds, exception = nil)
|
11
|
-
if seconds
|
12
|
-
::SystemTimer.timeout_after(seconds, exception) do
|
13
|
-
yield
|
14
|
-
end
|
15
|
-
else
|
16
|
-
yield
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end # SystemTimer
|
20
|
-
end # Bunny
|
@@ -1,10 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
if RUBY_VERSION.to_f < 1.9
|
4
|
-
describe Bunny::SystemTimer do
|
5
|
-
it 'supports being called with a single argument' do
|
6
|
-
expect {Bunny::SystemTimer::timeout(1) {}}.not_to raise_error
|
7
|
-
expect {Bunny::SystemTimer::timeout(1, nil) {}}.not_to raise_error
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|