right_amqp 0.3.3 → 0.5.2
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/lib/right_amqp/amqp/client.rb +16 -7
- data/lib/right_amqp/ha_client/broker_client.rb +154 -122
- data/lib/right_amqp/ha_client/ha_broker_client.rb +29 -51
- data/right_amqp.gemspec +2 -2
- data/spec/amqp/client_extensions_spec.rb +2 -13
- data/spec/ha_client/broker_client_spec.rb +268 -206
- data/spec/ha_client/ha_broker_client_spec.rb +55 -73
- data/spec/spec_helper.rb +2 -2
- metadata +3 -3
@@ -136,6 +136,7 @@ module RightAMQP
|
|
136
136
|
def initialize(serializer, options = {})
|
137
137
|
@options = options.dup
|
138
138
|
@options[:update_status_callback] = lambda { |b, c| update_status(b, c) }
|
139
|
+
@options[:return_message_callback] = lambda { |i, t, r, m| handle_return(i, t, r, m) }
|
139
140
|
@options[:reconnect_interval] ||= RECONNECT_INTERVAL
|
140
141
|
@connection_status = {}
|
141
142
|
unless serializer.nil? || [:dump, :load].all? { |m| serializer.respond_to?(m) }
|
@@ -149,7 +150,6 @@ module RightAMQP
|
|
149
150
|
@closed = false
|
150
151
|
@brokers_hash = {}
|
151
152
|
@brokers.each { |b| @brokers_hash[b.identity] = b }
|
152
|
-
return_message { |i, r, m, t, c| handle_return(i, r, m, t, c) }
|
153
153
|
end
|
154
154
|
|
155
155
|
# Parse agent user data to extract broker host and port configuration
|
@@ -360,7 +360,7 @@ module RightAMQP
|
|
360
360
|
# === Return
|
361
361
|
# (Array):: Serialized identity of unusable brokers
|
362
362
|
def unusable
|
363
|
-
|
363
|
+
all - usable
|
364
364
|
end
|
365
365
|
|
366
366
|
# Get serialized identity of all brokers
|
@@ -430,7 +430,7 @@ module RightAMQP
|
|
430
430
|
end unless existing
|
431
431
|
|
432
432
|
address = {:host => host, :port => port, :index => index}
|
433
|
-
broker = BrokerClient.new(identity, address, @serializer, @
|
433
|
+
broker = BrokerClient.new(identity, address, @serializer, @exception_stats, @non_delivery_stats, @options, existing)
|
434
434
|
p = priority(old_identity)
|
435
435
|
if priority && priority < p
|
436
436
|
@brokers.insert(priority, broker)
|
@@ -466,7 +466,8 @@ module RightAMQP
|
|
466
466
|
# to cause its creation; for use when client does not have create permission or
|
467
467
|
# knows the exchange already exists and wants to avoid declare overhead
|
468
468
|
# options(Hash):: Subscribe options:
|
469
|
-
# :ack(Boolean)::
|
469
|
+
# :ack(Boolean):: Whether client takes responsibility for explicitly acknowledging each
|
470
|
+
# message received, defaults to implicit acknowledgement in AMQP as part of message receipt
|
470
471
|
# :no_unserialize(Boolean):: Do not unserialize message, this is an escape for special
|
471
472
|
# situations like enrollment, also implicitly disables receive filtering and logging;
|
472
473
|
# this option is implicitly invoked if initialize without a serializer
|
@@ -553,6 +554,10 @@ module RightAMQP
|
|
553
554
|
# to force it to be declared on the broker and thus be created if it does not exist
|
554
555
|
# packet(Packet):: Message to serialize and publish
|
555
556
|
# options(Hash):: Publish options -- standard AMQP ones plus
|
557
|
+
# :mandatory(Boolean):: Return message if the exchange does not have any associated queues
|
558
|
+
# or if all the associated queues do not have any consumers
|
559
|
+
# :immediate(Boolean):: Return message for the same reasons as :mandatory plus if all
|
560
|
+
# of the queues associated with the exchange are not immediately ready to consume the message
|
556
561
|
# :fanout(Boolean):: true means publish to all connected brokers
|
557
562
|
# :brokers(Array):: Identity of brokers selected for use, defaults to all home brokers
|
558
563
|
# if nil or empty
|
@@ -593,38 +598,6 @@ module RightAMQP
|
|
593
598
|
identities
|
594
599
|
end
|
595
600
|
|
596
|
-
# Register callback to be activated when a broker returns a message that could not be delivered
|
597
|
-
# A message published with :mandatory => true is returned if the exchange does not have any associated queues
|
598
|
-
# or if all the associated queues do not have any consumers
|
599
|
-
# A message published with :immediate => true is returned for the same reasons as :mandatory plus if all
|
600
|
-
# of the queues associated with the exchange are not immediately ready to consume the message
|
601
|
-
# Remove any previously registered callback
|
602
|
-
#
|
603
|
-
# === Block
|
604
|
-
# Required block to be called when a message is returned with parameters
|
605
|
-
# identity(String):: Broker serialized identity
|
606
|
-
# reason(String):: Reason for return
|
607
|
-
# "NO_ROUTE" - queue does not exist
|
608
|
-
# "NO_CONSUMERS" - queue exists but it has no consumers, or if :immediate was specified,
|
609
|
-
# all consumers are not immediately ready to consume
|
610
|
-
# "ACCESS_REFUSED" - queue not usable because broker is in the process of stopping service
|
611
|
-
# message(String):: Returned serialized message
|
612
|
-
# to(String):: Queue to which message was published
|
613
|
-
# context(Context|nil):: Message publishing context, or nil if not available
|
614
|
-
#
|
615
|
-
# === Return
|
616
|
-
# true:: Always return true
|
617
|
-
def return_message(&blk)
|
618
|
-
each_usable do |b|
|
619
|
-
b.return_message do |to, reason, message|
|
620
|
-
context = @published.fetch(message)
|
621
|
-
context.record_failure(b.identity) if context
|
622
|
-
blk.call(b.identity, reason, message, to, context)
|
623
|
-
end
|
624
|
-
end
|
625
|
-
true
|
626
|
-
end
|
627
|
-
|
628
601
|
# Provide callback to be activated when a message cannot be delivered
|
629
602
|
#
|
630
603
|
# === Block
|
@@ -748,7 +721,7 @@ module RightAMQP
|
|
748
721
|
rescue Exception => e
|
749
722
|
handler.completed_one
|
750
723
|
logger.exception("Failed to close broker #{b.alias}", e, :trace)
|
751
|
-
@
|
724
|
+
@exception_stats.track("close", e)
|
752
725
|
end
|
753
726
|
end
|
754
727
|
end
|
@@ -838,14 +811,17 @@ module RightAMQP
|
|
838
811
|
# "total"(Integer):: Total exceptions for this category
|
839
812
|
# "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
|
840
813
|
# "heartbeat"(Integer|nil):: Number of seconds between AMQP heartbeats, or nil if heartbeat disabled
|
814
|
+
# "non_deliveries"(Hash|nil):: Non-delivery activity stats with keys "total", "percent", "last", and "rate"
|
815
|
+
# with percentage breakdown per non-delivery reason, or nil if none
|
841
816
|
# "returns"(Hash|nil):: Message return activity stats with keys "total", "percent", "last", and "rate"
|
842
817
|
# with percentage breakdown per return reason, or nil if none
|
843
818
|
def stats(reset = false)
|
844
819
|
stats = {
|
845
|
-
"brokers"
|
846
|
-
"exceptions"
|
847
|
-
"heartbeat"
|
848
|
-
"
|
820
|
+
"brokers" => @brokers.map { |b| b.stats },
|
821
|
+
"exceptions" => @exception_stats.stats,
|
822
|
+
"heartbeat" => @options[:heartbeat],
|
823
|
+
"non-deliveries" => @non_delivery_stats.all,
|
824
|
+
"returns" => @return_stats.all
|
849
825
|
}
|
850
826
|
reset_stats if reset
|
851
827
|
stats
|
@@ -858,8 +834,9 @@ module RightAMQP
|
|
858
834
|
# === Return
|
859
835
|
# true:: Always return true
|
860
836
|
def reset_stats
|
861
|
-
@
|
862
|
-
@
|
837
|
+
@return_stats = RightSupport::Stats::Activity.new
|
838
|
+
@non_delivery_stats = RightSupport::Stats::Activity.new
|
839
|
+
@exception_stats = RightSupport::Stats::Exceptions.new(self, @options[:exception_callback])
|
863
840
|
true
|
864
841
|
end
|
865
842
|
|
@@ -872,7 +849,7 @@ module RightAMQP
|
|
872
849
|
def connect_all
|
873
850
|
self.class.addresses(@options[:host], @options[:port]).map do |a|
|
874
851
|
identity = self.class.identity(a[:host], a[:port])
|
875
|
-
BrokerClient.new(identity, a, @serializer, @
|
852
|
+
BrokerClient.new(identity, a, @serializer, @exception_stats, @non_delivery_stats, @options, nil)
|
876
853
|
end
|
877
854
|
end
|
878
855
|
|
@@ -1029,22 +1006,22 @@ module RightAMQP
|
|
1029
1006
|
#
|
1030
1007
|
# === Parameters
|
1031
1008
|
# identity(String):: Identity of broker that could not deliver message
|
1009
|
+
# to(String):: Queue to which message was published
|
1032
1010
|
# reason(String):: Reason for return
|
1033
1011
|
# "NO_ROUTE" - queue does not exist
|
1034
1012
|
# "NO_CONSUMERS" - queue exists but it has no consumers, or if :immediate was specified,
|
1035
1013
|
# all consumers are not immediately ready to consume
|
1036
1014
|
# "ACCESS_REFUSED" - queue not usable because broker is in the process of stopping service
|
1037
1015
|
# message(String):: Returned message in serialized packet format
|
1038
|
-
# to(String):: Queue to which message was published
|
1039
|
-
# context(Context):: Message publishing context
|
1040
1016
|
#
|
1041
1017
|
# === Return
|
1042
1018
|
# true:: Always return true
|
1043
|
-
def handle_return(identity, reason, message
|
1019
|
+
def handle_return(identity, to, reason, message)
|
1044
1020
|
@brokers_hash[identity].update_status(:stopping) if reason == "ACCESS_REFUSED"
|
1045
1021
|
|
1046
|
-
if context
|
1047
|
-
@
|
1022
|
+
if context = @published.fetch(message)
|
1023
|
+
@return_stats.update("#{alias_(identity)} (#{reason.to_s.downcase})")
|
1024
|
+
context.record_failure(identity)
|
1048
1025
|
name = context.name
|
1049
1026
|
options = context.options || {}
|
1050
1027
|
token = context.token
|
@@ -1064,6 +1041,7 @@ module RightAMQP
|
|
1064
1041
|
t = token ? " <#{token}>" : ""
|
1065
1042
|
logger.info("NO ROUTE #{aliases(context.brokers).join(", ")} [#{name}]#{t} to #{to}")
|
1066
1043
|
@non_delivery.call(reason, context.type, token, context.from, to) if @non_delivery
|
1044
|
+
@non_delivery_stats.update("no route")
|
1067
1045
|
end
|
1068
1046
|
end
|
1069
1047
|
|
@@ -1077,14 +1055,14 @@ module RightAMQP
|
|
1077
1055
|
:persistent => persistent, :mandatory => mandatory))
|
1078
1056
|
end
|
1079
1057
|
else
|
1080
|
-
@
|
1058
|
+
@return_stats.update("#{alias_(identity)} (#{reason.to_s.downcase} - missing context)")
|
1081
1059
|
logger.info("Dropping message returned from broker #{identity} for reason #{reason} " +
|
1082
1060
|
"because no message context available for re-routing it to #{to}")
|
1083
1061
|
end
|
1084
1062
|
true
|
1085
1063
|
rescue Exception => e
|
1086
1064
|
logger.exception("Failed to handle #{reason} return from #{identity} for message being routed to #{to}", e, :trace)
|
1087
|
-
@
|
1065
|
+
@exception_stats.track("return", e)
|
1088
1066
|
end
|
1089
1067
|
|
1090
1068
|
# Helper for deferring block execution until specified number of actions have completed
|
data/right_amqp.gemspec
CHANGED
@@ -24,8 +24,8 @@ require 'rubygems'
|
|
24
24
|
|
25
25
|
Gem::Specification.new do |spec|
|
26
26
|
spec.name = 'right_amqp'
|
27
|
-
spec.version = '0.
|
28
|
-
spec.date = '2012-
|
27
|
+
spec.version = '0.5.2'
|
28
|
+
spec.date = '2012-09-27'
|
29
29
|
spec.authors = ['Lee Kirchhoff']
|
30
30
|
spec.email = 'lee@rightscale.com'
|
31
31
|
spec.homepage = 'https://github.com/rightscale/right_amqp'
|
@@ -33,7 +33,7 @@ describe AMQP::Client do
|
|
33
33
|
class SUT
|
34
34
|
include AMQP::Client
|
35
35
|
|
36
|
-
attr_accessor :reconnecting, :settings, :channels
|
36
|
+
attr_accessor :reconnecting, :settings, :channels
|
37
37
|
end
|
38
38
|
|
39
39
|
before(:each) do
|
@@ -88,7 +88,7 @@ describe AMQP::Client do
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
-
context 'with a :reconnect_interval of 5 seconds'
|
91
|
+
context 'with a :reconnect_interval of 5 seconds' do
|
92
92
|
it 'should schedule reconnect attempts on a 5s interval' do
|
93
93
|
@sut.reconnecting = true
|
94
94
|
@sut.settings[:reconnect_delay] = 15
|
@@ -101,17 +101,6 @@ describe AMQP::Client do
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
context 'with a reconnect failure' do
|
105
|
-
it 'should fail the connection' do
|
106
|
-
@logger.should_receive(:error).with(/Failed to reconnect/).once
|
107
|
-
flexmock(EM).should_receive(:reconnect).and_raise(Exception).once
|
108
|
-
flexmock(@sut).should_receive(:close_connection).once
|
109
|
-
|
110
|
-
@sut.reconnect()
|
111
|
-
@sut.has_failed.should be_true
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
104
|
end
|
116
105
|
|
117
106
|
context "heartbeat" do
|