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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7035cf94d8295c49d7e57deb2143be7ed1b6a465
4
- data.tar.gz: 0387323f9a4029809fbe05c5160731c2a9839ccc
3
+ metadata.gz: e0c99fb0a3faf8edcc73da84f74ce724e77b71a1
4
+ data.tar.gz: 4c50a4aa3b4b6bb70ae4f9f8d4305914c24e9f1b
5
5
  SHA512:
6
- metadata.gz: 0a4ab1f554f8445a4d7a283ba182a2c6b8244c5371295cd81478c24da0daaf00a71eeb477dfc1bd14dcb22f9b5ef28de938672edc8907a17fae3d0ac07c18b1c
7
- data.tar.gz: 68cc7911d99ee0161f3c09383d06f88ba482c4a0ab3e04f21049cdd94bbdac46e108598dde44ebff97a3671994a54679602a44727001363f2770ca8935e922be
6
+ metadata.gz: 717ee6c9d892e4d930464b2122ffbd2059420553c4b3f3ec670d6b66331d9885feeac96eb0edf7f2da1fcf11ef77bc05e3b2beacfbb7f96a19a7e780b2fb3ea5
7
+ data.tar.gz: 3b24edbe00fbbb46a20592bb5cc28bc5f00fa6fb05180a5b91405f2534c9c4a8d8e3b0b9ab12e1f6213a501f3cc2cab374e00a3bc3a31ba79281efa7e9e0a8d1
@@ -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.1.0"
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
@@ -1,4 +1,21 @@
1
- ## Changes between Bunny 1.7.0 and 1.8.0
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
@@ -19,8 +19,6 @@ extend Module.new {
19
19
  end
20
20
  }
21
21
 
22
- gem "SystemTimer", "~> 1.2.3", :platform => :ruby_18
23
-
24
22
  gem "rake", ">= 10.0.4"
25
23
  gem "effin_utf8"
26
24
 
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, 1.9.3, and 1.8.7
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
 
@@ -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
- guarding_against_stale_delivery_tags(delivery_tag) do
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
- guarding_against_stale_delivery_tags(delivery_tag) do
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
- guarding_against_stale_delivery_tags(delivery_tag) do
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.send_frameset_without_timeout(frames, self)
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
- raise_if_no_longer_open!
712
- @connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
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
- nil
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
- raise_if_no_longer_open!
759
- @connection.send_frame(AMQ::Protocol::Basic::Ack.encode(@id, delivery_tag, multiple))
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
- nil
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
- raise_if_no_longer_open!
819
- @connection.send_frame(AMQ::Protocol::Basic::Nack.encode(@id,
820
- delivery_tag,
821
- multiple,
822
- requeue))
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
- nil
822
+ nil
823
+ end
825
824
  end
826
825
 
827
826
  # Registers a consumer for queue. Delivered messages will be handled with the block
@@ -6,27 +6,24 @@ module Bunny
6
6
  #
7
7
  # Heavily inspired by Dalli by Mike Perham.
8
8
  # @private
9
- class Socket < TCPSocket
9
+ module Socket
10
10
  attr_accessor :options
11
11
 
12
- # IO::WaitReadable is 1.9+ only
13
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
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
- Timeout.timeout(options[:connect_timeout], ClientTimeout) do
22
- sock = new(host, port)
23
- if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
24
- sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
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
- # IO::WaitReadable is 1.9+ only
12
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
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
  #
@@ -46,11 +46,7 @@ module Bunny
46
46
  CONNECT_TIMEOUT = Transport::DEFAULT_CONNECTION_TIMEOUT
47
47
 
48
48
  # @private
49
- DEFAULT_CONTINUATION_TIMEOUT = if RUBY_VERSION.to_f < 1.9
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
- retry if recoverable_network_failure?(e)
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
- frames.each { |frame| self.send_frame(frame, false) }
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)
@@ -1,16 +1,5 @@
1
1
  module Bunny
2
- # Unifies Ruby standard library's Timeout (which is not accurate on
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
@@ -20,10 +20,10 @@ module Bunny
20
20
  #
21
21
 
22
22
  # Default TCP connection timeout
23
- DEFAULT_CONNECTION_TIMEOUT = 25.0
23
+ DEFAULT_CONNECTION_TIMEOUT = 30.0
24
24
 
25
- DEFAULT_READ_TIMEOUT = 5.0
26
- DEFAULT_WRITE_TIMEOUT = 5.0
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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Bunny
4
4
  # @return [String] Version of the library
5
- VERSION = "2.0.0.rc1"
5
+ VERSION = "2.0.0.rc2"
6
6
  end
@@ -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
- expect(q.message_count).to eq 0
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
@@ -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.rc1
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-12 00:00:00.000000000 Z
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
@@ -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