amqp 1.1.0.pre1 → 1.1.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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