amqp 1.1.0.pre1 → 1.1.0.pre2

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.
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require "amqp/exceptions"
4
+
5
+ module AMQP
6
+ module Framing
7
+ module String
8
+ class Frame < AMQ::Protocol::Frame
9
+ ENCODINGS_SUPPORTED = defined? Encoding
10
+ HEADER_SLICE = (0..6).freeze
11
+ DATA_SLICE = (7..-1).freeze
12
+ PAYLOAD_SLICE = (0..-2).freeze
13
+
14
+ def self.decode(string)
15
+ header = string[HEADER_SLICE]
16
+ type, channel, size = self.decode_header(header)
17
+ data = string[DATA_SLICE]
18
+ payload = data[PAYLOAD_SLICE]
19
+ frame_end = data[-1, 1]
20
+
21
+ frame_end.force_encoding(AMQ::Protocol::Frame::FINAL_OCTET.encoding) if ENCODINGS_SUPPORTED
22
+
23
+ # 1) the size is miscalculated
24
+ if payload.bytesize != size
25
+ raise BadLengthError.new(size, payload.bytesize)
26
+ end
27
+
28
+ # 2) the size is OK, but the string doesn't end with FINAL_OCTET
29
+ raise NoFinalOctetError.new if frame_end != AMQ::Protocol::Frame::FINAL_OCTET
30
+
31
+ self.new(type, payload, channel)
32
+ end # self.from
33
+ end # Frame
34
+ end # String
35
+ end # Framing
36
+ end # AMQP
@@ -0,0 +1,28 @@
1
+ module AMQP
2
+ class HandlersRegistry
3
+
4
+ @@handlers ||= Hash.new
5
+
6
+
7
+ #
8
+ # API
9
+ #
10
+
11
+
12
+ def self.register(klass, &block)
13
+ @@handlers[klass] = block
14
+ end
15
+ class << self
16
+ alias handle register
17
+ end
18
+
19
+ def self.find(klass)
20
+ @@handlers[klass]
21
+ end
22
+
23
+ def self.handlers
24
+ @@handlers
25
+ end
26
+
27
+ end # HandlersRegistry
28
+ end
@@ -0,0 +1,58 @@
1
+ module AMQP
2
+ module Openable
3
+ VALUES = [:opened, :closed, :opening, :closing].freeze
4
+
5
+ class ImproperStatusError < ArgumentError
6
+ def initialize(value)
7
+ super("Value #{value.inspect} isn't permitted. Choose one of: #{AMQP::Openable::VALUES.inspect}")
8
+ end
9
+ end
10
+
11
+ attr_reader :status
12
+ def status=(value)
13
+ if VALUES.include?(value)
14
+ @status = value
15
+ else
16
+ raise ImproperStatusError.new(value)
17
+ end
18
+ end
19
+
20
+ def opened?
21
+ @status == :opened
22
+ end
23
+ alias open? opened?
24
+
25
+ def closed?
26
+ @status == :closed
27
+ end
28
+
29
+
30
+
31
+ def opening?
32
+ @status == :opening
33
+ end
34
+
35
+ def closing?
36
+ @status == :closing
37
+ end
38
+
39
+
40
+ def opened!
41
+ @status = :opened
42
+ end # opened!
43
+
44
+ def closed!
45
+ @status = :closed
46
+ end # closed!
47
+
48
+
49
+
50
+ def opening!
51
+ @status = :opening
52
+ end # opening!
53
+
54
+ def closing!
55
+ @status = :closing
56
+ end # closing!
57
+ end
58
+ end
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "amq/client/queue"
3
+ require "amqp/entity"
4
+
5
+ require "amq/protocol/get_response"
4
6
  require "amqp/consumer"
5
7
 
6
8
  module AMQP
@@ -118,7 +120,17 @@ module AMQP
118
120
  #
119
121
  # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.1.1)
120
122
  # @see AMQP::Exchange
121
- class Queue < AMQ::Client::Queue
123
+ class Queue
124
+
125
+ #
126
+ # Behaviours
127
+ #
128
+
129
+ include Entity
130
+ include ServerNamedEntity
131
+ extend ProtocolMethodHandlers
132
+
133
+
122
134
 
123
135
  #
124
136
  # API
@@ -129,6 +141,22 @@ module AMQP
129
141
  # Options this queue object was instantiated with
130
142
  attr_accessor :opts
131
143
 
144
+ # Channel this queue belongs to.
145
+ # @return [AMQP::Channel]
146
+ attr_reader :channel
147
+
148
+ # @return [Array<Hash>] All consumers on this queue.
149
+ attr_reader :consumers
150
+
151
+ # @return [AMQP::Consumer] Default consumer (registered with {Queue#consume}).
152
+ attr_reader :default_consumer
153
+
154
+ # @return [Hash] Additional arguments given on queue declaration. Typically used by AMQP extensions.
155
+ attr_reader :arguments
156
+
157
+ # @return [Array<Hash>]
158
+ attr_reader :bindings
159
+
132
160
 
133
161
 
134
162
  # @option opts [Boolean] :passive (false) If set, the server will not create the queue if it does not
@@ -167,7 +195,7 @@ module AMQP
167
195
  #
168
196
  # @yield [queue, declare_ok] Yields successfully declared queue instance and AMQP method (queue.declare-ok) instance. The latter is optional.
169
197
  # @yieldparam [Queue] queue Queue that is successfully declared and is ready to be used.
170
- # @yieldparam [AMQP::Protocol::Queue::DeclareOk] declare_ok AMQP queue.declare-ok) instance.
198
+ # @yieldparam [AMQ::Protocol::Queue::DeclareOk] declare_ok AMQP queue.declare-ok) instance.
171
199
  #
172
200
  # @api public
173
201
  def initialize(channel, name = AMQ::Protocol::EMPTY_STRING, opts = {}, &block)
@@ -183,9 +211,26 @@ module AMQP
183
211
  # a deferrable that we use to delay operations until this queue is actually declared.
184
212
  # one reason for this is to support a case when a server-named queue is immediately bound.
185
213
  # it's crazy, but 0.7.x supports it, so... MK.
186
- @declaration_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
214
+ @declaration_deferrable = AMQP::Deferrable.new
215
+
216
+ super(channel.connection)
217
+
218
+ @name = name
219
+ # this has to stay true even after queue.declare-ok arrives. MK.
220
+ @server_named = @name.empty?
221
+ if @server_named
222
+ self.on_connection_interruption do
223
+ # server-named queue need to get new names after recovery. MK.
224
+ @name = AMQ::Protocol::EMPTY_STRING
225
+ end
226
+ end
187
227
 
188
- super(channel.connection, channel, name)
228
+ @channel = channel
229
+
230
+ # primarily for autorecovery. MK.
231
+ @bindings = Array.new
232
+
233
+ @consumers = Hash.new
189
234
 
190
235
  shim = Proc.new do |q, declare_ok|
191
236
  case block.arity
@@ -202,11 +247,11 @@ module AMQP
202
247
  end
203
248
 
204
249
  if block
205
- self.declare(@opts[:passive], @opts[:durable], @opts[:exclusive], @opts[:auto_delete], @opts[:nowait], @opts[:arguments], &shim)
250
+ self.queue_declare(@opts[:passive], @opts[:durable], @opts[:exclusive], @opts[:auto_delete], @opts[:nowait], @opts[:arguments], &shim)
206
251
  else
207
- # we cannot pass :nowait as true here, AMQ::Client::Queue will (rightfully) raise an exception because
252
+ # we cannot pass :nowait as true here, AMQP::Queue will (rightfully) raise an exception because
208
253
  # it has no idea about crazy edge cases we are trying to support for sake of backwards compatibility. MK.
209
- self.declare(@opts[:passive], @opts[:durable], @opts[:exclusive], @opts[:auto_delete], false, @opts[:arguments])
254
+ self.queue_declare(@opts[:passive], @opts[:durable], @opts[:exclusive], @opts[:auto_delete], false, @opts[:arguments])
210
255
  end
211
256
  end
212
257
  end
@@ -224,6 +269,25 @@ module AMQP
224
269
  end # once_declared(&block)
225
270
 
226
271
 
272
+ # @return [Boolean] true if this queue was declared as durable (will survive broker restart).
273
+ # @api public
274
+ def durable?
275
+ @durable
276
+ end # durable?
277
+
278
+ # @return [Boolean] true if this queue was declared as exclusive (limited to just one consumer)
279
+ # @api public
280
+ def exclusive?
281
+ @exclusive
282
+ end # exclusive?
283
+
284
+ # @return [Boolean] true if this queue was declared as automatically deleted (deleted as soon as last consumer unbinds).
285
+ # @api public
286
+ def auto_delete?
287
+ @auto_delete
288
+ end # auto_delete?
289
+
290
+
227
291
  # @return [Boolean] true if this queue is server-named
228
292
  def server_named?
229
293
  @server_named
@@ -282,7 +346,7 @@ module AMQP
282
346
  def bind(exchange, opts = {}, &block)
283
347
  @channel.once_open do
284
348
  self.once_name_is_available do
285
- super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), (opts[:nowait] || block.nil?), opts[:arguments], &block)
349
+ queue_bind(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), (opts[:nowait] || block.nil?), opts[:arguments], &block)
286
350
  end
287
351
  end
288
352
 
@@ -351,7 +415,7 @@ module AMQP
351
415
  def unbind(exchange, opts = {}, &block)
352
416
  @channel.once_open do
353
417
  self.once_name_is_available do
354
- super(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), opts[:arguments], &block)
418
+ queue_unbind(exchange, (opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING), opts[:arguments], &block)
355
419
  end
356
420
  end
357
421
  end
@@ -379,7 +443,7 @@ module AMQP
379
443
  # @return [NilClass] nil (for v0.7 compatibility)
380
444
  #
381
445
  # @yield [delete_ok] Yields AMQP method (queue.delete-ok) instance.
382
- # @yieldparam [AMQP::Protocol::Queue::DeleteOk] delete_ok AMQP queue.delete-ok) instance. Carries number of messages that were in the queue.
446
+ # @yieldparam [AMQ::Protocol::Queue::DeleteOk] delete_ok AMQP queue.delete-ok) instance. Carries number of messages that were in the queue.
383
447
  #
384
448
  # @api public
385
449
  # @see Queue#purge
@@ -387,7 +451,7 @@ module AMQP
387
451
  def delete(opts = {}, &block)
388
452
  @channel.once_open do
389
453
  self.once_name_is_available do
390
- super(opts.fetch(:if_unused, false), opts.fetch(:if_empty, false), opts.fetch(:nowait, false), &block)
454
+ queue_delete(opts.fetch(:if_unused, false), opts.fetch(:if_empty, false), opts.fetch(:nowait, false), &block)
391
455
  end
392
456
  end
393
457
 
@@ -406,7 +470,7 @@ module AMQP
406
470
  #
407
471
  #
408
472
  # @yield [purge_ok] Yields AMQP method (queue.purge-ok) instance.
409
- # @yieldparam [AMQP::Protocol::Queue::PurgeOk] purge_ok AMQP queue.purge-ok) instance. Carries number of messages that were purged.
473
+ # @yieldparam [AMQ::Protocol::Queue::PurgeOk] purge_ok AMQP queue.purge-ok) instance. Carries number of messages that were purged.
410
474
  #
411
475
  # @api public
412
476
  # @see Queue#delete
@@ -414,7 +478,7 @@ module AMQP
414
478
  def purge(opts = {}, &block)
415
479
  @channel.once_open do
416
480
  self.once_declared do
417
- super(opts.fetch(:nowait, false), &block)
481
+ queue_purge(opts.fetch(:nowait, false), &block)
418
482
  end
419
483
  end
420
484
 
@@ -477,7 +541,7 @@ module AMQP
477
541
 
478
542
  @channel.once_open do
479
543
  self.once_name_is_available do
480
- # see AMQ::Client::Queue#get in amq-client
544
+ # see AMQP::Queue#get in amq-client
481
545
  self.get(!opts.fetch(:ack, false), &shim)
482
546
  end
483
547
  end
@@ -727,7 +791,7 @@ module AMQP
727
791
  self.once_name_is_available do
728
792
  # guards against a pathological case race condition when a channel
729
793
  # is opened and closed before delayed operations are completed.
730
- self.consume(!opts[:ack], opts[:exclusive], (opts[:nowait] || block.nil?), opts[:no_local], nil, &opts[:confirm])
794
+ self.basic_consume(!opts[:ack], opts[:exclusive], (opts[:nowait] || block.nil?), opts[:no_local], nil, &opts[:confirm])
731
795
 
732
796
  self.on_delivery(&block)
733
797
  end
@@ -736,6 +800,13 @@ module AMQP
736
800
  self
737
801
  end
738
802
 
803
+ # @api public
804
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.8.3.9)
805
+ def on_delivery(&block)
806
+ @default_consumer.on_delivery(&block)
807
+ end # on_delivery(&block)
808
+
809
+
739
810
  # @return [String] Consumer tag of the default consumer associated with this queue (if any), or nil
740
811
  # @note Default consumer is the one registered with the convenience {AMQP::Queue#subscribe} method. It has no special properties of any kind.
741
812
  # @see Queue#subscribe
@@ -786,7 +857,7 @@ module AMQP
786
857
  # method it will raise a channel or connection exception.
787
858
  #
788
859
  # @yield [cancel_ok]
789
- # @yieldparam [AMQP::Protocol::Basic::CancelOk] cancel_ok AMQP method basic.cancel-ok. You can obtain consumer tag from it.
860
+ # @yieldparam [AMQ::Protocol::Basic::CancelOk] cancel_ok AMQP method basic.cancel-ok. You can obtain consumer tag from it.
790
861
  #
791
862
  #
792
863
  # @api public
@@ -880,17 +951,453 @@ module AMQP
880
951
  # @private
881
952
  # @api plugin
882
953
  def handle_connection_interruption(method = nil)
883
- super(method)
954
+ @consumers.each { |tag, consumer| consumer.handle_connection_interruption(method) }
955
+
956
+ self.exec_callback_yielding_self(:after_connection_interruption)
884
957
 
885
958
  @declaration_deferrable = EventMachine::DefaultDeferrable.new
886
959
  end
887
960
 
888
961
  def handle_declare_ok(method)
889
- super(method)
962
+ @name = method.queue if @name.empty?
963
+ @channel.register_queue(self)
964
+
965
+ self.exec_callback_once_yielding_self(:declare, method)
966
+
890
967
  @declaration_deferrable.succeed
891
968
  end
892
969
 
893
970
 
971
+ # @group Declaration
972
+
973
+ # Declares this queue.
974
+ #
975
+ #
976
+ # @return [Queue] self
977
+ #
978
+ # @api public
979
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.1.)
980
+ def queue_declare(passive = false, durable = false, exclusive = false, auto_delete = false, nowait = false, arguments = nil, &block)
981
+ raise ArgumentError, "declaration with nowait does not make sense for server-named queues! Either specify name other than empty string or use #declare without nowait" if nowait && self.anonymous?
982
+
983
+ # these two are for autorecovery. MK.
984
+ @passive = passive
985
+ @server_named = @name.empty?
986
+
987
+ @durable = durable
988
+ @exclusive = exclusive
989
+ @auto_delete = auto_delete
990
+ @arguments = arguments
991
+
992
+ nowait = true if !block && !@name.empty? && nowait.nil?
993
+ @connection.send_frame(AMQ::Protocol::Queue::Declare.encode(@channel.id, @name, passive, durable, exclusive, auto_delete, nowait, arguments))
994
+
995
+ if !nowait
996
+ self.append_callback(:declare, &block)
997
+ @channel.queues_awaiting_declare_ok.push(self)
998
+ end
999
+
1000
+ self
1001
+ end
1002
+
1003
+ # Re-declares queue with the same attributes
1004
+ # @api public
1005
+ def redeclare(&block)
1006
+ nowait = true if !block && !@name.empty?
1007
+
1008
+ # server-named queues get their new generated names.
1009
+ new_name = if @server_named
1010
+ AMQ::Protocol::EMPTY_STRING
1011
+ else
1012
+ @name
1013
+ end
1014
+ @connection.send_frame(AMQ::Protocol::Queue::Declare.encode(@channel.id, new_name, @passive, @durable, @exclusive, @auto_delete, false, @arguments))
1015
+
1016
+ if !nowait
1017
+ self.append_callback(:declare, &block)
1018
+ @channel.queues_awaiting_declare_ok.push(self)
1019
+ end
1020
+
1021
+ self
1022
+ end
1023
+
1024
+ # @endgroup
1025
+
1026
+
1027
+
1028
+ # Deletes this queue.
1029
+ #
1030
+ # @param [Boolean] if_unused delete only if queue has no consumers (subscribers).
1031
+ # @param [Boolean] if_empty delete only if queue has no messages in it.
1032
+ # @param [Boolean] nowait Don't wait for reply from broker.
1033
+ # @return [Queue] self
1034
+ #
1035
+ # @api public
1036
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.9.)
1037
+ def queue_delete(if_unused = false, if_empty = false, nowait = false, &block)
1038
+ nowait = true unless block
1039
+ @connection.send_frame(AMQ::Protocol::Queue::Delete.encode(@channel.id, @name, if_unused, if_empty, nowait))
1040
+
1041
+ if !nowait
1042
+ self.append_callback(:delete, &block)
1043
+
1044
+ # TODO: delete itself from queues cache
1045
+ @channel.queues_awaiting_delete_ok.push(self)
1046
+ end
1047
+
1048
+ self
1049
+ end # delete(channel, queue, if_unused, if_empty, nowait, &block)
1050
+
1051
+
1052
+
1053
+ # @group Binding
1054
+
1055
+ #
1056
+ # @return [Queue] self
1057
+ #
1058
+ # @api public
1059
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.3.)
1060
+ def queue_bind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, nowait = false, arguments = nil, &block)
1061
+ nowait = true unless block
1062
+ exchange_name = if exchange.respond_to?(:name)
1063
+ exchange.name
1064
+ else
1065
+
1066
+ exchange
1067
+ end
1068
+
1069
+ @connection.send_frame(AMQ::Protocol::Queue::Bind.encode(@channel.id, @name, exchange_name, routing_key, nowait, arguments))
1070
+
1071
+ if !nowait
1072
+ self.append_callback(:bind, &block)
1073
+ @channel.queues_awaiting_bind_ok.push(self)
1074
+ end
1075
+
1076
+ # store bindings for automatic recovery, but BE VERY CAREFUL to
1077
+ # not cause an infinite rebinding loop here when we recover. MK.
1078
+ binding = { :exchange => exchange_name, :routing_key => routing_key, :arguments => arguments }
1079
+ @bindings.push(binding) unless @bindings.include?(binding)
1080
+
1081
+ self
1082
+ end
1083
+
1084
+ #
1085
+ # @return [Queue] self
1086
+ #
1087
+ # @api public
1088
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.5.)
1089
+ def queue_unbind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, arguments = nil, &block)
1090
+ exchange_name = if exchange.respond_to?(:name)
1091
+ exchange.name
1092
+ else
1093
+
1094
+ exchange
1095
+ end
1096
+
1097
+ @connection.send_frame(AMQ::Protocol::Queue::Unbind.encode(@channel.id, @name, exchange_name, routing_key, arguments))
1098
+
1099
+ self.append_callback(:unbind, &block)
1100
+ @channel.queues_awaiting_unbind_ok.push(self)
1101
+
1102
+
1103
+ @bindings.delete_if { |b| b[:exchange] == exchange_name }
1104
+
1105
+ self
1106
+ end
1107
+
1108
+ # @endgroup
1109
+
1110
+
1111
+
1112
+
1113
+ # @group Consuming messages
1114
+
1115
+ #
1116
+ # @return [Queue] self
1117
+ #
1118
+ # @api public
1119
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.3.)
1120
+ def basic_consume(no_ack = false, exclusive = false, nowait = false, no_local = false, arguments = nil, &block)
1121
+ raise RuntimeError.new("This queue already has default consumer. Please instantiate AMQP::Consumer directly to register additional consumers.") if @default_consumer
1122
+
1123
+ nowait = true unless block
1124
+ @default_consumer = self.class.consumer_class.new(@channel, self, generate_consumer_tag(@name), exclusive, no_ack, arguments, no_local, &block)
1125
+ @default_consumer.consume(nowait, &block)
1126
+
1127
+ self
1128
+ end
1129
+
1130
+ # Unsubscribes from message delivery.
1131
+ # @return [Queue] self
1132
+ #
1133
+ # @api public
1134
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.5.)
1135
+ def cancel(nowait = false, &block)
1136
+ raise "There is no default consumer for this queue. This usually means that you are trying to unsubscribe a queue that never was subscribed for messages in the first place." if @default_consumer.nil?
1137
+
1138
+ @default_consumer.cancel(nowait, &block)
1139
+
1140
+ self
1141
+ end # cancel(&block)
1142
+
1143
+ # @api public
1144
+ def on_cancel(&block)
1145
+ @default_consumer.on_cancel(&block)
1146
+ end # on_cancel(&block)
1147
+
1148
+ # @endgroup
1149
+
1150
+
1151
+
1152
+
1153
+ # @group Working With Messages
1154
+
1155
+ # Fetches messages from the queue.
1156
+ # @return [Queue] self
1157
+ #
1158
+ # @api public
1159
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.10.)
1160
+ def get(no_ack = false, &block)
1161
+ @connection.send_frame(AMQ::Protocol::Basic::Get.encode(@channel.id, @name, no_ack))
1162
+
1163
+ # most people only want one callback per #get call. Consider the following example:
1164
+ #
1165
+ # 100.times { queue.get { ... } }
1166
+ #
1167
+ # most likely you won't expect 100 callback runs per message here. MK.
1168
+ self.redefine_callback(:get, &block)
1169
+ @channel.queues_awaiting_get_response.push(self)
1170
+
1171
+ self
1172
+ end # get(no_ack = false, &block)
1173
+
1174
+
1175
+
1176
+ # Purges (removes all messagse from) the queue.
1177
+ # @return [Queue] self
1178
+ #
1179
+ # @api public
1180
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.7.)
1181
+ def queue_purge(nowait = false, &block)
1182
+ nowait = true unless block
1183
+ @connection.send_frame(AMQ::Protocol::Queue::Purge.encode(@channel.id, @name, nowait))
1184
+
1185
+ if !nowait
1186
+ self.redefine_callback(:purge, &block)
1187
+ # TODO: handle channel & connection-level exceptions
1188
+ @channel.queues_awaiting_purge_ok.push(self)
1189
+ end
1190
+
1191
+ self
1192
+ end # purge(nowait = false, &block)
1193
+
1194
+ # @endgroup
1195
+
1196
+
1197
+
1198
+ # @group Acknowledging & Rejecting Messages
1199
+
1200
+ # Acknowledge a delivery tag.
1201
+ # @return [Queue] self
1202
+ #
1203
+ # @api public
1204
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.13.)
1205
+ def acknowledge(delivery_tag)
1206
+ @channel.acknowledge(delivery_tag)
1207
+
1208
+ self
1209
+ end # acknowledge(delivery_tag)
1210
+
1211
+ #
1212
+ # @return [Queue] self
1213
+ #
1214
+ # @api public
1215
+ # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.14.)
1216
+ def reject(delivery_tag, requeue = true)
1217
+ @channel.reject(delivery_tag, requeue)
1218
+
1219
+ self
1220
+ end # reject(delivery_tag, requeue = true)
1221
+
1222
+ # @endgroup
1223
+
1224
+
1225
+
1226
+
1227
+ # @group Error Handling & Recovery
1228
+
1229
+ # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure).
1230
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1231
+ #
1232
+ # @api public
1233
+ def on_connection_interruption(&block)
1234
+ self.redefine_callback(:after_connection_interruption, &block)
1235
+ end # on_connection_interruption(&block)
1236
+ alias after_connection_interruption on_connection_interruption
1237
+
1238
+ # Defines a callback that will be executed after TCP connection is recovered after a network failure
1239
+ # but before AMQP connection is re-opened.
1240
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1241
+ #
1242
+ # @api public
1243
+ def before_recovery(&block)
1244
+ self.redefine_callback(:before_recovery, &block)
1245
+ end # before_recovery(&block)
1246
+
1247
+ # @private
1248
+ def run_before_recovery_callbacks
1249
+ self.exec_callback_yielding_self(:before_recovery)
1250
+
1251
+ @consumers.each { |tag, c| c.run_before_recovery_callbacks }
1252
+ end
1253
+
1254
+
1255
+ # Defines a callback that will be executed when AMQP connection is recovered after a network failure..
1256
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1257
+ #
1258
+ # @api public
1259
+ def on_recovery(&block)
1260
+ self.redefine_callback(:after_recovery, &block)
1261
+ end # on_recovery(&block)
1262
+ alias after_recovery on_recovery
1263
+
1264
+ # @private
1265
+ def run_after_recovery_callbacks
1266
+ self.exec_callback_yielding_self(:after_recovery)
1267
+
1268
+ @consumers.each { |tag, c| c.run_after_recovery_callbacks }
1269
+ end
1270
+
1271
+
1272
+
1273
+ # Called by associated connection object when AMQP connection has been re-established
1274
+ # (for example, after a network failure).
1275
+ #
1276
+ # @api plugin
1277
+ def auto_recover
1278
+ self.exec_callback_yielding_self(:before_recovery)
1279
+ self.redeclare do
1280
+ self.rebind
1281
+
1282
+ @consumers.each { |tag, consumer| consumer.auto_recover }
1283
+
1284
+ self.exec_callback_yielding_self(:after_recovery)
1285
+ end
1286
+ end # auto_recover
1287
+
1288
+ # @endgroup
1289
+
1290
+
1291
+ #
1292
+ # Implementation
1293
+ #
1294
+
1295
+
1296
+ # Unique string supposed to be used as a consumer tag.
1297
+ #
1298
+ # @return [String] Unique string.
1299
+ # @api plugin
1300
+ def generate_consumer_tag(name)
1301
+ "#{name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}"
1302
+ end
1303
+
1304
+
1305
+ def handle_connection_interruption(method = nil)
1306
+ @consumers.each { |tag, c| c.handle_connection_interruption(method) }
1307
+ end # handle_connection_interruption(method = nil)
1308
+
1309
+
1310
+ def handle_delete_ok(method)
1311
+ self.exec_callback_once(:delete, method)
1312
+ end # handle_delete_ok(method)
1313
+
1314
+ def handle_purge_ok(method)
1315
+ self.exec_callback_once(:purge, method)
1316
+ end # handle_purge_ok(method)
1317
+
1318
+ def handle_bind_ok(method)
1319
+ self.exec_callback_once(:bind, method)
1320
+ end # handle_bind_ok(method)
1321
+
1322
+ def handle_unbind_ok(method)
1323
+ self.exec_callback_once(:unbind, method)
1324
+ end # handle_unbind_ok(method)
1325
+
1326
+ def handle_get_ok(method, header, payload)
1327
+ method = AMQ::Protocol::GetResponse.new(method)
1328
+ self.exec_callback(:get, method, header, payload)
1329
+ end # handle_get_ok(method, header, payload)
1330
+
1331
+ def handle_get_empty(method)
1332
+ method = AMQ::Protocol::GetResponse.new(method)
1333
+ self.exec_callback(:get, method)
1334
+ end # handle_get_empty(method)
1335
+
1336
+
1337
+
1338
+ # Get the first queue which didn't receive Queue.Declare-Ok yet and run its declare callback.
1339
+ # The cache includes only queues with {nowait: false}.
1340
+ self.handle(AMQ::Protocol::Queue::DeclareOk) do |connection, frame|
1341
+ method = frame.decode_payload
1342
+
1343
+ channel = connection.channels[frame.channel]
1344
+ queue = channel.queues_awaiting_declare_ok.shift
1345
+
1346
+ queue.handle_declare_ok(method)
1347
+ end
1348
+
1349
+
1350
+ self.handle(AMQ::Protocol::Queue::DeleteOk) do |connection, frame|
1351
+ channel = connection.channels[frame.channel]
1352
+ queue = channel.queues_awaiting_delete_ok.shift
1353
+ queue.handle_delete_ok(frame.decode_payload)
1354
+ end
1355
+
1356
+
1357
+ self.handle(AMQ::Protocol::Queue::BindOk) do |connection, frame|
1358
+ channel = connection.channels[frame.channel]
1359
+ queue = channel.queues_awaiting_bind_ok.shift
1360
+
1361
+ queue.handle_bind_ok(frame.decode_payload)
1362
+ end
1363
+
1364
+
1365
+ self.handle(AMQ::Protocol::Queue::UnbindOk) do |connection, frame|
1366
+ channel = connection.channels[frame.channel]
1367
+ queue = channel.queues_awaiting_unbind_ok.shift
1368
+
1369
+ queue.handle_unbind_ok(frame.decode_payload)
1370
+ end
1371
+
1372
+
1373
+ self.handle(AMQ::Protocol::Queue::PurgeOk) do |connection, frame|
1374
+ channel = connection.channels[frame.channel]
1375
+ queue = channel.queues_awaiting_purge_ok.shift
1376
+
1377
+ queue.handle_purge_ok(frame.decode_payload)
1378
+ end
1379
+
1380
+
1381
+ self.handle(AMQ::Protocol::Basic::GetOk) do |connection, frame, content_frames|
1382
+ channel = connection.channels[frame.channel]
1383
+ queue = channel.queues_awaiting_get_response.shift
1384
+ method = frame.decode_payload
1385
+
1386
+ header = content_frames.shift
1387
+ body = content_frames.map {|frame| frame.payload }.join
1388
+
1389
+ queue.handle_get_ok(method, header, body) if queue
1390
+ end
1391
+
1392
+
1393
+ self.handle(AMQ::Protocol::Basic::GetEmpty) do |connection, frame|
1394
+ channel = connection.channels[frame.channel]
1395
+ queue = channel.queues_awaiting_get_response.shift
1396
+
1397
+ queue.handle_get_empty(frame.decode_payload)
1398
+ end
1399
+
1400
+
894
1401
  protected
895
1402
 
896
1403
  # @private