bunny 0.9.0.pre5 → 0.9.0.pre6
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.
- data/.gitignore +1 -0
- data/ChangeLog.md +46 -0
- data/README.md +1 -1
- data/examples/connection/authentication_failure.rb +16 -0
- data/examples/connection/automatic_recovery_with_client_named_queues.rb +28 -0
- data/examples/connection/automatic_recovery_with_multiple_consumers.rb +40 -0
- data/examples/connection/automatic_recovery_with_server_named_queues.rb +28 -0
- data/examples/connection/channel_level_exception.rb +35 -0
- data/examples/connection/unknown_host.rb +6 -3
- data/lib/bunny/channel.rb +65 -8
- data/lib/bunny/consumer.rb +8 -0
- data/lib/bunny/consumer_work_pool.rb +14 -0
- data/lib/bunny/exceptions.rb +8 -3
- data/lib/bunny/exchange.rb +10 -0
- data/lib/bunny/main_loop.rb +10 -1
- data/lib/bunny/queue.rb +53 -1
- data/lib/bunny/session.rb +70 -5
- data/lib/bunny/transport.rb +30 -17
- data/lib/bunny/version.rb +1 -1
- data/spec/unit/transport_spec.rb +15 -0
- metadata +197 -197
data/.gitignore
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,3 +1,49 @@
|
|
1
|
+
## Changes between Bunny 0.9.0.pre5 and 0.9.0.pre6
|
2
|
+
|
3
|
+
### Automatic Network Failure Recovery
|
4
|
+
|
5
|
+
Automatic Network Failure Recovery is a new Bunny feature that was earlier
|
6
|
+
impemented and vetted out in [amqp gem](http://rubyamqp.info). What it does
|
7
|
+
is, when a network activity loop detects an issue, it will try to
|
8
|
+
periodically recover [first TCP, then] AMQP 0.9.1 connection, reopen
|
9
|
+
all channels, recover all exchanges, queues, bindings and consumers
|
10
|
+
on those channels (to be clear: this only includes entities and consumers added via
|
11
|
+
Bunny).
|
12
|
+
|
13
|
+
Publishers and consumers will continue operating shortly after the network
|
14
|
+
connection recovers.
|
15
|
+
|
16
|
+
Learn more in the [Error Handling and Recovery](http://rubybunny.info/articles/error_handling.html)
|
17
|
+
documentation guide.
|
18
|
+
|
19
|
+
### Confirms Listeners
|
20
|
+
|
21
|
+
Bunny now supports listeners (callbacks) on
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
ch.confirm_select do |delivery_tag, multiple, nack|
|
25
|
+
# handle confirms (e.g. perform retries) here
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
Contributed by Greg Brockman.
|
30
|
+
|
31
|
+
### Publisher Confirms Improvements
|
32
|
+
|
33
|
+
Publisher confirms implementation now uses non-strict equality (`<=`) for
|
34
|
+
cases when multiple messages are confirmed by RabbitMQ at once.
|
35
|
+
|
36
|
+
`Bunny::Channel#unconfirmed_set` is now part of the public API that lets
|
37
|
+
developers access unconfirmed delivery tags to perform retries and such.
|
38
|
+
|
39
|
+
Contributed by Greg Brockman.
|
40
|
+
|
41
|
+
### Publisher Confirms Concurrency Fix
|
42
|
+
|
43
|
+
`Bunny::Channel#wait_for_confirms` will now correctly block the calling
|
44
|
+
thread until all pending confirms are received.
|
45
|
+
|
46
|
+
|
1
47
|
## Changes between Bunny 0.9.0.pre4 and 0.9.0.pre5
|
2
48
|
|
3
49
|
### Channel Errors Reset
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ gem install bunny --pre
|
|
37
37
|
To use Bunny 0.9.x in a project managed with Bundler:
|
38
38
|
|
39
39
|
``` ruby
|
40
|
-
gem "bunny", ">= 0.9.0.
|
40
|
+
gem "bunny", ">= 0.9.0.pre6" # optionally: , :git => "git://github.com/ruby-amqp/bunny.git", :branch => "master"
|
41
41
|
```
|
42
42
|
|
43
43
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'bunny'
|
10
|
+
|
11
|
+
begin
|
12
|
+
conn = Bunny.new("amqp://guest8we78w7e8:guest2378278@127.0.0.1")
|
13
|
+
conn.start
|
14
|
+
rescue Bunny::PossibleAuthenticationFailureError => e
|
15
|
+
puts "Could not authenticate as #{conn.username}"
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'bunny'
|
10
|
+
|
11
|
+
conn = Bunny.new(:heartbeat_interval => 8)
|
12
|
+
conn.start
|
13
|
+
|
14
|
+
ch = conn.create_channel
|
15
|
+
x = ch.topic("bunny.examples.recovery.topic", :durable => false)
|
16
|
+
q = ch.queue("bunny.examples.recovery.client_named_queue1", :durable => false)
|
17
|
+
|
18
|
+
q.bind(x, :routing_key => "abc").bind(x, :routing_key => "def")
|
19
|
+
|
20
|
+
q.subscribe do |delivery_info, metadata, payload|
|
21
|
+
puts "Consumed #{payload}"
|
22
|
+
end
|
23
|
+
|
24
|
+
loop do
|
25
|
+
sleep 3
|
26
|
+
puts "Tick"
|
27
|
+
x.publish(rand.to_s, :routing_key => ["abc", "def", "ghi", "xyz"].sample)
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'bunny'
|
10
|
+
|
11
|
+
conn = Bunny.new(:heartbeat_interval => 8)
|
12
|
+
conn.start
|
13
|
+
|
14
|
+
ch1 = conn.create_channel
|
15
|
+
x1 = ch1.topic("bunny.examples.recovery.e1", :durable => false)
|
16
|
+
q1 = ch1.queue("bunny.examples.recovery.q1", :durable => false)
|
17
|
+
|
18
|
+
q1.bind(x1, :routing_key => "abc").bind(x1, :routing_key => "def")
|
19
|
+
|
20
|
+
ch2 = conn.create_channel
|
21
|
+
x2 = ch2.topic("bunny.examples.recovery.e2", :durable => false)
|
22
|
+
q2 = ch2.queue("bunny.examples.recovery.q2", :durable => false)
|
23
|
+
|
24
|
+
q2.bind(x2, :routing_key => "abc").bind(x2, :routing_key => "def")
|
25
|
+
|
26
|
+
q1.subscribe do |delivery_info, metadata, payload|
|
27
|
+
puts "Consumed #{payload} at stage one"
|
28
|
+
x2.publish(payload, :routing_key => ["abc", "def", "xyz"].sample)
|
29
|
+
end
|
30
|
+
|
31
|
+
q2.subscribe do |delivery_info, metadata, payload|
|
32
|
+
puts "Consumed #{payload} at stage two"
|
33
|
+
end
|
34
|
+
|
35
|
+
loop do
|
36
|
+
sleep 3
|
37
|
+
rk = ["abc", "def", "ghi", "xyz"].sample
|
38
|
+
puts "Publishing with routing key #{rk}"
|
39
|
+
x1.publish(rand.to_s, :routing_key => rk)
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'bunny'
|
10
|
+
|
11
|
+
conn = Bunny.new(:heartbeat_interval => 8)
|
12
|
+
conn.start
|
13
|
+
|
14
|
+
ch = conn.create_channel
|
15
|
+
x = ch.topic("bunny.examples.recovery.topic", :durable => false)
|
16
|
+
q = ch.queue("", :durable => false)
|
17
|
+
|
18
|
+
q.bind(x, :routing_key => "abc").bind(x, :routing_key => "def")
|
19
|
+
|
20
|
+
q.subscribe do |delivery_info, metadata, payload|
|
21
|
+
puts "Consumed #{payload}"
|
22
|
+
end
|
23
|
+
|
24
|
+
loop do
|
25
|
+
sleep 3
|
26
|
+
puts "Tick"
|
27
|
+
x.publish(rand.to_s, :routing_key => ["abc", "def", "ghi", "xyz"].sample)
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'bunny'
|
10
|
+
|
11
|
+
conn = Bunny.new(:heartbeat_interval => 8)
|
12
|
+
conn.start
|
13
|
+
|
14
|
+
begin
|
15
|
+
ch1 = conn.create_channel
|
16
|
+
ch1.queue_delete("queue_that_should_not_exist#{rand}")
|
17
|
+
rescue Bunny::NotFound => e
|
18
|
+
puts "Channel-level exception! Code: #{e.channel_close.reply_code}, message: #{e.channel_close.reply_text}"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
begin
|
23
|
+
ch2 = conn.create_channel
|
24
|
+
q = "bunny.examples.recovery.q#{rand}"
|
25
|
+
|
26
|
+
ch2.queue_declare(q, :durable => false)
|
27
|
+
ch2.queue_declare(q, :durable => true)
|
28
|
+
rescue Bunny::PreconditionFailed => e
|
29
|
+
puts "Channel-level exception! Code: #{e.channel_close.reply_code}, message: #{e.channel_close.reply_text}"
|
30
|
+
ensure
|
31
|
+
conn.create_channel.queue_delete(q)
|
32
|
+
end
|
33
|
+
|
34
|
+
puts "Disconnecting..."
|
35
|
+
conn.close
|
@@ -8,6 +8,9 @@ $:.unshift(File.expand_path("../../../lib", __FILE__))
|
|
8
8
|
|
9
9
|
require 'bunny'
|
10
10
|
|
11
|
-
|
12
|
-
conn.
|
13
|
-
|
11
|
+
begin
|
12
|
+
conn = Bunny.new("amqp://guest:guest@aksjhdkajshdkj.example82737.com")
|
13
|
+
conn.start
|
14
|
+
rescue Bunny::TCPConnectionFailed => e
|
15
|
+
puts "Connection to #{conn.hostname} failed"
|
16
|
+
end
|
data/lib/bunny/channel.rb
CHANGED
@@ -18,7 +18,7 @@ module Bunny
|
|
18
18
|
#
|
19
19
|
|
20
20
|
attr_accessor :id, :connection, :status, :work_pool
|
21
|
-
attr_reader :next_publish_seq_no, :queues, :exchanges
|
21
|
+
attr_reader :next_publish_seq_no, :queues, :exchanges, :unconfirmed_set, :consumers
|
22
22
|
|
23
23
|
|
24
24
|
def initialize(connection = nil, id = nil, work_pool = ConsumerWorkPool.new(1))
|
@@ -215,6 +215,8 @@ module Bunny
|
|
215
215
|
end
|
216
216
|
raise_if_continuation_resulted_in_a_channel_error!
|
217
217
|
|
218
|
+
@prefetch_count = prefetch_count
|
219
|
+
|
218
220
|
@last_basic_qos_ok
|
219
221
|
end
|
220
222
|
|
@@ -572,15 +574,17 @@ module Bunny
|
|
572
574
|
|
573
575
|
# confirm.*
|
574
576
|
|
575
|
-
def confirm_select
|
577
|
+
def confirm_select(callback=nil)
|
576
578
|
raise_if_no_longer_open!
|
577
579
|
|
578
580
|
if @next_publish_seq_no == 0
|
579
|
-
@confirms_continuations =
|
581
|
+
@confirms_continuations = ::Queue.new
|
580
582
|
@unconfirmed_set = Set.new
|
581
583
|
@next_publish_seq_no = 1
|
582
584
|
end
|
583
585
|
|
586
|
+
@confirms_callback = callback
|
587
|
+
|
584
588
|
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
585
589
|
Bunny::Timer.timeout(1, ClientTimeout) do
|
586
590
|
@last_confirm_select_ok = @continuations.pop
|
@@ -597,6 +601,47 @@ module Bunny
|
|
597
601
|
end
|
598
602
|
|
599
603
|
|
604
|
+
#
|
605
|
+
# Recovery
|
606
|
+
#
|
607
|
+
|
608
|
+
def recover_from_network_failure
|
609
|
+
# puts "Recovering channel #{@id} from network failure..."
|
610
|
+
recover_prefetch_setting
|
611
|
+
recover_exchanges
|
612
|
+
# this includes recovering bindings
|
613
|
+
recover_queues
|
614
|
+
recover_consumers
|
615
|
+
end
|
616
|
+
|
617
|
+
def recover_prefetch_setting
|
618
|
+
basic_qos(@prefetch_count) if @prefetch_count
|
619
|
+
end
|
620
|
+
|
621
|
+
def recover_exchanges
|
622
|
+
@exchanges.values.dup.each do |x|
|
623
|
+
x.recover_from_network_failure
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
def recover_queues
|
628
|
+
@queues.values.dup.each do |q|
|
629
|
+
q.recover_from_network_failure
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
def recover_consumers
|
634
|
+
unless @consumers.empty?
|
635
|
+
@work_pool = ConsumerWorkPool.new(@work_pool.size)
|
636
|
+
@work_pool.start
|
637
|
+
end
|
638
|
+
@consumers.values.dup.each do |c|
|
639
|
+
c.recover_from_network_failure
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
|
644
|
+
|
600
645
|
#
|
601
646
|
# Implementation
|
602
647
|
#
|
@@ -660,10 +705,8 @@ module Bunny
|
|
660
705
|
when AMQ::Protocol::Confirm::SelectOk then
|
661
706
|
@continuations.push(method)
|
662
707
|
when AMQ::Protocol::Basic::Ack then
|
663
|
-
# TODO: implement confirm listeners
|
664
708
|
handle_ack_or_nack(method.delivery_tag, method.multiple, false)
|
665
709
|
when AMQ::Protocol::Basic::Nack then
|
666
|
-
# TODO: implement confirm listeners
|
667
710
|
handle_ack_or_nack(method.delivery_tag, method.multiple, true)
|
668
711
|
when AMQ::Protocol::Channel::Close then
|
669
712
|
# puts "Exception on channel #{@id}: #{method.reply_code} #{method.reply_text}"
|
@@ -711,7 +754,7 @@ module Bunny
|
|
711
754
|
|
712
755
|
def handle_ack_or_nack(delivery_tag, multiple, nack)
|
713
756
|
if multiple
|
714
|
-
@unconfirmed_set.delete_if { |i| i
|
757
|
+
@unconfirmed_set.delete_if { |i| i <= delivery_tag }
|
715
758
|
else
|
716
759
|
@unconfirmed_set.delete(delivery_tag)
|
717
760
|
end
|
@@ -720,6 +763,8 @@ module Bunny
|
|
720
763
|
@only_acks_received = (@only_acks_received && !nack)
|
721
764
|
|
722
765
|
@confirms_continuations.push(true) if @unconfirmed_set.empty?
|
766
|
+
|
767
|
+
@confirms_callback.call(delivery_tag, multiple, nack) if @confirms_callback
|
723
768
|
end
|
724
769
|
end
|
725
770
|
|
@@ -730,6 +775,14 @@ module Bunny
|
|
730
775
|
@work_pool.start unless @work_pool.started?
|
731
776
|
end
|
732
777
|
|
778
|
+
def maybe_pause_consumer_work_pool!
|
779
|
+
@work_pool.pause if @work_pool && @work_pool.started?
|
780
|
+
end
|
781
|
+
|
782
|
+
def maybe_kill_consumer_work_pool!
|
783
|
+
@work_pool.kill if @work_pool && @work_pool.started?
|
784
|
+
end
|
785
|
+
|
733
786
|
def read_next_frame(options = {})
|
734
787
|
@connection.read_next_frame(options = {})
|
735
788
|
end
|
@@ -739,11 +792,15 @@ module Bunny
|
|
739
792
|
def synchronize(&block)
|
740
793
|
@publishing_mutex.synchronize(&block)
|
741
794
|
end
|
742
|
-
|
795
|
+
|
743
796
|
def deregister_queue(queue)
|
744
797
|
@queues.delete(queue.name)
|
745
798
|
end
|
746
799
|
|
800
|
+
def deregister_queue_named(name)
|
801
|
+
@queues.delete(name)
|
802
|
+
end
|
803
|
+
|
747
804
|
def register_queue(queue)
|
748
805
|
@queues[queue.name] = queue
|
749
806
|
end
|
@@ -751,7 +808,7 @@ module Bunny
|
|
751
808
|
def find_queue(name)
|
752
809
|
@queues[name]
|
753
810
|
end
|
754
|
-
|
811
|
+
|
755
812
|
def deregister_exchange(exchange)
|
756
813
|
@exchanges.delete(exchange.name)
|
757
814
|
end
|
data/lib/bunny/consumer.rb
CHANGED
@@ -58,5 +58,13 @@ module Bunny
|
|
58
58
|
def inspect
|
59
59
|
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}> @consumer_tag=#{@consumer_tag} @exclusive=#{@exclusive} @no_ack=#{@no_ack}>"
|
60
60
|
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Recovery
|
64
|
+
#
|
65
|
+
|
66
|
+
def recover_from_network_failure
|
67
|
+
@channel.basic_consume_with(self)
|
68
|
+
end
|
61
69
|
end
|
62
70
|
end
|
@@ -9,6 +9,8 @@ module Bunny
|
|
9
9
|
# API
|
10
10
|
#
|
11
11
|
|
12
|
+
attr_reader :size
|
13
|
+
|
12
14
|
def initialize(size = 1)
|
13
15
|
@size = size
|
14
16
|
@queue = ::Queue.new
|
@@ -46,6 +48,18 @@ module Bunny
|
|
46
48
|
@threads.each { |t| t.join }
|
47
49
|
end
|
48
50
|
|
51
|
+
def pause
|
52
|
+
@threads.each { |t| t.stop }
|
53
|
+
end
|
54
|
+
|
55
|
+
def resume
|
56
|
+
@threads.each { |t| t.run }
|
57
|
+
end
|
58
|
+
|
59
|
+
def kill
|
60
|
+
@threads.each { |t| t.kill }
|
61
|
+
end
|
62
|
+
|
49
63
|
protected
|
50
64
|
|
51
65
|
def run_loop
|
data/lib/bunny/exceptions.rb
CHANGED
@@ -16,9 +16,9 @@ module Bunny
|
|
16
16
|
class ConnectionClosedError < StandardError
|
17
17
|
def initialize(frame)
|
18
18
|
if frame.respond_to?(:method_class)
|
19
|
-
super("Trying to send frame through a closed connection. Frame is #{frame.inspect}")
|
20
|
-
else
|
21
19
|
super("Trying to send frame through a closed connection. Frame is #{frame.inspect}, method class is #{frame.method_class}")
|
20
|
+
else
|
21
|
+
super("Trying to send frame through a closed connection. Frame is #{frame.inspect}")
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -44,7 +44,6 @@ module Bunny
|
|
44
44
|
ConnectionError = TCPConnectionFailed
|
45
45
|
ServerDownError = TCPConnectionFailed
|
46
46
|
|
47
|
-
# TODO
|
48
47
|
class ForcedChannelCloseError < StandardError; end
|
49
48
|
class ForcedConnectionCloseError < StandardError; end
|
50
49
|
class MessageError < StandardError; end
|
@@ -131,4 +130,10 @@ module Bunny
|
|
131
130
|
|
132
131
|
class ChannelError < ConnectionLevelException
|
133
132
|
end
|
133
|
+
|
134
|
+
class InvalidCommand < ConnectionLevelException
|
135
|
+
end
|
136
|
+
|
137
|
+
class UnexpectedFrame < ConnectionLevelException
|
138
|
+
end
|
134
139
|
end
|
data/lib/bunny/exchange.rb
CHANGED
@@ -126,6 +126,11 @@ module Bunny
|
|
126
126
|
self
|
127
127
|
end
|
128
128
|
|
129
|
+
def recover_from_network_failure
|
130
|
+
# puts "Recovering exchange #{@name} from network failure"
|
131
|
+
declare! unless predefined?
|
132
|
+
end
|
133
|
+
|
129
134
|
|
130
135
|
#
|
131
136
|
# Implementation
|
@@ -139,6 +144,11 @@ module Bunny
|
|
139
144
|
end
|
140
145
|
end
|
141
146
|
|
147
|
+
# @return [Boolean] true if this exchange is a pre-defined one (amq.direct, amq.fanout, amq.match and so on)
|
148
|
+
def predefined?
|
149
|
+
@name && ((@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\./i))
|
150
|
+
end # predefined?
|
151
|
+
|
142
152
|
protected
|
143
153
|
|
144
154
|
# @private
|
data/lib/bunny/main_loop.rb
CHANGED
@@ -18,10 +18,15 @@ module Bunny
|
|
18
18
|
@thread = Thread.new(&method(:run_loop))
|
19
19
|
end
|
20
20
|
|
21
|
+
def resume
|
22
|
+
start
|
23
|
+
end
|
24
|
+
|
25
|
+
|
21
26
|
def run_loop
|
22
27
|
loop do
|
23
28
|
begin
|
24
|
-
break if @stopping
|
29
|
+
break if @stopping || @network_is_down
|
25
30
|
|
26
31
|
frame = @transport.read_next_frame
|
27
32
|
@session.signal_activity!
|
@@ -50,6 +55,10 @@ module Bunny
|
|
50
55
|
# should happen per operation and not in this loop
|
51
56
|
rescue Errno::EBADF => ebadf
|
52
57
|
# ignored, happens when we loop after the transport has already been closed
|
58
|
+
rescue AMQ::Protocol::EmptyResponseError, IOError, Errno::EPIPE, Errno::EAGAIN => e
|
59
|
+
puts "Exception in the main loop: #{e.class.name}"
|
60
|
+
@network_is_down = true
|
61
|
+
@session.handle_network_failure(e)
|
53
62
|
rescue Exception => e
|
54
63
|
puts e.class.name
|
55
64
|
puts e.message
|
data/lib/bunny/queue.rb
CHANGED
@@ -26,6 +26,8 @@ module Bunny
|
|
26
26
|
@auto_delete = @options[:auto_delete]
|
27
27
|
@arguments = @options[:arguments]
|
28
28
|
|
29
|
+
@bindings = Array.new
|
30
|
+
|
29
31
|
@default_consumer = nil
|
30
32
|
|
31
33
|
declare! unless opts[:no_declare]
|
@@ -65,12 +67,33 @@ module Bunny
|
|
65
67
|
def bind(exchange, opts = {})
|
66
68
|
@channel.queue_bind(@name, exchange, opts)
|
67
69
|
|
70
|
+
exchange_name = if exchange.respond_to?(:name)
|
71
|
+
exchange.name
|
72
|
+
else
|
73
|
+
exchange
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# store bindings for automatic recovery. We need to be very careful to
|
78
|
+
# not cause an infinite rebinding loop here when we recover. MK.
|
79
|
+
binding = { :exchange => exchange_name, :routing_key => (opts[:routing_key] || opts[:key]), :arguments => opts[:arguments] }
|
80
|
+
@bindings.push(binding) unless @bindings.include?(binding)
|
81
|
+
|
68
82
|
self
|
69
83
|
end
|
70
84
|
|
71
85
|
def unbind(exchange, opts = {})
|
72
86
|
@channel.queue_unbind(@name, exchange, opts)
|
73
87
|
|
88
|
+
exchange_name = if exchange.respond_to?(:name)
|
89
|
+
exchange.name
|
90
|
+
else
|
91
|
+
exchange
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
@bindings.delete_if { |b| b[:exchange] == exchange_name && b[:routing_key] == (opts[:routing_key] || opts[:key]) && b[:arguments] == opts[:arguments] }
|
96
|
+
|
74
97
|
self
|
75
98
|
end
|
76
99
|
|
@@ -84,11 +107,12 @@ module Bunny
|
|
84
107
|
|
85
108
|
ctag = opts.fetch(:consumer_tag, @channel.generate_consumer_tag)
|
86
109
|
consumer = Consumer.new(@channel,
|
87
|
-
|
110
|
+
self,
|
88
111
|
ctag,
|
89
112
|
!opts[:ack],
|
90
113
|
opts[:exclusive],
|
91
114
|
opts[:arguments])
|
115
|
+
puts "Added consumer #{ctag} on queue #{@name}"
|
92
116
|
consumer.on_delivery(&block)
|
93
117
|
consumer.on_cancellation(&opts[:on_cancellation]) if opts[:on_cancellation]
|
94
118
|
|
@@ -172,6 +196,34 @@ module Bunny
|
|
172
196
|
s[:consumer_count]
|
173
197
|
end
|
174
198
|
|
199
|
+
#
|
200
|
+
# Recovery
|
201
|
+
#
|
202
|
+
|
203
|
+
def recover_from_network_failure
|
204
|
+
# puts "Recovering queue #{@name} from network failure"
|
205
|
+
|
206
|
+
if self.server_named?
|
207
|
+
old_name = @name.dup
|
208
|
+
@name = AMQ::Protocol::EMPTY_STRING
|
209
|
+
|
210
|
+
@channel.deregister_queue_named(old_name)
|
211
|
+
end
|
212
|
+
|
213
|
+
declare!
|
214
|
+
begin
|
215
|
+
@channel.register_queue(self)
|
216
|
+
rescue Exception => e
|
217
|
+
puts "Caught #{e.inspect} while registering #{@name}!"
|
218
|
+
end
|
219
|
+
recover_bindings
|
220
|
+
end
|
221
|
+
|
222
|
+
def recover_bindings
|
223
|
+
@bindings.each do |b|
|
224
|
+
self.bind(b[:exchange], b)
|
225
|
+
end
|
226
|
+
end
|
175
227
|
|
176
228
|
|
177
229
|
#
|
data/lib/bunny/session.rb
CHANGED
@@ -111,13 +111,15 @@ module Bunny
|
|
111
111
|
alias ssl? uses_ssl?
|
112
112
|
|
113
113
|
def start
|
114
|
-
@
|
114
|
+
@continuations = ::Queue.new
|
115
|
+
@status = :connecting
|
115
116
|
|
116
117
|
self.initialize_transport
|
117
118
|
|
118
119
|
self.init_connection
|
119
120
|
self.open_connection
|
120
121
|
|
122
|
+
@event_loop = nil
|
121
123
|
self.start_main_loop
|
122
124
|
|
123
125
|
@default_channel = self.create_channel
|
@@ -233,9 +235,7 @@ module Bunny
|
|
233
235
|
def close_connection(sync = true)
|
234
236
|
@transport.send_frame(AMQ::Protocol::Connection::Close.encode(200, "Goodbye", 0, 0))
|
235
237
|
|
236
|
-
|
237
|
-
@heartbeat_sender.stop
|
238
|
-
end
|
238
|
+
maybe_shutdown_heartbeat_sender
|
239
239
|
@status = :not_connected
|
240
240
|
|
241
241
|
if sync
|
@@ -303,6 +303,60 @@ module Bunny
|
|
303
303
|
end
|
304
304
|
end
|
305
305
|
|
306
|
+
def handle_network_failure(exception)
|
307
|
+
if !recovering_from_network_failure?
|
308
|
+
@recovering_from_network_failure = true
|
309
|
+
if recoverable_network_failure?(exception)
|
310
|
+
# puts "Recovering from a network failure..."
|
311
|
+
@channels.each do |n, ch|
|
312
|
+
ch.maybe_kill_consumer_work_pool!
|
313
|
+
end
|
314
|
+
maybe_shutdown_heartbeat_sender
|
315
|
+
|
316
|
+
recover_from_network_failure
|
317
|
+
else
|
318
|
+
# TODO: investigate if we can be a bit smarter here. MK.
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def recoverable_network_failure?(exception)
|
324
|
+
# TODO: investigate if we can be a bit smarter here. MK.
|
325
|
+
true
|
326
|
+
end
|
327
|
+
|
328
|
+
def recovering_from_network_failure?
|
329
|
+
@recovering_from_network_failure
|
330
|
+
end
|
331
|
+
|
332
|
+
def recover_from_network_failure
|
333
|
+
begin
|
334
|
+
# puts "About to start recovery..."
|
335
|
+
start
|
336
|
+
|
337
|
+
if open?
|
338
|
+
@recovering_from_network_failure = false
|
339
|
+
|
340
|
+
recover_channels
|
341
|
+
end
|
342
|
+
rescue TCPConnectionFailed, AMQ::Protocol::EmptyResponseError => e
|
343
|
+
# puts "TCP connection failed, reconnecting in 5 seconds"
|
344
|
+
sleep 5.0
|
345
|
+
retry if recoverable_network_failure?(e)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def recover_channels
|
350
|
+
# default channel is reopened right after connection
|
351
|
+
# negotiation is completed, so make sure we do not try to open
|
352
|
+
# it twice. MK.
|
353
|
+
@channels.reject { |n, ch| ch == @default_channel }.each do |n, ch|
|
354
|
+
ch.open
|
355
|
+
|
356
|
+
ch.recover_from_network_failure
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
306
360
|
def send_raw(*args)
|
307
361
|
@transport.write(*args)
|
308
362
|
end
|
@@ -311,8 +365,14 @@ module Bunny
|
|
311
365
|
case frame
|
312
366
|
when AMQ::Protocol::Connection::Close then
|
313
367
|
klass = case frame.reply_code
|
368
|
+
when 503 then
|
369
|
+
InvalidCommand
|
314
370
|
when 504 then
|
315
371
|
ChannelError
|
372
|
+
when 504 then
|
373
|
+
UnexpectedFrame
|
374
|
+
else
|
375
|
+
raise "Unknown reply code: #{frame.reply_code}, text: #{frame.reply_text}"
|
316
376
|
end
|
317
377
|
|
318
378
|
klass.new("Connection-level error: #{frame.reply_text}", self, frame)
|
@@ -488,13 +548,18 @@ module Bunny
|
|
488
548
|
end
|
489
549
|
|
490
550
|
def initialize_heartbeat_sender
|
551
|
+
# puts "Initializing heartbeat sender..."
|
491
552
|
@heartbeat_sender = HeartbeatSender.new(@transport)
|
492
553
|
@heartbeat_sender.start(@heartbeat)
|
493
554
|
end
|
494
555
|
|
556
|
+
def maybe_shutdown_heartbeat_sender
|
557
|
+
@heartbeat_sender.stop if @heartbeat_sender
|
558
|
+
end
|
559
|
+
|
495
560
|
|
496
561
|
def initialize_transport
|
497
|
-
@transport = Transport.new(@host, @port, @opts)
|
562
|
+
@transport = Transport.new(self, @host, @port, @opts)
|
498
563
|
end
|
499
564
|
|
500
565
|
# Sends AMQ protocol header (also known as preamble).
|
data/lib/bunny/transport.rb
CHANGED
@@ -14,12 +14,13 @@ module Bunny
|
|
14
14
|
DEFAULT_CONNECTION_TIMEOUT = 5.0
|
15
15
|
|
16
16
|
|
17
|
-
attr_reader :host, :port, :socket, :connect_timeout
|
17
|
+
attr_reader :session, :host, :port, :socket, :connect_timeout
|
18
18
|
|
19
|
-
def initialize(host, port, opts)
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
19
|
+
def initialize(session, host, port, opts)
|
20
|
+
@session = session
|
21
|
+
@host = host
|
22
|
+
@port = port
|
23
|
+
@opts = opts
|
23
24
|
|
24
25
|
@ssl = opts[:ssl] || false
|
25
26
|
@ssl_cert = opts[:ssl_cert]
|
@@ -61,24 +62,18 @@ module Bunny
|
|
61
62
|
# @raise [ClientTimeout]
|
62
63
|
def write(*args)
|
63
64
|
begin
|
64
|
-
raise Bunny::ConnectionError.new(
|
65
|
+
raise Bunny::ConnectionError.new("No connection: socket is nil. ", @host, @port) if !@socket
|
65
66
|
if @read_write_timeout
|
66
67
|
Bunny::Timer.timeout(@read_write_timeout, Bunny::ClientTimeout) do
|
67
|
-
@socket.write(*args)
|
68
|
+
@socket.write(*args) if open?
|
68
69
|
end
|
69
70
|
else
|
70
|
-
@socket.write(*args)
|
71
|
+
@socket.write(*args) if open?
|
71
72
|
end
|
72
73
|
rescue Errno::EPIPE, Errno::EAGAIN, Bunny::ClientTimeout, IOError => e
|
73
74
|
close
|
74
75
|
|
75
|
-
|
76
|
-
when String then
|
77
|
-
e
|
78
|
-
when Exception then
|
79
|
-
e.message
|
80
|
-
end
|
81
|
-
raise Bunny::ConnectionError.new(m, @host, @port)
|
76
|
+
@session.handle_network_failure(e)
|
82
77
|
end
|
83
78
|
end
|
84
79
|
alias send_raw write
|
@@ -97,7 +92,7 @@ module Bunny
|
|
97
92
|
end
|
98
93
|
|
99
94
|
def flush
|
100
|
-
@socket.flush
|
95
|
+
@socket.flush if @socket
|
101
96
|
end
|
102
97
|
|
103
98
|
def read_fully(*args)
|
@@ -135,13 +130,31 @@ module Bunny
|
|
135
130
|
# @private
|
136
131
|
def send_frame(frame)
|
137
132
|
if closed?
|
138
|
-
|
133
|
+
@session.handle_network_failure(ConnectionClosedError.new(frame))
|
139
134
|
else
|
140
135
|
send_raw(frame.encode)
|
141
136
|
end
|
142
137
|
end
|
143
138
|
|
144
139
|
|
140
|
+
def self.reacheable?(host, port, timeout)
|
141
|
+
begin
|
142
|
+
s = Bunny::Socket.open(host, port,
|
143
|
+
:socket_timeout => timeout)
|
144
|
+
|
145
|
+
true
|
146
|
+
rescue SocketError, Timeout::Error => e
|
147
|
+
false
|
148
|
+
ensure
|
149
|
+
s.close if s
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.ping!(host, port, timeout)
|
154
|
+
raise ConnectionTimeout.new("#{host}:#{port} is unreachable") if !reacheable?(host, port, timeout)
|
155
|
+
end
|
156
|
+
|
157
|
+
|
145
158
|
protected
|
146
159
|
|
147
160
|
def initialize_socket
|
data/lib/bunny/version.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Bunny::Transport, ".reachable?" do
|
4
|
+
it "returns true for google.com, 80" do
|
5
|
+
Bunny::Transport.reacheable?("google.com", 80, 1).should be_true
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns true for google.com, 8088" do
|
9
|
+
Bunny::Transport.reacheable?("google.com", 8088, 1).should be_false
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns false for google1237982792837.com, 8277" do
|
13
|
+
Bunny::Transport.reacheable?("google1237982792837.com", 8277, 1).should be_false
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,213 +1,213 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.0.pre5
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease: 6
|
5
|
+
version: 0.9.0.pre6
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
- Chris Duncan
|
9
|
-
- Eric Lindvall
|
10
|
-
- Jakub Stastny aka botanicus
|
11
|
-
- Michael S. Klishin
|
12
|
-
- Stefan Kaes
|
13
|
-
autorequire:
|
7
|
+
authors:
|
8
|
+
- Chris Duncan
|
9
|
+
- Eric Lindvall
|
10
|
+
- Jakub Stastny aka botanicus
|
11
|
+
- Michael S. Klishin
|
12
|
+
- Stefan Kaes
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
version: 1.0.1
|
31
|
-
none: false
|
32
|
-
prerelease: false
|
33
|
-
type: :runtime
|
16
|
+
|
17
|
+
date: 2013-01-14 00:00:00 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: amq-protocol
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.0.1
|
28
|
+
type: :runtime
|
29
|
+
version_requirements: *id001
|
34
30
|
description: Easy to use synchronous Ruby client for RabbitMQ
|
35
|
-
email:
|
36
|
-
-
|
37
|
-
|
38
|
-
-
|
39
|
-
|
40
|
-
-
|
41
|
-
c3Rhc3RueUAxMDFpZGVhcy5jeg==
|
42
|
-
- !binary |-
|
43
|
-
bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=
|
44
|
-
- !binary |-
|
45
|
-
c2thZXNAcmFpbHNleHByZXNzLmRl
|
31
|
+
email:
|
32
|
+
- celldee@gmail.com
|
33
|
+
- eric@5stops.com
|
34
|
+
- stastny@101ideas.cz
|
35
|
+
- michael@novemberain.com
|
36
|
+
- skaes@railsexpress.de
|
46
37
|
executables: []
|
38
|
+
|
47
39
|
extensions: []
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
- .
|
53
|
-
- .
|
54
|
-
- .
|
55
|
-
-
|
56
|
-
-
|
57
|
-
-
|
58
|
-
-
|
59
|
-
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
- examples/connection/
|
63
|
-
- examples/
|
64
|
-
- examples/
|
65
|
-
- examples/
|
66
|
-
- examples/
|
67
|
-
- examples/
|
68
|
-
- examples/
|
69
|
-
- examples/guides/
|
70
|
-
- examples/guides/
|
71
|
-
- examples/guides/
|
72
|
-
- examples/guides/
|
73
|
-
- examples/guides/extensions/
|
74
|
-
- examples/guides/extensions/
|
75
|
-
- examples/guides/extensions/
|
76
|
-
- examples/guides/extensions/
|
77
|
-
- examples/guides/
|
78
|
-
- examples/guides/
|
79
|
-
- examples/guides/
|
80
|
-
- examples/guides/
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
-
|
85
|
-
-
|
86
|
-
-
|
87
|
-
- lib/bunny
|
88
|
-
- lib/bunny/
|
89
|
-
- lib/bunny/
|
90
|
-
- lib/bunny/
|
91
|
-
- lib/bunny/
|
92
|
-
- lib/bunny/
|
93
|
-
- lib/bunny/
|
94
|
-
- lib/bunny/
|
95
|
-
- lib/bunny/
|
96
|
-
- lib/bunny/
|
97
|
-
- lib/bunny/
|
98
|
-
- lib/bunny/
|
99
|
-
- lib/bunny/
|
100
|
-
- lib/bunny/
|
101
|
-
- lib/bunny/
|
102
|
-
- lib/bunny/
|
103
|
-
- lib/bunny/
|
104
|
-
- lib/bunny/
|
105
|
-
- lib/bunny/
|
106
|
-
-
|
107
|
-
-
|
108
|
-
-
|
109
|
-
-
|
110
|
-
-
|
111
|
-
-
|
112
|
-
- spec/
|
113
|
-
- spec/higher_level_api/integration/
|
114
|
-
- spec/higher_level_api/integration/
|
115
|
-
- spec/higher_level_api/integration/
|
116
|
-
- spec/higher_level_api/integration/
|
117
|
-
- spec/higher_level_api/integration/
|
118
|
-
- spec/higher_level_api/integration/
|
119
|
-
- spec/higher_level_api/integration/
|
120
|
-
- spec/higher_level_api/integration/
|
121
|
-
- spec/higher_level_api/integration/
|
122
|
-
- spec/higher_level_api/integration/
|
123
|
-
- spec/higher_level_api/integration/
|
124
|
-
- spec/higher_level_api/integration/
|
125
|
-
- spec/higher_level_api/integration/
|
126
|
-
- spec/higher_level_api/integration/
|
127
|
-
- spec/higher_level_api/integration/
|
128
|
-
- spec/higher_level_api/integration/
|
129
|
-
- spec/higher_level_api/integration/
|
130
|
-
- spec/higher_level_api/integration/
|
131
|
-
- spec/higher_level_api/integration/
|
132
|
-
- spec/higher_level_api/integration/
|
133
|
-
- spec/higher_level_api/integration/
|
134
|
-
- spec/higher_level_api/integration/
|
135
|
-
- spec/higher_level_api/integration/
|
136
|
-
- spec/higher_level_api/integration/
|
137
|
-
- spec/higher_level_api/integration/
|
138
|
-
- spec/higher_level_api/integration/
|
139
|
-
- spec/
|
140
|
-
- spec/
|
141
|
-
- spec/
|
142
|
-
- spec/
|
143
|
-
- spec/
|
144
|
-
- spec/
|
145
|
-
- spec/
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.md
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- .rspec
|
46
|
+
- .travis.yml
|
47
|
+
- .yardopts
|
48
|
+
- ChangeLog.md
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE
|
51
|
+
- README.md
|
52
|
+
- bin/ci/before_build.sh
|
53
|
+
- bunny.gemspec
|
54
|
+
- examples/connection/authentication_failure.rb
|
55
|
+
- examples/connection/automatic_recovery_with_client_named_queues.rb
|
56
|
+
- examples/connection/automatic_recovery_with_multiple_consumers.rb
|
57
|
+
- examples/connection/automatic_recovery_with_server_named_queues.rb
|
58
|
+
- examples/connection/channel_level_exception.rb
|
59
|
+
- examples/connection/heartbeat.rb
|
60
|
+
- examples/connection/unknown_host.rb
|
61
|
+
- examples/guides/exchanges/direct_exchange_routing.rb
|
62
|
+
- examples/guides/exchanges/fanout_exchange_routing.rb
|
63
|
+
- examples/guides/exchanges/headers_exchange_routing.rb
|
64
|
+
- examples/guides/exchanges/mandatory_messages.rb
|
65
|
+
- examples/guides/extensions/alternate_exchange.rb
|
66
|
+
- examples/guides/extensions/basic_nack.rb
|
67
|
+
- examples/guides/extensions/consumer_cancellation_notification.rb
|
68
|
+
- examples/guides/extensions/dead_letter_exchange.rb
|
69
|
+
- examples/guides/extensions/exchange_to_exchange_bindings.rb
|
70
|
+
- examples/guides/extensions/per_message_ttl.rb
|
71
|
+
- examples/guides/extensions/per_queue_message_ttl.rb
|
72
|
+
- examples/guides/extensions/publisher_confirms.rb
|
73
|
+
- examples/guides/extensions/queue_lease.rb
|
74
|
+
- examples/guides/extensions/sender_selected_distribution.rb
|
75
|
+
- examples/guides/getting_started/blabbr.rb
|
76
|
+
- examples/guides/getting_started/hello_world.rb
|
77
|
+
- examples/guides/getting_started/weathr.rb
|
78
|
+
- examples/guides/queues/redeliveries.rb
|
79
|
+
- lib/bunny.rb
|
80
|
+
- lib/bunny/authentication/credentials_encoder.rb
|
81
|
+
- lib/bunny/authentication/external_mechanism_encoder.rb
|
82
|
+
- lib/bunny/authentication/plain_mechanism_encoder.rb
|
83
|
+
- lib/bunny/channel.rb
|
84
|
+
- lib/bunny/channel_id_allocator.rb
|
85
|
+
- lib/bunny/compatibility.rb
|
86
|
+
- lib/bunny/concurrent/condition.rb
|
87
|
+
- lib/bunny/consumer.rb
|
88
|
+
- lib/bunny/consumer_tag_generator.rb
|
89
|
+
- lib/bunny/consumer_work_pool.rb
|
90
|
+
- lib/bunny/delivery_info.rb
|
91
|
+
- lib/bunny/exceptions.rb
|
92
|
+
- lib/bunny/exchange.rb
|
93
|
+
- lib/bunny/framing.rb
|
94
|
+
- lib/bunny/heartbeat_sender.rb
|
95
|
+
- lib/bunny/main_loop.rb
|
96
|
+
- lib/bunny/message_properties.rb
|
97
|
+
- lib/bunny/queue.rb
|
98
|
+
- lib/bunny/return_info.rb
|
99
|
+
- lib/bunny/session.rb
|
100
|
+
- lib/bunny/socket.rb
|
101
|
+
- lib/bunny/system_timer.rb
|
102
|
+
- lib/bunny/transport.rb
|
103
|
+
- lib/bunny/version.rb
|
104
|
+
- spec/compatibility/queue_declare_spec.rb
|
105
|
+
- spec/higher_level_api/integration/basic_ack_spec.rb
|
106
|
+
- spec/higher_level_api/integration/basic_cancel_spec.rb
|
107
|
+
- spec/higher_level_api/integration/basic_consume_spec.rb
|
108
|
+
- spec/higher_level_api/integration/basic_get_spec.rb
|
109
|
+
- spec/higher_level_api/integration/basic_nack_spec.rb
|
110
|
+
- spec/higher_level_api/integration/basic_publish_spec.rb
|
111
|
+
- spec/higher_level_api/integration/basic_qos_spec.rb
|
112
|
+
- spec/higher_level_api/integration/basic_recover_spec.rb
|
113
|
+
- spec/higher_level_api/integration/basic_reject_spec.rb
|
114
|
+
- spec/higher_level_api/integration/basic_return_spec.rb
|
115
|
+
- spec/higher_level_api/integration/channel_close_spec.rb
|
116
|
+
- spec/higher_level_api/integration/channel_flow_spec.rb
|
117
|
+
- spec/higher_level_api/integration/channel_open_spec.rb
|
118
|
+
- spec/higher_level_api/integration/channel_open_stress_spec.rb
|
119
|
+
- spec/higher_level_api/integration/confirm_select_spec.rb
|
120
|
+
- spec/higher_level_api/integration/connection_spec.rb
|
121
|
+
- spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb
|
122
|
+
- spec/higher_level_api/integration/dead_lettering_spec.rb
|
123
|
+
- spec/higher_level_api/integration/exchange_bind_spec.rb
|
124
|
+
- spec/higher_level_api/integration/exchange_declare_spec.rb
|
125
|
+
- spec/higher_level_api/integration/exchange_delete_spec.rb
|
126
|
+
- spec/higher_level_api/integration/exchange_unbind_spec.rb
|
127
|
+
- spec/higher_level_api/integration/message_properties_access_spec.rb
|
128
|
+
- spec/higher_level_api/integration/publisher_confirms_spec.rb
|
129
|
+
- spec/higher_level_api/integration/queue_bind_spec.rb
|
130
|
+
- spec/higher_level_api/integration/queue_declare_spec.rb
|
131
|
+
- spec/higher_level_api/integration/queue_delete_spec.rb
|
132
|
+
- spec/higher_level_api/integration/queue_purge_spec.rb
|
133
|
+
- spec/higher_level_api/integration/queue_unbind_spec.rb
|
134
|
+
- spec/higher_level_api/integration/sender_selected_distribution_spec.rb
|
135
|
+
- spec/higher_level_api/integration/tx_commit_spec.rb
|
136
|
+
- spec/higher_level_api/integration/tx_rollback_spec.rb
|
137
|
+
- spec/issues/issue78_spec.rb
|
138
|
+
- spec/issues/issue83_spec.rb
|
139
|
+
- spec/lower_level_api/integration/basic_cancel_spec.rb
|
140
|
+
- spec/lower_level_api/integration/basic_consume_spec.rb
|
141
|
+
- spec/spec_helper.rb
|
142
|
+
- spec/unit/bunny_spec.rb
|
143
|
+
- spec/unit/concurrent/condition_spec.rb
|
144
|
+
- spec/unit/transport_spec.rb
|
146
145
|
homepage: http://github.com/ruby-amqp/bunny
|
147
|
-
licenses:
|
148
|
-
- MIT
|
149
|
-
post_install_message:
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
post_install_message:
|
150
149
|
rdoc_options: []
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
- - ! '>='
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
version: !binary |-
|
158
|
-
MA==
|
150
|
+
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
154
|
none: false
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
version: 1.3.1
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: "0"
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
160
|
none: false
|
161
|
+
requirements:
|
162
|
+
- - ">"
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 1.3.1
|
167
165
|
requirements: []
|
168
|
-
|
166
|
+
|
167
|
+
rubyforge_project:
|
169
168
|
rubygems_version: 1.8.24
|
170
|
-
signing_key:
|
169
|
+
signing_key:
|
171
170
|
specification_version: 3
|
172
171
|
summary: Easy to use synchronous Ruby client for RabbitMQ
|
173
|
-
test_files:
|
174
|
-
- spec/compatibility/queue_declare_spec.rb
|
175
|
-
- spec/higher_level_api/integration/basic_ack_spec.rb
|
176
|
-
- spec/higher_level_api/integration/basic_cancel_spec.rb
|
177
|
-
- spec/higher_level_api/integration/basic_consume_spec.rb
|
178
|
-
- spec/higher_level_api/integration/basic_get_spec.rb
|
179
|
-
- spec/higher_level_api/integration/basic_nack_spec.rb
|
180
|
-
- spec/higher_level_api/integration/basic_publish_spec.rb
|
181
|
-
- spec/higher_level_api/integration/basic_qos_spec.rb
|
182
|
-
- spec/higher_level_api/integration/basic_recover_spec.rb
|
183
|
-
- spec/higher_level_api/integration/basic_reject_spec.rb
|
184
|
-
- spec/higher_level_api/integration/basic_return_spec.rb
|
185
|
-
- spec/higher_level_api/integration/channel_close_spec.rb
|
186
|
-
- spec/higher_level_api/integration/channel_flow_spec.rb
|
187
|
-
- spec/higher_level_api/integration/channel_open_spec.rb
|
188
|
-
- spec/higher_level_api/integration/channel_open_stress_spec.rb
|
189
|
-
- spec/higher_level_api/integration/confirm_select_spec.rb
|
190
|
-
- spec/higher_level_api/integration/connection_spec.rb
|
191
|
-
- spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb
|
192
|
-
- spec/higher_level_api/integration/dead_lettering_spec.rb
|
193
|
-
- spec/higher_level_api/integration/exchange_bind_spec.rb
|
194
|
-
- spec/higher_level_api/integration/exchange_declare_spec.rb
|
195
|
-
- spec/higher_level_api/integration/exchange_delete_spec.rb
|
196
|
-
- spec/higher_level_api/integration/exchange_unbind_spec.rb
|
197
|
-
- spec/higher_level_api/integration/message_properties_access_spec.rb
|
198
|
-
- spec/higher_level_api/integration/publisher_confirms_spec.rb
|
199
|
-
- spec/higher_level_api/integration/queue_bind_spec.rb
|
200
|
-
- spec/higher_level_api/integration/queue_declare_spec.rb
|
201
|
-
- spec/higher_level_api/integration/queue_delete_spec.rb
|
202
|
-
- spec/higher_level_api/integration/queue_purge_spec.rb
|
203
|
-
- spec/higher_level_api/integration/queue_unbind_spec.rb
|
204
|
-
- spec/higher_level_api/integration/sender_selected_distribution_spec.rb
|
205
|
-
- spec/higher_level_api/integration/tx_commit_spec.rb
|
206
|
-
- spec/higher_level_api/integration/tx_rollback_spec.rb
|
207
|
-
- spec/issues/issue78_spec.rb
|
208
|
-
- spec/issues/issue83_spec.rb
|
209
|
-
- spec/lower_level_api/integration/basic_cancel_spec.rb
|
210
|
-
- spec/lower_level_api/integration/basic_consume_spec.rb
|
211
|
-
- spec/spec_helper.rb
|
212
|
-
- spec/unit/bunny_spec.rb
|
213
|
-
- spec/unit/concurrent/condition_spec.rb
|
172
|
+
test_files:
|
173
|
+
- spec/compatibility/queue_declare_spec.rb
|
174
|
+
- spec/higher_level_api/integration/basic_ack_spec.rb
|
175
|
+
- spec/higher_level_api/integration/basic_cancel_spec.rb
|
176
|
+
- spec/higher_level_api/integration/basic_consume_spec.rb
|
177
|
+
- spec/higher_level_api/integration/basic_get_spec.rb
|
178
|
+
- spec/higher_level_api/integration/basic_nack_spec.rb
|
179
|
+
- spec/higher_level_api/integration/basic_publish_spec.rb
|
180
|
+
- spec/higher_level_api/integration/basic_qos_spec.rb
|
181
|
+
- spec/higher_level_api/integration/basic_recover_spec.rb
|
182
|
+
- spec/higher_level_api/integration/basic_reject_spec.rb
|
183
|
+
- spec/higher_level_api/integration/basic_return_spec.rb
|
184
|
+
- spec/higher_level_api/integration/channel_close_spec.rb
|
185
|
+
- spec/higher_level_api/integration/channel_flow_spec.rb
|
186
|
+
- spec/higher_level_api/integration/channel_open_spec.rb
|
187
|
+
- spec/higher_level_api/integration/channel_open_stress_spec.rb
|
188
|
+
- spec/higher_level_api/integration/confirm_select_spec.rb
|
189
|
+
- spec/higher_level_api/integration/connection_spec.rb
|
190
|
+
- spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb
|
191
|
+
- spec/higher_level_api/integration/dead_lettering_spec.rb
|
192
|
+
- spec/higher_level_api/integration/exchange_bind_spec.rb
|
193
|
+
- spec/higher_level_api/integration/exchange_declare_spec.rb
|
194
|
+
- spec/higher_level_api/integration/exchange_delete_spec.rb
|
195
|
+
- spec/higher_level_api/integration/exchange_unbind_spec.rb
|
196
|
+
- spec/higher_level_api/integration/message_properties_access_spec.rb
|
197
|
+
- spec/higher_level_api/integration/publisher_confirms_spec.rb
|
198
|
+
- spec/higher_level_api/integration/queue_bind_spec.rb
|
199
|
+
- spec/higher_level_api/integration/queue_declare_spec.rb
|
200
|
+
- spec/higher_level_api/integration/queue_delete_spec.rb
|
201
|
+
- spec/higher_level_api/integration/queue_purge_spec.rb
|
202
|
+
- spec/higher_level_api/integration/queue_unbind_spec.rb
|
203
|
+
- spec/higher_level_api/integration/sender_selected_distribution_spec.rb
|
204
|
+
- spec/higher_level_api/integration/tx_commit_spec.rb
|
205
|
+
- spec/higher_level_api/integration/tx_rollback_spec.rb
|
206
|
+
- spec/issues/issue78_spec.rb
|
207
|
+
- spec/issues/issue83_spec.rb
|
208
|
+
- spec/lower_level_api/integration/basic_cancel_spec.rb
|
209
|
+
- spec/lower_level_api/integration/basic_consume_spec.rb
|
210
|
+
- spec/spec_helper.rb
|
211
|
+
- spec/unit/bunny_spec.rb
|
212
|
+
- spec/unit/concurrent/condition_spec.rb
|
213
|
+
- spec/unit/transport_spec.rb
|