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
@@ -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)
|
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)
|
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
|
-
@
|
303
|
+
@failed = true
|
295
304
|
close_connection
|
296
305
|
end
|
297
306
|
|
298
307
|
private
|
299
308
|
|
300
309
|
def disconnected
|
301
|
-
unless @
|
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 :
|
68
|
+
attr_reader :disconnect_stats
|
69
69
|
|
70
70
|
# (RightSupport::Stats::Activity) AMQP connection failure statistics
|
71
|
-
attr_reader :
|
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
|
-
#
|
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,
|
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
|
121
|
-
@
|
122
|
-
@
|
123
|
-
@
|
124
|
-
@
|
125
|
-
@
|
126
|
-
@
|
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
|
-
@
|
132
|
-
@
|
133
|
-
@last_failed
|
134
|
-
@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
|
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
|
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
|
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)::
|
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
|
-
#
|
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 = {}, &
|
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
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
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
|
-
@
|
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, &
|
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 {
|
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
|
-
@
|
309
|
-
|
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
|
-
@
|
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
|
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
|
-
@
|
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
|
-
@
|
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, &
|
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
|
-
@
|
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 => @
|
520
|
-
:failures => @
|
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" => @
|
541
|
-
"disconnects" => RightSupport::Stats.nil_if_zero(@
|
542
|
-
"failure last" => @
|
543
|
-
"failures" => RightSupport::Stats.nil_if_zero(@
|
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
|
-
@
|
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
|
-
@
|
580
|
+
@failure_stats.update
|
617
581
|
logger.exception("Failed connecting to broker #{@alias}", e, :trace)
|
618
|
-
@
|
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,
|
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
|
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.
|
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
|
658
|
-
@
|
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
|
-
@
|
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
|