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.
@@ -247,7 +247,13 @@ module AMQP
247
247
  def reconnect force = false
248
248
  if @reconnecting and not force
249
249
  # Wait after first reconnect attempt and in between each subsequent attempt
250
- EM.add_timer(@settings[:reconnect_interval] || 5) { reconnect(true) }
250
+ EM.add_timer(@settings[:reconnect_interval] || 5) do
251
+ begin
252
+ reconnect(true)
253
+ rescue Exception => e
254
+ logger.exception("[amqp] Failed to reconnect", e, :trace)
255
+ end
256
+ end
251
257
  return
252
258
  end
253
259
 
@@ -265,7 +271,13 @@ module AMQP
265
271
  again = again.call if again.is_a?(Proc)
266
272
  if again.is_a?(Numeric)
267
273
  # Wait before making initial reconnect attempt
268
- EM.add_timer(again) { reconnect(true) }
274
+ EM.add_timer(again) do
275
+ begin
276
+ reconnect(true)
277
+ rescue Exception => e
278
+ logger.exception("[amqp] Failed to reconnect", e, :trace)
279
+ end
280
+ end
269
281
  return
270
282
  elsif ![nil, true].include?(again)
271
283
  raise ::AMQP::Error, "Could not interpret :reconnect_delay => #{again.inspect}; expected nil, true, or Numeric"
@@ -275,9 +287,6 @@ module AMQP
275
287
  log 'reconnecting'
276
288
  logger.info("[amqp] Attempting to reconnect to #{@settings[:identity]}")
277
289
  EM.reconnect(@settings[:host], @settings[:port], self)
278
- rescue Exception => e
279
- logger.exception("[amqp] Failed to reconnect", e, :trace)
280
- failed
281
290
  end
282
291
 
283
292
  def self.connect opts = {}
@@ -291,14 +300,14 @@ module AMQP
291
300
 
292
301
  def failed
293
302
  @connection_status.call(:failed) if @connection_status
294
- @has_failed = true
303
+ @failed = true
295
304
  close_connection
296
305
  end
297
306
 
298
307
  private
299
308
 
300
309
  def disconnected
301
- unless @has_failed
310
+ unless @failed
302
311
  @connection_status.call(:disconnected) if @connection_status
303
312
  reconnect
304
313
  end
@@ -65,10 +65,10 @@ module RightAMQP
65
65
  attr_reader :last_failed
66
66
 
67
67
  # (RightSupport::Stats::Activity) AMQP lost connection statistics
68
- attr_reader :disconnects
68
+ attr_reader :disconnect_stats
69
69
 
70
70
  # (RightSupport::Stats::Activity) AMQP connection failure statistics
71
- attr_reader :failures
71
+ attr_reader :failure_stats
72
72
 
73
73
  # (Integer) Number of attempts to connect after failure
74
74
  attr_reader :retries
@@ -83,7 +83,10 @@ module RightAMQP
83
83
  # :index(String):: Unique index for broker within set of brokers for use in forming alias
84
84
  # serializer(Serializer):: Serializer used for unmarshaling received messages to packets
85
85
  # (responds to :load); if nil, has same effect as setting subscribe option :no_unserialize
86
- # exceptions(RightSupport::Stats::Exceptions):: Exception statistics container
86
+ # exception_stats(RightSupport::Stats::Exceptions):: Exception statistics container to be updated
87
+ # whenever there is an unexpected exception
88
+ # non_delivery_stats(RightSupport::Stats::Activity):: Non-delivery statistics container to be
89
+ # updated whenever a message cannot be sent or received
87
90
  # options(Hash):: Configuration options
88
91
  # :user(String):: User name
89
92
  # :pass(String):: Password
@@ -96,17 +99,28 @@ module RightAMQP
96
99
  # :prefetch(Integer):: Maximum number of messages the AMQP broker is to prefetch for the agent
97
100
  # before it receives an ack. Value 1 ensures that only last unacknowledged gets redelivered
98
101
  # if the agent crashes. Value 0 means unlimited prefetch.
102
+ # :fiber_pool(NB::FiberPool):: Pool of initialized fibers to be used for asynchronous message
103
+ # processing (can be overridden with subscribe option)
99
104
  # :exception_on_receive_callback(Proc):: Callback activated on a receive exception with parameters
100
105
  # message(Object):: Message received
101
106
  # exception(Exception):: Exception raised
102
107
  # :update_status_callback(Proc):: Callback activated on a connection status change with parameters
103
108
  # broker(BrokerClient):: Broker client
104
109
  # connected_before(Boolean):: Whether was connected prior to this status change
110
+ # :return_message_callback(Proc):: Callback activated when a message is returned with parameters
111
+ # to(String):: Queue to which message was published
112
+ # reason(String):: Reason for return
113
+ # "NO_ROUTE" - queue does not exist
114
+ # "NO_CONSUMERS" - queue exists but it has no consumers, or if :immediate was specified,
115
+ # all consumers are not immediately ready to consume
116
+ # "ACCESS_REFUSED" - queue not usable because broker is in the process of stopping service
117
+ # message(String):: Returned serialized message
118
+ #
105
119
  # existing(BrokerClient|nil):: Existing broker client for this address, or nil if none
106
120
  #
107
121
  # === Raise
108
122
  # ArgumentError:: If serializer does not respond to :dump and :load
109
- def initialize(identity, address, serializer, exceptions, options, existing = nil)
123
+ def initialize(identity, address, serializer, exception_stats, non_delivery_stats, options, existing = nil)
110
124
  @options = options
111
125
  @identity = identity
112
126
  @host = address[:host]
@@ -117,21 +131,22 @@ module RightAMQP
117
131
  unless serializer.nil? || [:dump, :load].all? { |m| serializer.respond_to?(m) }
118
132
  raise ArgumentError, "serializer must be a class/object that responds to :dump and :load"
119
133
  end
120
- @serializer = serializer
121
- @exceptions = exceptions
122
- @queues = []
123
- @last_failed = false
124
- @disconnects = RightSupport::Stats::Activity.new(measure_rate = false)
125
- @failures = RightSupport::Stats::Activity.new(measure_rate = false)
126
- @retries = 0
134
+ @serializer = serializer
135
+ @queues = []
136
+ @last_failed = false
137
+ @exception_stats = exception_stats
138
+ @non_delivery_stats = non_delivery_stats
139
+ @disconnect_stats = RightSupport::Stats::Activity.new(measure_rate = false)
140
+ @failure_stats = RightSupport::Stats::Activity.new(measure_rate = false)
141
+ @retries = 0
127
142
 
128
143
  connect(address, @options[:reconnect_interval])
129
144
 
130
145
  if existing
131
- @disconnects = existing.disconnects
132
- @failures = existing.failures
133
- @last_failed = existing.last_failed
134
- @retries = existing.retries
146
+ @disconnect_stats = existing.disconnect_stats
147
+ @failure_stats = existing.failure_stats
148
+ @last_failed = existing.last_failed
149
+ @retries = existing.retries
135
150
  update_failure if @status == :failed
136
151
  end
137
152
  end
@@ -174,22 +189,23 @@ module RightAMQP
174
189
  # Subscribe an AMQP queue to an AMQP exchange
175
190
  # Do not wait for confirmation from broker that subscription is complete
176
191
  # When a message is received, acknowledge, unserialize, and log it as specified
177
- # If the message is unserialized and it is not of the right type, it is dropped after logging a warning
192
+ # If the message is unserialized and it is not of the right type, it is dropped after logging an error
178
193
  #
179
194
  # === Parameters
180
195
  # queue(Hash):: AMQP queue being subscribed with keys :name and :options,
181
196
  # which are the standard AMQP ones plus
182
197
  # :no_declare(Boolean):: Whether to skip declaring this queue on the broker
183
- # to cause its creation; for use when client does not have permission to create or
198
+ # to cause its creation; for use when caller does not have permission to create or
184
199
  # knows the queue already exists and wants to avoid declare overhead
185
200
  # exchange(Hash|nil):: AMQP exchange to subscribe to with keys :type, :name, and :options,
186
201
  # nil means use empty exchange by directly subscribing to queue; the :options are the
187
202
  # standard AMQP ones plus
188
203
  # :no_declare(Boolean):: Whether to skip declaring this exchange on the broker
189
- # to cause its creation; for use when client does not have create permission or
204
+ # to cause its creation; for use when caller does not have create permission or
190
205
  # knows the exchange already exists and wants to avoid declare overhead
191
206
  # options(Hash):: Subscribe options:
192
- # :ack(Boolean):: Explicitly acknowledge received messages to AMQP
207
+ # :ack(Boolean):: Whether caller takes responsibility for explicitly acknowledging each
208
+ # message received, defaults to implicit acknowledgement in AMQP as part of message receipt
193
209
  # :no_unserialize(Boolean):: Do not unserialize message, this is an escape for special
194
210
  # situations like enrollment, also implicitly disables receive filtering and logging;
195
211
  # this option is implicitly invoked if initialize without a serializer
@@ -200,16 +216,22 @@ module RightAMQP
200
216
  # :no_log(Boolean):: Disable receive logging unless debug level
201
217
  # :exchange2(Hash):: Additional exchange to which same queue is to be bound
202
218
  # :brokers(Array):: Identity of brokers for which to subscribe, defaults to all usable if nil or empty
219
+ # :fiber_pool(NB::FiberPool):: Pool of initialized fibers to be used for asynchronous message
220
+ # processing (non-nil value will override constructor option setting)
203
221
  #
204
222
  # === Block
205
- # Block with following parameters to be called each time exchange matches a message to the queue:
223
+ # Required block with following parameters to be called each time exchange matches a message to the queue
206
224
  # identity(String):: Serialized identity of broker delivering the message
207
225
  # message(Packet|String):: Message received, which is unserialized unless :no_unserialize was specified
208
226
  # header(AMQP::Protocol::Header):: Message header (optional block parameter)
209
227
  #
228
+ # === Raise
229
+ # ArgumentError:: If a block is not supplied
230
+ #
210
231
  # === Return
211
232
  # (Boolean):: true if subscribe successfully or if already subscribed, otherwise false
212
- def subscribe(queue, exchange = nil, options = {}, &blk)
233
+ def subscribe(queue, exchange = nil, options = {}, &block)
234
+ raise ArgumentError, "Must call this method with a block" unless block
213
235
  return false unless usable?
214
236
  return true unless @queues.select { |q| q.name == queue[:name] }.empty?
215
237
 
@@ -235,52 +257,24 @@ module RightAMQP
235
257
  end
236
258
  q = binding
237
259
  end
238
- if options[:ack]
239
- q.subscribe(:ack => true) do |header, message|
240
- begin
241
- # Ack now before processing to avoid risk of duplication after a crash
242
- header.ack
243
- if options[:no_unserialize] || @serializer.nil?
244
- execute_callback(blk, @identity, message, header)
245
- elsif message == "nil"
246
- # This happens as part of connecting an instance agent to a broker prior to version 13
247
- logger.debug("RECV #{@alias} nil message ignored")
248
- elsif
249
- packet = receive(queue[:name], message, options)
250
- execute_callback(blk, @identity, packet, header) if packet
251
- end
252
- true
253
- rescue Exception => e
254
- logger.exception("Failed executing block for message from queue #{queue.inspect}#{to_exchange} " +
255
- "on broker #{@alias}", e, :trace)
256
- @exceptions.track("receive", e)
257
- false
258
- end
259
- end
260
- else
261
- q.subscribe do |header, message|
262
- begin
263
- if options[:no_unserialize] || @serializer.nil?
264
- execute_callback(blk, @identity, message, header)
265
- elsif message == "nil"
266
- # This happens as part of connecting an instance agent to a broker
267
- logger.debug("RECV #{@alias} nil message ignored")
268
- elsif
269
- packet = receive(queue[:name], message, options)
270
- execute_callback(blk, @identity, packet, header) if packet
271
- end
272
- true
273
- rescue Exception => e
274
- logger.exception("Failed executing block for message from queue #{queue.inspect}#{to_exchange} " +
275
- "on broker #{@alias}", e, :trace)
276
- @exceptions.track("receive", e)
277
- false
260
+ q.subscribe(options[:ack] ? {:ack => true} : {}) do |header, message|
261
+ begin
262
+ if pool = (options[:fiber_pool] || @options[:fiber_pool])
263
+ pool.spawn { receive(queue[:name], header, message, options, &block) }
264
+ else
265
+ receive(queue[:name], header, message, options, &block)
278
266
  end
267
+ rescue Exception => e
268
+ header.ack if options[:ack]
269
+ logger.exception("Failed setting up to receive message from queue #{queue.inspect} " +
270
+ "on broker #{@alias}", e, :trace)
271
+ @exception_stats.track("receive", e)
272
+ @non_delivery_stats.update("receive failure")
279
273
  end
280
274
  end
281
275
  rescue Exception => e
282
276
  logger.exception("Failed subscribing queue #{queue.inspect}#{to_exchange} on broker #{@alias}", e, :trace)
283
- @exceptions.track("subscribe", e)
277
+ @exception_stats.track("subscribe", e)
284
278
  false
285
279
  end
286
280
  end
@@ -296,17 +290,17 @@ module RightAMQP
296
290
  #
297
291
  # === Return
298
292
  # true:: Always return true
299
- def unsubscribe(queue_names, &blk)
293
+ def unsubscribe(queue_names, &block)
300
294
  if usable?
301
295
  @queues.each do |q|
302
296
  if queue_names.include?(q.name)
303
297
  begin
304
298
  logger.info("[stop] Unsubscribing queue #{q.name} on broker #{@alias}")
305
- q.unsubscribe { blk.call if blk }
299
+ q.unsubscribe { block.call if block }
306
300
  rescue Exception => e
307
301
  logger.exception("Failed unsubscribing queue #{q.name} on broker #{@alias}", e, :trace)
308
- @exceptions.track("unsubscribe", e)
309
- blk.call if blk
302
+ @exception_stats.track("unsubscribe", e)
303
+ block.call if block
310
304
  end
311
305
  end
312
306
  end
@@ -332,7 +326,7 @@ module RightAMQP
332
326
  true
333
327
  rescue Exception => e
334
328
  logger.exception("Failed declaring #{type.to_s} #{name} on broker #{@alias}", e, :trace)
335
- @exceptions.track("declare", e)
329
+ @exception_stats.track("declare", e)
336
330
  false
337
331
  end
338
332
  end
@@ -343,7 +337,7 @@ module RightAMQP
343
337
  # exchange(Hash):: AMQP exchange to subscribe to with keys :type, :name, and :options,
344
338
  # which are the standard AMQP ones plus
345
339
  # :no_declare(Boolean):: Whether to skip declaring this exchange or queue on the broker
346
- # to cause its creation; for use when client does not have create permission or
340
+ # to cause its creation; for use when caller does not have create permission or
347
341
  # knows the object already exists and wants to avoid declare overhead
348
342
  # :declare(Boolean):: Whether to delete this exchange or queue from the AMQP cache
349
343
  # to force it to be declared on the broker and thus be created if it does not exist
@@ -382,44 +376,12 @@ module RightAMQP
382
376
  true
383
377
  rescue Exception => e
384
378
  logger.exception("Failed publishing to exchange #{exchange.inspect} on broker #{@alias}", e, :trace)
385
- @exceptions.track("publish", e)
379
+ @exception_stats.track("publish", e)
380
+ @non_delivery_stats.update("publish failure")
386
381
  false
387
382
  end
388
383
  end
389
384
 
390
- # Provide callback to be activated when broker returns a message that could not be delivered
391
- # A message published with :mandatory => true is returned if the exchange does not have any associated queues
392
- # or if all the associated queues do not have any consumers
393
- # A message published with :immediate => true is returned for the same reasons as :mandatory plus if all
394
- # of the queues associated with the exchange are not immediately ready to consume the message
395
- #
396
- # === Block
397
- # Optional block with following parameters to be called when a message is returned
398
- # to(String):: Queue to which message was published
399
- # reason(String):: Reason for return
400
- # "NO_ROUTE" - queue does not exist
401
- # "NO_CONSUMERS" - queue exists but it has no consumers, or if :immediate was specified,
402
- # all consumers are not immediately ready to consume
403
- # "ACCESS_REFUSED" - queue not usable because broker is in the process of stopping service
404
- # message(String):: Returned serialized message
405
- #
406
- # === Return
407
- # true:: Always return true
408
- def return_message
409
- @channel.return_message do |info, message|
410
- begin
411
- to = if info.exchange && !info.exchange.empty? then info.exchange else info.routing_key end
412
- reason = info.reply_text
413
- logger.debug("RETURN #{@alias} because #{reason} for #{to}")
414
- yield(to, reason, message) if block_given?
415
- rescue Exception => e
416
- logger.exception("Failed return #{info.inspect} of message from broker #{@alias}", e, :trace)
417
- @exceptions.track("return", e)
418
- end
419
- end
420
- true
421
- end
422
-
423
385
  # Delete queue
424
386
  #
425
387
  # === Parameters
@@ -446,7 +408,7 @@ module RightAMQP
446
408
  end
447
409
  rescue Exception => e
448
410
  logger.exception("Failed deleting queue #{name.inspect} on broker #{@alias}", e, :trace)
449
- @exceptions.track("delete", e)
411
+ @exception_stats.track("delete", e)
450
412
  end
451
413
  end
452
414
  deleted
@@ -477,7 +439,7 @@ module RightAMQP
477
439
  #
478
440
  # === Return
479
441
  # true:: Always return true
480
- def close(propagate = true, normal = true, log = true, &blk)
442
+ def close(propagate = true, normal = true, log = true, &block)
481
443
  final_status = normal ? :closed : :failed
482
444
  if ![:closed, :failed].include?(@status)
483
445
  begin
@@ -489,7 +451,7 @@ module RightAMQP
489
451
  end
490
452
  rescue Exception => e
491
453
  logger.exception("Failed to close broker #{@alias}", e, :trace)
492
- @exceptions.track("close", e)
454
+ @exception_stats.track("close", e)
493
455
  @status = final_status
494
456
  yield if block_given?
495
457
  end
@@ -516,8 +478,8 @@ module RightAMQP
516
478
  :alias => @alias,
517
479
  :status => @status,
518
480
  :retries => @retries,
519
- :disconnects => @disconnects.total,
520
- :failures => @failures.total,
481
+ :disconnects => @disconnect_stats.total,
482
+ :failures => @failure_stats.total,
521
483
  }
522
484
  end
523
485
 
@@ -532,15 +494,16 @@ module RightAMQP
532
494
  # "disconnects"(Integer|nil):: Number of times lost connection, or nil if none
533
495
  # "failure last"(Hash|nil):: Last connect failure information with key "elapsed", or nil if none
534
496
  # "failures"(Integer|nil):: Number of failed attempts to connect to broker, or nil if none
497
+ # "retries"(Integer|nil):: Number of connect retries, or nil if none
535
498
  def stats
536
499
  {
537
500
  "alias" => @alias,
538
501
  "identity" => @identity,
539
502
  "status" => @status.to_s,
540
- "disconnect last" => @disconnects.last,
541
- "disconnects" => RightSupport::Stats.nil_if_zero(@disconnects.total),
542
- "failure last" => @failures.last,
543
- "failures" => RightSupport::Stats.nil_if_zero(@failures.total),
503
+ "disconnect last" => @disconnect_stats.last,
504
+ "disconnects" => RightSupport::Stats.nil_if_zero(@disconnect_stats.total),
505
+ "failure last" => @failure_stats.last,
506
+ "failures" => RightSupport::Stats.nil_if_zero(@failure_stats.total),
544
507
  "retries" => RightSupport::Stats.nil_if_zero(@retries)
545
508
  }
546
509
  end
@@ -570,7 +533,7 @@ module RightAMQP
570
533
  elsif status == :failed
571
534
  update_failure
572
535
  elsif status == :disconnected && before != :disconnected
573
- @disconnects.update
536
+ @disconnect_stats.update
574
537
  end
575
538
 
576
539
  unless status == before || @options[:update_status_callback].nil?
@@ -582,7 +545,7 @@ module RightAMQP
582
545
  protected
583
546
 
584
547
  # Connect to broker and register for status updates
585
- # Also set prefetch value if specified
548
+ # Also set prefetch value if specified and setup for message returns
586
549
  #
587
550
  # === Parameters
588
551
  # address(Hash):: Broker address
@@ -611,21 +574,67 @@ module RightAMQP
611
574
  @channel = MQ.new(@connection)
612
575
  @channel.__send__(:connection).connection_status { |status| update_status(status) }
613
576
  @channel.prefetch(@options[:prefetch]) if @options[:prefetch]
577
+ @channel.return_message { |header, message| handle_return(header, message) }
614
578
  rescue Exception => e
615
579
  @status = :failed
616
- @failures.update
580
+ @failure_stats.update
617
581
  logger.exception("Failed connecting to broker #{@alias}", e, :trace)
618
- @exceptions.track("connect", e)
582
+ @exception_stats.track("connect", e)
619
583
  @connection.close if @connection
620
584
  end
621
585
  end
622
586
 
623
- # Receive message by unserializing it, checking that it is an acceptable type, and logging accordingly
587
+ # Receive message by optionally unserializing it, passing it to the callback, and optionally
588
+ # acknowledging it
624
589
  #
625
590
  # === Parameters
626
591
  # queue(String):: Name of queue
592
+ # header(AMQP::Protocol::Header):: Message header
627
593
  # message(String):: Serialized packet
628
- # options(Hash):: Subscribe options:
594
+ # options(Hash):: Subscribe options
595
+ # :ack(Boolean):: Whether caller takes responsibility for explicitly acknowledging each
596
+ # message received, defaults to implicit acknowledgement in AMQP as part of message receipt
597
+ # :no_unserialize(Boolean):: Do not unserialize message, this is an escape for special
598
+ # situations like enrollment, also implicitly disables receive filtering and logging;
599
+ # this option is implicitly invoked if initialize without a serializer
600
+ #
601
+ # === Block
602
+ # Block with following parameters to be called with received message
603
+ # identity(String):: Serialized identity of broker delivering the message
604
+ # message(Packet|String):: Message received, which is unserialized unless :no_unserialize was specified
605
+ # header(AMQP::Protocol::Header):: Message header (optional block parameter)
606
+ #
607
+ # === Return
608
+ # true:: Always return true
609
+ def receive(queue, header, message, options, &block)
610
+ begin
611
+ if options[:no_unserialize] || @serializer.nil?
612
+ execute_callback(block, @identity, message, header)
613
+ elsif message == "nil"
614
+ # This happens as part of connecting an instance agent to a broker prior to version 13
615
+ header.ack if options[:ack]
616
+ logger.debug("RECV #{@alias} nil message ignored")
617
+ elsif packet = unserialize(queue, message, options)
618
+ execute_callback(block, @identity, packet, header)
619
+ elsif options[:ack]
620
+ # Need to ack empty packet since no callback is being made
621
+ header.ack
622
+ end
623
+ true
624
+ rescue Exception => e
625
+ header.ack if options[:ack]
626
+ logger.exception("Failed receiving message from queue #{queue.inspect} on broker #{@alias}", e, :trace)
627
+ @exception_stats.track("receive", e)
628
+ @non_delivery_stats.update("receive failure")
629
+ end
630
+ end
631
+
632
+ # Unserialize message, check that it is an acceptable type, and log it
633
+ #
634
+ # === Parameters
635
+ # queue(String):: Name of queue
636
+ # message(String):: Serialized packet
637
+ # options(Hash):: Subscribe options
629
638
  # (packet class)(Array(Symbol)):: Filters to be applied in to_s when logging packet to :info,
630
639
  # only packet classes specified are accepted, others are not processed but are logged with error
631
640
  # :category(String):: Packet category description to be used in error messages
@@ -634,7 +643,7 @@ module RightAMQP
634
643
  #
635
644
  # === Return
636
645
  # (Packet|nil):: Unserialized packet or nil if not of right type or if there is an exception
637
- def receive(queue, message, options = {})
646
+ def unserialize(queue, message, options = {})
638
647
  begin
639
648
  received_at = Time.now.to_f
640
649
  packet = @serializer.load(message)
@@ -648,15 +657,16 @@ module RightAMQP
648
657
  packet
649
658
  else
650
659
  category = options[:category] + " " if options[:category]
651
- logger.warning("Received invalid #{category}packet type from queue #{queue} on broker #{@alias}: #{packet.class}\n" + caller.join("\n"))
660
+ logger.error("Received invalid #{category}packet type from queue #{queue} on broker #{@alias}: #{packet.class}\n" + caller.join("\n"))
652
661
  nil
653
662
  end
654
663
  rescue Exception => e
655
664
  # TODO Taking advantage of Serializer knowledge here even though out of scope
656
665
  trace = e.class.name =~ /SerializationError/ ? :caller : :trace
657
- logger.exception("Failed receiving from queue #{queue} on #{@alias}", e, trace)
658
- @exceptions.track("receive", e)
666
+ logger.exception("Failed unserializing message from queue #{queue.inspect} on broker #{@alias}", e, trace)
667
+ @exception_stats.track("receive", e)
659
668
  @options[:exception_on_receive_callback].call(message, e) if @options[:exception_on_receive_callback]
669
+ @non_delivery_stats.update("receive failure")
660
670
  nil
661
671
  end
662
672
  end
@@ -682,7 +692,29 @@ module RightAMQP
682
692
  else
683
693
  @last_failed = true
684
694
  @retries = 0
685
- @failures.update
695
+ @failure_stats.update
696
+ end
697
+ true
698
+ end
699
+
700
+ # Handle message returned by broker because it could not deliver it
701
+ #
702
+ # === Parameters
703
+ # header(AMQP::Protocol::Header):: Message header
704
+ # message(String):: Serialized packet
705
+ #
706
+ # === Return
707
+ # true:: Always return true
708
+ def handle_return(header, message)
709
+ begin
710
+ to = if header.exchange && !header.exchange.empty? then header.exchange else header.routing_key end
711
+ reason = header.reply_text
712
+ callback = @options[:return_message_callback]
713
+ logger.__send__(callback ? :debug : :info, "RETURN #{@alias} for #{to} because #{reason}")
714
+ callback.call(@identity, to, reason, message) if callback
715
+ rescue Exception => e
716
+ logger.exception("Failed return #{header.inspect} of message from broker #{@alias}", e, :trace)
717
+ @exception_stats.track("return", e)
686
718
  end
687
719
  true
688
720
  end