amq-client 0.7.0.alpha35 → 0.8.0

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.
Files changed (69) hide show
  1. data/.rspec +0 -1
  2. data/.travis.yml +9 -3
  3. data/Gemfile +22 -12
  4. data/amq-client.gemspec +1 -1
  5. data/examples/coolio_adapter/example_helper.rb +2 -0
  6. data/examples/eventmachine_adapter/basic_consume_with_acknowledgements.rb +3 -3
  7. data/examples/eventmachine_adapter/{connection_failure_callback.rb → error_handling/connection_failure_callback.rb} +4 -8
  8. data/examples/eventmachine_adapter/{connection_failure_exception.rb → error_handling/connection_failure_exception.rb} +5 -9
  9. data/examples/eventmachine_adapter/{connection_loss_handler.rb → error_handling/connection_loss_handler_that_fails_over.rb} +12 -12
  10. data/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_automatic_recovery.rb +85 -0
  11. data/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_manual_recovery.rb +85 -0
  12. data/examples/eventmachine_adapter/error_handling/handling_a_channel_level_exception.rb +2 -5
  13. data/examples/eventmachine_adapter/example_helper.rb +2 -0
  14. data/examples/eventmachine_adapter/server_capabilities.rb +12 -0
  15. data/examples/eventmachine_adapter/tls/tls_without_peer_verification.rb +2 -2
  16. data/lib/amq/client/async/adapter.rb +170 -31
  17. data/lib/amq/client/async/adapters/coolio.rb +18 -1
  18. data/lib/amq/client/async/adapters/event_machine.rb +48 -32
  19. data/lib/amq/client/async/adapters/eventmachine.rb +3 -1
  20. data/lib/amq/client/async/callbacks.rb +9 -7
  21. data/lib/amq/client/async/channel.rb +113 -20
  22. data/lib/amq/client/async/consumer.rb +270 -0
  23. data/lib/amq/client/async/exchange.rb +137 -16
  24. data/lib/amq/client/async/extensions/rabbitmq/confirm.rb +4 -4
  25. data/lib/amq/client/async/queue.rb +217 -113
  26. data/lib/amq/client/callbacks.rb +2 -0
  27. data/lib/amq/client/consumer_tag_generator.rb +24 -0
  28. data/lib/amq/client/exceptions.rb +10 -6
  29. data/lib/amq/client/handlers_registry.rb +2 -0
  30. data/lib/amq/client/queue.rb +2 -0
  31. data/lib/amq/client/server_named_entity.rb +1 -8
  32. data/lib/amq/client/settings.rb +64 -2
  33. data/lib/amq/client/version.rb +3 -1
  34. data/spec/benchmarks/adapters.rb +2 -0
  35. data/spec/client/framing/io_frame_spec.rb +9 -6
  36. data/spec/integration/coolio/basic_ack_spec.rb +2 -0
  37. data/spec/integration/coolio/basic_cancel_spec.rb +2 -0
  38. data/spec/integration/coolio/basic_consume_spec.rb +58 -0
  39. data/spec/integration/coolio/basic_get_spec.rb +2 -0
  40. data/spec/integration/coolio/basic_return_spec.rb +2 -0
  41. data/spec/integration/coolio/channel_close_spec.rb +2 -0
  42. data/spec/integration/coolio/channel_flow_spec.rb +2 -0
  43. data/spec/integration/coolio/connection_close_spec.rb +2 -0
  44. data/spec/integration/coolio/connection_start_spec.rb +2 -0
  45. data/spec/integration/coolio/exchange_declare_spec.rb +8 -6
  46. data/spec/integration/coolio/spec_helper.rb +2 -0
  47. data/spec/integration/coolio/tx_commit_spec.rb +2 -1
  48. data/spec/integration/coolio/tx_rollback_spec.rb +1 -1
  49. data/spec/integration/eventmachine/basic_ack_spec.rb +3 -1
  50. data/spec/integration/eventmachine/basic_cancel_spec.rb +2 -0
  51. data/spec/integration/eventmachine/basic_consume_spec.rb +90 -6
  52. data/spec/integration/eventmachine/basic_get_spec.rb +2 -0
  53. data/spec/integration/eventmachine/basic_return_spec.rb +2 -0
  54. data/spec/integration/eventmachine/channel_close_spec.rb +2 -0
  55. data/spec/integration/eventmachine/channel_flow_spec.rb +4 -2
  56. data/spec/integration/eventmachine/concurrent_basic_publish_spec.rb +79 -0
  57. data/spec/integration/eventmachine/connection_close_spec.rb +2 -0
  58. data/spec/integration/eventmachine/connection_start_spec.rb +2 -0
  59. data/spec/integration/eventmachine/exchange_declare_spec.rb +4 -2
  60. data/spec/integration/eventmachine/queue_declare_spec.rb +2 -0
  61. data/spec/integration/eventmachine/regressions/amqp_gem_issue66_spec.rb +2 -0
  62. data/spec/integration/eventmachine/spec_helper.rb +2 -0
  63. data/spec/integration/eventmachine/tx_commit_spec.rb +2 -1
  64. data/spec/integration/eventmachine/tx_rollback_spec.rb +1 -1
  65. data/spec/regression/bad_frame_slicing_in_adapters_spec.rb +2 -0
  66. data/spec/spec_helper.rb +10 -0
  67. data/spec/unit/client/settings_spec.rb +92 -3
  68. metadata +24 -23
  69. data/CONTRIBUTORS +0 -3
@@ -1 +1,3 @@
1
- require "amq/client/async/adapters/event_machine"
1
+ # encoding: utf-8
2
+
3
+ require "amq/client/async/adapters/event_machine"
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module AMQ
2
4
  module Client
3
5
  module Async
@@ -34,28 +36,28 @@ module AMQ
34
36
 
35
37
 
36
38
  def exec_callback(name, *args, &block)
37
- list = Array(self.callbacks[name])
39
+ list = Array(@callbacks[name])
38
40
  if list.any?
39
41
  list.each { |c| c.call(*args, &block) }
40
42
  end
41
43
  end
42
44
 
43
45
  def exec_callback_once(name, *args, &block)
44
- list = (self.callbacks.delete(name) || Array.new)
46
+ list = (@callbacks.delete(name) || Array.new)
45
47
  if list.any?
46
48
  list.each { |c| c.call(*args, &block) }
47
49
  end
48
50
  end
49
51
 
50
52
  def exec_callback_yielding_self(name, *args, &block)
51
- list = Array(self.callbacks[name])
53
+ list = Array(@callbacks[name])
52
54
  if list.any?
53
55
  list.each { |c| c.call(self, *args, &block) }
54
56
  end
55
57
  end
56
58
 
57
59
  def exec_callback_once_yielding_self(name, *args, &block)
58
- list = (self.callbacks.delete(name) || Array.new)
60
+ list = (@callbacks.delete(name) || Array.new)
59
61
 
60
62
  if list.any?
61
63
  list.each { |c| c.call(self, *args, &block) }
@@ -63,9 +65,9 @@ module AMQ
63
65
  end
64
66
 
65
67
  def has_callback?(name)
66
- self.callbacks[name] && !self.callbacks[name].empty?
68
+ @callbacks[name] && !@callbacks[name].empty?
67
69
  end # has_callback?
68
- end # Callbacks
70
+ end # Callbacks
69
71
  end # Async
70
72
  end # Client
71
- end # AMQ
73
+ end # AMQ
@@ -25,30 +25,29 @@ module AMQ
25
25
  #
26
26
 
27
27
 
28
- class ChannelOutOfBadError < StandardError # TODO: inherit from some AMQP error class defined in amq-protocol or use it straight away.
29
- def initialize(max, given)
30
- super("Channel max is #{max}, #{given} given.")
31
- end
32
- end
33
-
34
-
35
28
  DEFAULT_REPLY_TEXT = "Goodbye".freeze
36
29
 
37
30
  attr_reader :id
38
31
 
39
32
  attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok
40
- attr_reader :queues_awaiting_declare_ok, :queues_awaiting_delete_ok, :queues_awaiting_bind_ok, :queues_awaiting_unbind_ok, :queues_awaiting_purge_ok, :queues_awaiting_consume_ok, :queues_awaiting_cancel_ok, :queues_awaiting_get_response
33
+ attr_reader :queues_awaiting_declare_ok, :queues_awaiting_delete_ok, :queues_awaiting_bind_ok, :queues_awaiting_unbind_ok, :queues_awaiting_purge_ok, :queues_awaiting_get_response
34
+ attr_reader :consumers_awaiting_consume_ok, :consumers_awaiting_cancel_ok
41
35
 
42
36
  attr_accessor :flow_is_active
43
37
 
44
38
 
45
- def initialize(connection, id)
39
+ def initialize(connection, id, options = {})
46
40
  super(connection)
47
41
 
48
42
  @id = id
49
43
  @exchanges = Hash.new
50
44
  @queues = Hash.new
51
45
  @consumers = Hash.new
46
+ @options = { :auto_recovery => connection.auto_recovering? }.merge(options)
47
+ @auto_recovery = (!!@options[:auto_recovery])
48
+
49
+ # we must synchronize frameset delivery. MK.
50
+ @mutex = Mutex.new
52
51
 
53
52
  reset_state!
54
53
 
@@ -62,10 +61,17 @@ module AMQ
62
61
  end
63
62
 
64
63
  if channel_max != 0 && !(0..channel_max).include?(id)
65
- raise ChannelOutOfBadError.new(channel_max, id)
64
+ raise ArgumentError.new("Max channel for the connection is #{channel_max}, given: #{id}")
66
65
  end
67
66
  end
68
67
 
68
+ # @return [Boolean] true if this channel uses automatic recovery mode
69
+ def auto_recovering?
70
+ @auto_recovery
71
+ end # auto_recovering?
72
+
73
+
74
+ # @return [Hash<String, Consumer>]
69
75
  def consumers
70
76
  @consumers
71
77
  end # consumers
@@ -88,6 +94,12 @@ module AMQ
88
94
  @connection
89
95
  end # connection
90
96
 
97
+ # Synchronizes given block using this channel's mutex.
98
+ # @api public
99
+ def synchronize(&block)
100
+ @mutex.synchronize(&block)
101
+ end
102
+
91
103
 
92
104
  # @group Channel lifecycle
93
105
 
@@ -101,6 +113,7 @@ module AMQ
101
113
 
102
114
  self.redefine_callback :open, &block
103
115
  end
116
+ alias reopen open
104
117
 
105
118
  # Closes AMQP channel.
106
119
  #
@@ -245,6 +258,77 @@ module AMQ
245
258
  self.define_callback(:error, &block)
246
259
  end
247
260
 
261
+
262
+ # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure).
263
+ # Only one callback can be defined (the one defined last replaces previously added ones).
264
+ #
265
+ # @api public
266
+ def on_connection_interruption(&block)
267
+ self.redefine_callback(:after_connection_interruption, &block)
268
+ end # on_connection_interruption(&block)
269
+ alias after_connection_interruption on_connection_interruption
270
+
271
+ # @private
272
+ def handle_connection_interruption(method = nil)
273
+ @queues.each { |name, q| q.handle_connection_interruption(method) }
274
+ @exchanges.each { |name, e| e.handle_connection_interruption(method) }
275
+
276
+ self.exec_callback_yielding_self(:after_connection_interruption)
277
+ self.reset_state!
278
+ end # handle_connection_interruption
279
+
280
+
281
+ # Defines a callback that will be executed after TCP connection has recovered after a network failure
282
+ # but before AMQP connection is re-opened.
283
+ # Only one callback can be defined (the one defined last replaces previously added ones).
284
+ #
285
+ # @api public
286
+ def before_recovery(&block)
287
+ self.redefine_callback(:before_recovery, &block)
288
+ end # before_recovery(&block)
289
+
290
+ # @private
291
+ def run_before_recovery_callbacks
292
+ self.exec_callback_yielding_self(:before_recovery)
293
+
294
+ @queues.each { |name, q| q.run_before_recovery_callbacks }
295
+ @exchanges.each { |name, e| e.run_before_recovery_callbacks }
296
+ end
297
+
298
+
299
+
300
+ # Defines a callback that will be executed after AMQP connection has recovered after a network failure.
301
+ # Only one callback can be defined (the one defined last replaces previously added ones).
302
+ #
303
+ # @api public
304
+ def on_recovery(&block)
305
+ self.redefine_callback(:after_recovery, &block)
306
+ end # on_recovery(&block)
307
+ alias after_recovery on_recovery
308
+
309
+ # @private
310
+ def run_after_recovery_callbacks
311
+ self.exec_callback_yielding_self(:after_recovery)
312
+
313
+ @queues.each { |name, q| q.run_after_recovery_callbacks }
314
+ @exchanges.each { |name, e| e.run_after_recovery_callbacks }
315
+ end
316
+
317
+
318
+ # Called by associated connection object when AMQP connection has been re-established
319
+ # (for example, after a network failure).
320
+ #
321
+ # @api plugin
322
+ def auto_recover
323
+ return unless auto_recovering?
324
+
325
+ self.open do
326
+ # exchanges must be recovered first because queue recovery includes recovery of bindings. MK.
327
+ @exchanges.each { |name, e| e.auto_recover }
328
+ @queues.each { |name, q| q.auto_recover }
329
+ end
330
+ end # auto_recover
331
+
248
332
  # @endgroup
249
333
 
250
334
 
@@ -268,17 +352,26 @@ module AMQ
268
352
  @exchanges[name]
269
353
  end
270
354
 
355
+ # @api plugin
356
+ # @private
271
357
  def register_queue(queue)
272
358
  raise ArgumentError, "argument is nil!" if queue.nil?
273
359
 
274
360
  @queues[queue.name] = queue
275
361
  end # register_queue(queue)
276
362
 
363
+ # @api plugin
364
+ # @private
277
365
  def find_queue(name)
278
366
  @queues[name]
279
367
  end
280
368
 
281
369
 
370
+ RECOVERY_EVENTS = [:after_connection_interruption, :before_recovery, :after_recovery].freeze
371
+
372
+
373
+ # @api plugin
374
+ # @private
282
375
  def reset_state!
283
376
  @flow_is_active = true
284
377
 
@@ -291,31 +384,31 @@ module AMQ
291
384
  @queues_awaiting_purge_ok = Array.new
292
385
  @queues_awaiting_bind_ok = Array.new
293
386
  @queues_awaiting_unbind_ok = Array.new
294
- @queues_awaiting_consume_ok = Array.new
295
- @queues_awaiting_cancel_ok = Array.new
387
+ @consumers_awaiting_consume_ok = Array.new
388
+ @consumers_awaiting_cancel_ok = Array.new
296
389
 
297
390
  @queues_awaiting_get_response = Array.new
298
391
 
299
- @callbacks = Hash.new
392
+ @callbacks = @callbacks.delete_if { |k, v| !RECOVERY_EVENTS.include?(k) }
300
393
  end # reset_state!
301
394
 
302
395
 
303
- def handle_connection_interruption(method = nil)
304
- self.reset_state!
305
- end # handle_connection_interruption
306
-
307
-
308
-
396
+ # @api plugin
397
+ # @private
309
398
  def handle_open_ok(open_ok)
310
399
  self.status = :opened
311
400
  self.exec_callback_once_yielding_self(:open, open_ok)
312
401
  end
313
402
 
403
+ # @api plugin
404
+ # @private
314
405
  def handle_close_ok(close_ok)
315
406
  self.status = :closed
316
407
  self.exec_callback_once_yielding_self(:close, close_ok)
317
408
  end
318
409
 
410
+ # @api plugin
411
+ # @private
319
412
  def handle_close(channel_close)
320
413
  self.status = :closed
321
414
  self.exec_callback_yielding_self(:error, channel_close)
@@ -379,7 +472,7 @@ module AMQ
379
472
  channel = connection.channels[frame.channel]
380
473
  channel.exec_callback(:tx_rollback, frame.decode_payload)
381
474
  end
382
- end # Channel
475
+ end # Channel
383
476
  end # Async
384
477
  end # Client
385
478
  end # AMQ
@@ -0,0 +1,270 @@
1
+ # encoding: utf-8
2
+
3
+ require "amq/client/async/callbacks"
4
+ require "amq/client/consumer_tag_generator"
5
+
6
+ module AMQ
7
+ module Client
8
+ module Async
9
+ class Consumer
10
+
11
+ #
12
+ # Behaviors
13
+ #
14
+
15
+ include Async::Callbacks
16
+ extend Async::ProtocolMethodHandlers
17
+
18
+
19
+
20
+ #
21
+ # API
22
+ #
23
+
24
+ attr_reader :channel
25
+ attr_reader :queue
26
+ attr_reader :consumer_tag
27
+ attr_reader :arguments
28
+
29
+
30
+ def self.tag_generator
31
+ @tag_generator ||= AMQ::Client::ConsumerTagGenerator.new
32
+ end # self.tag_generator
33
+
34
+ def self.tag_generator=(generator)
35
+ @tag_generator = generator
36
+ end
37
+
38
+
39
+ def initialize(channel, queue, consumer_tag = self.class.tag_generator.generate_for(queue), exclusive = false, no_ack = false, arguments = {}, no_local = false, &block)
40
+ @callbacks = Hash.new
41
+
42
+ @channel = channel || raise(ArgumentError, "channel is nil")
43
+ @connection = channel.connection || raise(ArgumentError, "connection is nil")
44
+ @queue = queue || raise(ArgumentError, "queue is nil")
45
+ @consumer_tag = consumer_tag
46
+ @exclusive = exclusive
47
+ @no_ack = no_ack
48
+ @arguments = arguments
49
+
50
+ @no_local = no_local
51
+
52
+ self.register_with_channel
53
+ self.register_with_queue
54
+ end # initialize
55
+
56
+
57
+ def exclusive?
58
+ !!@exclusive
59
+ end # exclusive?
60
+
61
+
62
+
63
+ def consume(nowait = false, &block)
64
+ @connection.send_frame(Protocol::Basic::Consume.encode(@channel.id, @queue.name, @consumer_tag, @no_local, @no_ack, @exclusive, nowait, @arguments))
65
+ self.redefine_callback(:consume, &block)
66
+
67
+ @channel.consumers_awaiting_consume_ok.push(self)
68
+
69
+ self
70
+ end # consume(nowait = false, &block)
71
+
72
+ # Used by automatic recovery code.
73
+ # @api plugin
74
+ def resubscribe(&block)
75
+ @connection.send_frame(Protocol::Basic::Consume.encode(@channel.id, @queue.name, @consumer_tag, @no_local, @no_ack, @exclusive, block.nil?, @arguments))
76
+ self.redefine_callback(:consume, &block) if block
77
+
78
+ self
79
+ end # resubscribe(&block)
80
+
81
+
82
+ def cancel(nowait = false, &block)
83
+ @connection.send_frame(Protocol::Basic::Cancel.encode(@channel.id, @consumer_tag, nowait))
84
+ self.clear_callbacks(:delivery)
85
+ self.clear_callbacks(:consume)
86
+
87
+ self.unregister_with_channel
88
+ self.unregister_with_queue
89
+
90
+ if !nowait
91
+ self.redefine_callback(:cancel, &block)
92
+ @channel.consumers_awaiting_cancel_ok.push(self)
93
+ end
94
+
95
+ self
96
+ end # cancel(nowait = false, &block)
97
+
98
+
99
+
100
+ def on_delivery(&block)
101
+ self.append_callback(:delivery, &block)
102
+
103
+ self
104
+ end # on_delivery(&block)
105
+
106
+
107
+ # @group Acknowledging & Rejecting Messages
108
+
109
+ # Acknowledge a delivery tag.
110
+ # @return [Consumer] self
111
+ #
112
+ # @api public
113
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.13.)
114
+ def acknowledge(delivery_tag)
115
+ @channel.acknowledge(delivery_tag)
116
+
117
+ self
118
+ end # acknowledge(delivery_tag)
119
+
120
+ #
121
+ # @return [Consumer] self
122
+ #
123
+ # @api public
124
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.14.)
125
+ def reject(delivery_tag, requeue = true)
126
+ @channel.reject(delivery_tag, requeue)
127
+
128
+ self
129
+ end # reject(delivery_tag, requeue = true)
130
+
131
+ # @endgroup
132
+
133
+
134
+ # @group Error Handling & Recovery
135
+
136
+ # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure).
137
+ # Only one callback can be defined (the one defined last replaces previously added ones).
138
+ #
139
+ # @api public
140
+ def on_connection_interruption(&block)
141
+ self.redefine_callback(:after_connection_interruption, &block)
142
+ end # on_connection_interruption(&block)
143
+ alias after_connection_interruption on_connection_interruption
144
+
145
+ # @private
146
+ def handle_connection_interruption(method = nil)
147
+ self.exec_callback_yielding_self(:after_connection_interruption)
148
+ end # handle_connection_interruption
149
+
150
+
151
+ # Defines a callback that will be executed after TCP connection is recovered after a network failure
152
+ # but before AMQP connection is re-opened.
153
+ # Only one callback can be defined (the one defined last replaces previously added ones).
154
+ #
155
+ # @api public
156
+ def before_recovery(&block)
157
+ self.redefine_callback(:before_recovery, &block)
158
+ end # before_recovery(&block)
159
+
160
+ # @private
161
+ def run_before_recovery_callbacks
162
+ self.exec_callback_yielding_self(:before_recovery)
163
+ end
164
+
165
+
166
+ # Defines a callback that will be executed when AMQP connection is recovered after a network failure..
167
+ # Only one callback can be defined (the one defined last replaces previously added ones).
168
+ #
169
+ # @api public
170
+ def on_recovery(&block)
171
+ self.redefine_callback(:after_recovery, &block)
172
+ end # on_recovery(&block)
173
+ alias after_recovery on_recovery
174
+
175
+ # @private
176
+ def run_after_recovery_callbacks
177
+ self.exec_callback_yielding_self(:after_recovery)
178
+ end
179
+
180
+
181
+
182
+ # Called by associated connection object when AMQP connection has been re-established
183
+ # (for example, after a network failure).
184
+ #
185
+ # @api plugin
186
+ def auto_recover
187
+ self.exec_callback_yielding_self(:before_recovery)
188
+ self.resubscribe
189
+ self.exec_callback_yielding_self(:after_recovery)
190
+ end # auto_recover
191
+
192
+ # @endgroup
193
+
194
+
195
+
196
+
197
+ #
198
+ # Implementation
199
+ #
200
+
201
+ def handle_delivery(basic_deliver, metadata, payload)
202
+ self.exec_callback(:delivery, basic_deliver, metadata, payload)
203
+ end # handle_delivery(basic_deliver, metadata, payload)
204
+
205
+ def handle_consume_ok(consume_ok)
206
+ self.exec_callback_once(:consume, consume_ok)
207
+ end # handle_consume_ok(consume_ok)
208
+
209
+ def handle_cancel_ok(cancel_ok)
210
+ @consumer_tag = nil
211
+
212
+ # detach from object graph so that this object will be garbage-collected
213
+ @queue = nil
214
+ @channel = nil
215
+ @connection = nil
216
+
217
+ self.exec_callback_once(:cancel, cancel_ok)
218
+ end # handle_cancel_ok(method)
219
+
220
+
221
+
222
+ self.handle(Protocol::Basic::ConsumeOk) do |connection, frame|
223
+ channel = connection.channels[frame.channel]
224
+ consumer = channel.consumers_awaiting_consume_ok.shift
225
+
226
+ consumer.handle_consume_ok(frame.decode_payload)
227
+ end
228
+
229
+
230
+ self.handle(Protocol::Basic::CancelOk) do |connection, frame|
231
+ channel = connection.channels[frame.channel]
232
+ consumer = channel.consumers_awaiting_cancel_ok.shift
233
+
234
+ consumer.handle_consume_ok(frame.decode_payload)
235
+ end
236
+
237
+
238
+ self.handle(Protocol::Basic::Deliver) do |connection, method_frame, content_frames|
239
+ channel = connection.channels[method_frame.channel]
240
+ basic_deliver = method_frame.decode_payload
241
+ consumer = channel.consumers[basic_deliver.consumer_tag]
242
+
243
+ metadata = content_frames.shift
244
+ payload = content_frames.map { |frame| frame.payload }.join
245
+
246
+ consumer.handle_delivery(basic_deliver, metadata, payload)
247
+ end
248
+
249
+
250
+ protected
251
+
252
+ def register_with_channel
253
+ @channel.consumers[@consumer_tag] = self
254
+ end # register_with_channel
255
+
256
+ def register_with_queue
257
+ @queue.consumers[@consumer_tag] = self
258
+ end # register_with_queue
259
+
260
+ def unregister_with_channel
261
+ @channel.consumers.delete(@consumer_tag)
262
+ end # register_with_channel
263
+
264
+ def unregister_with_queue
265
+ @queue.consumers.delete(@consumer_tag)
266
+ end # register_with_queue
267
+ end # Consumer
268
+ end # Async
269
+ end # Client
270
+ end # AMQ