right_amqp 0.3.3 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- @brokers.map { |b| b.identity } - each_usable.map { |b| b.identity }
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, @exceptions, @options, existing)
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):: Explicitly acknowledge received messages to AMQP
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
- @exceptions.track("close", e)
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" => @brokers.map { |b| b.stats },
846
- "exceptions" => @exceptions.stats,
847
- "heartbeat" => @options[:heartbeat],
848
- "returns" => @returns.all
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
- @returns = RightSupport::Stats::Activity.new
862
- @exceptions = RightSupport::Stats::Exceptions.new(self, @options[:exception_callback])
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, @exceptions, @options, nil)
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, to, context)
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
- @returns.update("#{alias_(identity)} (#{reason.to_s.downcase})")
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
- @returns.update("#{alias_(identity)} (#{reason.to_s.downcase} - missing context)")
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
- @exceptions.track("return", e)
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.3.3'
28
- spec.date = '2012-10-30'
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, :has_failed
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' do
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