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.
@@ -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