bunny 2.0.0.rc1 → 2.0.0.rc2
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/.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
|