amq-client 0.7.0.alpha34 → 0.7.0.alpha35
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/Gemfile +1 -1
- data/README.textile +1 -1
- data/bin/ci/before_build.sh +24 -0
- data/examples/eventmachine_adapter/extensions/rabbitmq/handling_confirm_select_ok.rb +2 -2
- data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +1 -1
- data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unroutable_message.rb +1 -1
- data/lib/amq/client.rb +29 -17
- data/lib/amq/client/adapter.rb +8 -504
- data/lib/amq/client/adapters/coolio.rb +4 -282
- data/lib/amq/client/adapters/event_machine.rb +4 -382
- data/lib/amq/client/async/adapter.rb +517 -0
- data/lib/amq/client/async/adapters/coolio.rb +291 -0
- data/lib/amq/client/async/adapters/event_machine.rb +392 -0
- data/lib/amq/client/async/adapters/eventmachine.rb +1 -0
- data/lib/amq/client/async/callbacks.rb +71 -0
- data/lib/amq/client/async/channel.rb +385 -0
- data/lib/amq/client/async/entity.rb +66 -0
- data/lib/amq/client/async/exchange.rb +157 -0
- data/lib/amq/client/async/extensions/rabbitmq/basic.rb +38 -0
- data/lib/amq/client/async/extensions/rabbitmq/confirm.rb +248 -0
- data/lib/amq/client/async/queue.rb +455 -0
- data/lib/amq/client/callbacks.rb +6 -65
- data/lib/amq/client/channel.rb +4 -376
- data/lib/amq/client/entity.rb +6 -57
- data/lib/amq/client/exchange.rb +4 -148
- data/lib/amq/client/extensions/rabbitmq/basic.rb +4 -28
- data/lib/amq/client/extensions/rabbitmq/confirm.rb +5 -240
- data/lib/amq/client/queue.rb +5 -450
- data/lib/amq/client/version.rb +1 -1
- data/spec/unit/client_spec.rb +10 -30
- metadata +16 -22
data/lib/amq/client/queue.rb
CHANGED
@@ -1,453 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "amq/client/entity"
|
4
|
-
require "amq/client/adapter"
|
5
|
-
require "amq/client/server_named_entity"
|
6
|
-
require "amq/protocol/get_response"
|
1
|
+
require "amq/client/async/queue"
|
7
2
|
|
8
3
|
module AMQ
|
9
4
|
module Client
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
include Entity
|
17
|
-
include ServerNamedEntity
|
18
|
-
extend ProtocolMethodHandlers
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
# API
|
23
|
-
#
|
24
|
-
|
25
|
-
# Qeueue name. May be server-generated or assigned directly.
|
26
|
-
attr_reader :name
|
27
|
-
|
28
|
-
# Channel this queue belongs to.
|
29
|
-
attr_reader :channel
|
30
|
-
|
31
|
-
# Consumer tag identifies subscription for message delivery. It is nil for queues that are not subscribed for messages. See AMQ::Client::Queue#subscribe.
|
32
|
-
attr_reader :consumer_tag
|
33
|
-
|
34
|
-
# @param [AMQ::Client::Adapter] AMQ networking adapter to use.
|
35
|
-
# @param [AMQ::Client::Channel] AMQ channel this queue object uses.
|
36
|
-
# @param [String] Queue name. Please note that AMQP spec does not require brokers to support Unicode for queue names.
|
37
|
-
# @api public
|
38
|
-
def initialize(connection, channel, name = AMQ::Protocol::EMPTY_STRING)
|
39
|
-
raise ArgumentError.new("queue name must not be nil; if you want broker to generate queue name for you, pass an empty string") if name.nil?
|
40
|
-
|
41
|
-
super(connection)
|
42
|
-
|
43
|
-
@name = name
|
44
|
-
@channel = channel
|
45
|
-
end
|
46
|
-
|
47
|
-
def dup
|
48
|
-
if @name.empty?
|
49
|
-
raise RuntimeError.new("You can't clone anonymous queue until it receives server-generated name. Move the code with #dup to the callback for the #declare method.")
|
50
|
-
end
|
51
|
-
|
52
|
-
o = super
|
53
|
-
o.reset_consumer_tag!
|
54
|
-
o
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
# @return [Boolean] true if this queue was declared as durable (will survive broker restart).
|
59
|
-
# @api public
|
60
|
-
def durable?
|
61
|
-
@durable
|
62
|
-
end # durable?
|
63
|
-
|
64
|
-
# @return [Boolean] true if this queue was declared as exclusive (limited to just one consumer)
|
65
|
-
# @api public
|
66
|
-
def exclusive?
|
67
|
-
@exclusive
|
68
|
-
end # exclusive?
|
69
|
-
|
70
|
-
# @return [Boolean] true if this queue was declared as automatically deleted (deleted as soon as last consumer unbinds).
|
71
|
-
# @api public
|
72
|
-
def auto_delete?
|
73
|
-
@auto_delete
|
74
|
-
end # auto_delete?
|
75
|
-
|
76
|
-
|
77
|
-
# Declares this queue.
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# @return [Queue] self
|
81
|
-
#
|
82
|
-
# @api public
|
83
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.7.2.1.)
|
84
|
-
def declare(passive = false, durable = false, exclusive = false, auto_delete = false, nowait = false, arguments = nil, &block)
|
85
|
-
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?
|
86
|
-
|
87
|
-
@durable = durable
|
88
|
-
@exclusive = exclusive
|
89
|
-
@auto_delete = auto_delete
|
90
|
-
|
91
|
-
nowait = true if !block && !@name.empty?
|
92
|
-
@connection.send_frame(Protocol::Queue::Declare.encode(@channel.id, @name, passive, durable, exclusive, auto_delete, nowait, arguments))
|
93
|
-
|
94
|
-
if !nowait
|
95
|
-
self.append_callback(:declare, &block)
|
96
|
-
@channel.queues_awaiting_declare_ok.push(self)
|
97
|
-
end
|
98
|
-
|
99
|
-
self
|
100
|
-
end
|
101
|
-
|
102
|
-
# Deletes this queue.
|
103
|
-
#
|
104
|
-
# @param [Boolean] if_unused delete only if queue has no consumers (subscribers).
|
105
|
-
# @param [Boolean] if_empty delete only if queue has no messages in it.
|
106
|
-
# @param [Boolean] nowait Don't wait for reply from broker.
|
107
|
-
# @return [Queue] self
|
108
|
-
#
|
109
|
-
# @api public
|
110
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.7.2.9.)
|
111
|
-
def delete(if_unused = false, if_empty = false, nowait = false, &block)
|
112
|
-
nowait = true unless block
|
113
|
-
@connection.send_frame(Protocol::Queue::Delete.encode(@channel.id, @name, if_unused, if_empty, nowait))
|
114
|
-
|
115
|
-
if !nowait
|
116
|
-
self.append_callback(:delete, &block)
|
117
|
-
|
118
|
-
# TODO: delete itself from queues cache
|
119
|
-
@channel.queues_awaiting_delete_ok.push(self)
|
120
|
-
end
|
121
|
-
|
122
|
-
self
|
123
|
-
end # delete(channel, queue, if_unused, if_empty, nowait, &block)
|
124
|
-
|
125
|
-
#
|
126
|
-
# @return [Queue] self
|
127
|
-
#
|
128
|
-
# @api public
|
129
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.7.2.3.)
|
130
|
-
def bind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, nowait = false, arguments = nil, &block)
|
131
|
-
nowait = true unless block
|
132
|
-
exchange_name = if exchange.respond_to?(:name)
|
133
|
-
exchange.name
|
134
|
-
else
|
135
|
-
|
136
|
-
exchange
|
137
|
-
end
|
138
|
-
|
139
|
-
@connection.send_frame(Protocol::Queue::Bind.encode(@channel.id, @name, exchange_name, routing_key, nowait, arguments))
|
140
|
-
|
141
|
-
if !nowait
|
142
|
-
self.append_callback(:bind, &block)
|
143
|
-
|
144
|
-
# TODO: handle channel & connection-level exceptions
|
145
|
-
@channel.queues_awaiting_bind_ok.push(self)
|
146
|
-
end
|
147
|
-
|
148
|
-
self
|
149
|
-
end
|
150
|
-
|
151
|
-
#
|
152
|
-
# @return [Queue] self
|
153
|
-
#
|
154
|
-
# @api public
|
155
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.7.2.5.)
|
156
|
-
def unbind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, arguments = nil, &block)
|
157
|
-
exchange_name = if exchange.respond_to?(:name)
|
158
|
-
exchange.name
|
159
|
-
else
|
160
|
-
|
161
|
-
exchange
|
162
|
-
end
|
163
|
-
|
164
|
-
@connection.send_frame(Protocol::Queue::Unbind.encode(@channel.id, @name, exchange_name, routing_key, arguments))
|
165
|
-
|
166
|
-
self.append_callback(:unbind, &block)
|
167
|
-
# TODO: handle channel & connection-level exceptions
|
168
|
-
@channel.queues_awaiting_unbind_ok.push(self)
|
169
|
-
|
170
|
-
self
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
#
|
175
|
-
# @return [Queue] self
|
176
|
-
#
|
177
|
-
# @api public
|
178
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.3.)
|
179
|
-
def consume(no_ack = false, exclusive = false, nowait = false, no_local = false, arguments = nil, &block)
|
180
|
-
raise RuntimeError.new("This instance is already being consumed! Create another one using #dup.") if @consumer_tag
|
181
|
-
|
182
|
-
nowait = true unless block
|
183
|
-
@consumer_tag = generate_consumer_tag(name)
|
184
|
-
@connection.send_frame(Protocol::Basic::Consume.encode(@channel.id, @name, @consumer_tag, no_local, no_ack, exclusive, nowait, arguments))
|
185
|
-
|
186
|
-
@channel.consumers[@consumer_tag] = self
|
187
|
-
|
188
|
-
if !nowait
|
189
|
-
# unlike #get, here it is reasonable to expect more than one callback
|
190
|
-
# so we use #append_callback
|
191
|
-
self.append_callback(:consume, &block)
|
192
|
-
|
193
|
-
@channel.queues_awaiting_consume_ok.push(self)
|
194
|
-
end
|
195
|
-
|
196
|
-
self
|
197
|
-
end
|
198
|
-
|
199
|
-
# Unique string supposed to be used as a consumer tag.
|
200
|
-
#
|
201
|
-
# @return [String] Unique string.
|
202
|
-
# @api plugin
|
203
|
-
def generate_consumer_tag(name)
|
204
|
-
"#{name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}"
|
205
|
-
end
|
206
|
-
|
207
|
-
# Resets consumer tag by setting it to nil.
|
208
|
-
# @return [String] Consumer tag this queue previously used.
|
209
|
-
#
|
210
|
-
# @api plugin
|
211
|
-
def reset_consumer_tag!
|
212
|
-
ct = @consumer_tag.dup
|
213
|
-
@consumer_tag = nil
|
214
|
-
|
215
|
-
ct
|
216
|
-
end
|
217
|
-
|
218
|
-
|
219
|
-
#
|
220
|
-
# @return [Queue] self
|
221
|
-
#
|
222
|
-
# @api public
|
223
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.10.)
|
224
|
-
def get(no_ack = false, &block)
|
225
|
-
@connection.send_frame(Protocol::Basic::Get.encode(@channel.id, @name, no_ack))
|
226
|
-
|
227
|
-
# most people only want one callback per #get call. Consider the following example:
|
228
|
-
#
|
229
|
-
# 100.times { queue.get { ... } }
|
230
|
-
#
|
231
|
-
# most likely you won't expect 100 callback runs per message here. MK.
|
232
|
-
self.redefine_callback(:get, &block)
|
233
|
-
@channel.queues_awaiting_get_response.push(self)
|
234
|
-
|
235
|
-
self
|
236
|
-
end # get(no_ack = false, &block)
|
237
|
-
|
238
|
-
#
|
239
|
-
# @return [Queue] self
|
240
|
-
#
|
241
|
-
# @api public
|
242
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.5.)
|
243
|
-
def cancel(nowait = false, &block)
|
244
|
-
raise "There is no consumer tag 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 @consumer_tag.nil?
|
245
|
-
|
246
|
-
@connection.send_frame(Protocol::Basic::Cancel.encode(@channel.id, @consumer_tag, nowait))
|
247
|
-
@consumer_tag = nil
|
248
|
-
self.clear_callbacks(:delivery)
|
249
|
-
self.clear_callbacks(:consume)
|
250
|
-
|
251
|
-
if !nowait
|
252
|
-
self.redefine_callback(:cancel, &block)
|
253
|
-
@channel.queues_awaiting_cancel_ok.push(self)
|
254
|
-
end
|
255
|
-
|
256
|
-
self
|
257
|
-
end # cancel(&block)
|
258
|
-
|
259
|
-
#
|
260
|
-
# @return [Queue] self
|
261
|
-
#
|
262
|
-
# @api public
|
263
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.7.2.7.)
|
264
|
-
def purge(nowait = false, &block)
|
265
|
-
nowait = true unless block
|
266
|
-
@connection.send_frame(Protocol::Queue::Purge.encode(@channel.id, @name, nowait))
|
267
|
-
|
268
|
-
if !nowait
|
269
|
-
self.redefine_callback(:purge, &block)
|
270
|
-
# TODO: handle channel & connection-level exceptions
|
271
|
-
@channel.queues_awaiting_purge_ok.push(self)
|
272
|
-
end
|
273
|
-
|
274
|
-
self
|
275
|
-
end # purge(nowait = false, &block)
|
276
|
-
|
277
|
-
#
|
278
|
-
# @return [Queue] self
|
279
|
-
#
|
280
|
-
# @api public
|
281
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.13.)
|
282
|
-
def acknowledge(delivery_tag)
|
283
|
-
@channel.acknowledge(delivery_tag)
|
284
|
-
|
285
|
-
self
|
286
|
-
end # acknowledge(delivery_tag)
|
287
|
-
|
288
|
-
#
|
289
|
-
# @return [Queue] self
|
290
|
-
#
|
291
|
-
# @api public
|
292
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.14.)
|
293
|
-
def reject(delivery_tag, requeue = true)
|
294
|
-
@channel.reject(delivery_tag, requeue)
|
295
|
-
|
296
|
-
self
|
297
|
-
end # reject(delivery_tag, requeue = true)
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
# @api public
|
302
|
-
# @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Sections 1.8.3.9)
|
303
|
-
def on_delivery(&block)
|
304
|
-
self.append_callback(:delivery, &block)
|
305
|
-
end # on_delivery(&block)
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
#
|
310
|
-
# Implementation
|
311
|
-
#
|
312
|
-
|
313
|
-
def handle_declare_ok(method)
|
314
|
-
@name = method.queue if self.anonymous?
|
315
|
-
@channel.register_queue(self)
|
316
|
-
|
317
|
-
self.exec_callback_once_yielding_self(:declare, method)
|
318
|
-
end
|
319
|
-
|
320
|
-
def handle_delete_ok(method)
|
321
|
-
self.exec_callback_once(:delete, method)
|
322
|
-
end # handle_delete_ok(method)
|
323
|
-
|
324
|
-
def handle_consume_ok(method)
|
325
|
-
self.exec_callback_once(:consume, method)
|
326
|
-
end # handle_consume_ok(method)
|
327
|
-
|
328
|
-
def handle_purge_ok(method)
|
329
|
-
self.exec_callback_once(:purge, method)
|
330
|
-
end # handle_purge_ok(method)
|
331
|
-
|
332
|
-
def handle_bind_ok(method)
|
333
|
-
self.exec_callback_once(:bind, method)
|
334
|
-
end # handle_bind_ok(method)
|
335
|
-
|
336
|
-
def handle_unbind_ok(method)
|
337
|
-
self.exec_callback_once(:unbind, method)
|
338
|
-
end # handle_unbind_ok(method)
|
339
|
-
|
340
|
-
def handle_delivery(method, header, payload)
|
341
|
-
self.exec_callback(:delivery, method, header, payload)
|
342
|
-
end # handle_delivery
|
343
|
-
|
344
|
-
def handle_cancel_ok(method)
|
345
|
-
@consumer_tag = nil
|
346
|
-
self.exec_callback_once(:cancel, method)
|
347
|
-
end # handle_cancel_ok(method)
|
348
|
-
|
349
|
-
def handle_get_ok(method, header, payload)
|
350
|
-
method = Protocol::GetResponse.new(method)
|
351
|
-
self.exec_callback(:get, method, header, payload)
|
352
|
-
end # handle_get_ok(method, header, payload)
|
353
|
-
|
354
|
-
def handle_get_empty(method)
|
355
|
-
method = Protocol::GetResponse.new(method)
|
356
|
-
self.exec_callback(:get, method)
|
357
|
-
end # handle_get_empty(method)
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
# Get the first queue which didn't receive Queue.Declare-Ok yet and run its declare callback.
|
362
|
-
# The cache includes only queues with {nowait: false}.
|
363
|
-
self.handle(Protocol::Queue::DeclareOk) do |connection, frame|
|
364
|
-
method = frame.decode_payload
|
365
|
-
|
366
|
-
channel = connection.channels[frame.channel]
|
367
|
-
queue = channel.queues_awaiting_declare_ok.shift
|
368
|
-
|
369
|
-
queue.handle_declare_ok(method)
|
370
|
-
end
|
371
|
-
|
372
|
-
|
373
|
-
self.handle(Protocol::Queue::DeleteOk) do |connection, frame|
|
374
|
-
channel = connection.channels[frame.channel]
|
375
|
-
queue = channel.queues_awaiting_delete_ok.shift
|
376
|
-
queue.handle_delete_ok(frame.decode_payload)
|
377
|
-
end
|
378
|
-
|
379
|
-
|
380
|
-
self.handle(Protocol::Queue::BindOk) do |connection, frame|
|
381
|
-
channel = connection.channels[frame.channel]
|
382
|
-
queue = channel.queues_awaiting_bind_ok.shift
|
383
|
-
|
384
|
-
queue.handle_bind_ok(frame.decode_payload)
|
385
|
-
end
|
386
|
-
|
387
|
-
|
388
|
-
self.handle(Protocol::Queue::UnbindOk) do |connection, frame|
|
389
|
-
channel = connection.channels[frame.channel]
|
390
|
-
queue = channel.queues_awaiting_unbind_ok.shift
|
391
|
-
|
392
|
-
queue.handle_unbind_ok(frame.decode_payload)
|
393
|
-
end
|
394
|
-
|
395
|
-
|
396
|
-
self.handle(Protocol::Basic::ConsumeOk) do |connection, frame|
|
397
|
-
channel = connection.channels[frame.channel]
|
398
|
-
queue = channel.queues_awaiting_consume_ok.shift
|
399
|
-
|
400
|
-
queue.handle_consume_ok(frame.decode_payload)
|
401
|
-
end
|
402
|
-
|
403
|
-
|
404
|
-
self.handle(Protocol::Basic::CancelOk) do |connection, frame|
|
405
|
-
channel = connection.channels[frame.channel]
|
406
|
-
queue = channel.queues_awaiting_cancel_ok.shift
|
407
|
-
|
408
|
-
queue.handle_consume_ok(frame.decode_payload)
|
409
|
-
end
|
410
|
-
|
411
|
-
|
412
|
-
# Basic.Deliver
|
413
|
-
self.handle(Protocol::Basic::Deliver) do |connection, method_frame, content_frames|
|
414
|
-
channel = connection.channels[method_frame.channel]
|
415
|
-
method = method_frame.decode_payload
|
416
|
-
queue = channel.consumers[method.consumer_tag]
|
417
|
-
|
418
|
-
header = content_frames.shift
|
419
|
-
body = content_frames.map { |frame| frame.payload }.join
|
420
|
-
queue.handle_delivery(method, header, body)
|
421
|
-
# TODO: ack if necessary
|
422
|
-
end
|
423
|
-
|
424
|
-
|
425
|
-
self.handle(Protocol::Queue::PurgeOk) do |connection, frame|
|
426
|
-
channel = connection.channels[frame.channel]
|
427
|
-
queue = channel.queues_awaiting_purge_ok.shift
|
428
|
-
|
429
|
-
queue.handle_purge_ok(frame.decode_payload)
|
430
|
-
end
|
431
|
-
|
432
|
-
|
433
|
-
self.handle(Protocol::Basic::GetOk) do |connection, frame, content_frames|
|
434
|
-
channel = connection.channels[frame.channel]
|
435
|
-
queue = channel.queues_awaiting_get_response.shift
|
436
|
-
method = frame.decode_payload
|
437
|
-
|
438
|
-
header = content_frames.shift
|
439
|
-
body = content_frames.map {|frame| frame.payload }.join
|
440
|
-
|
441
|
-
queue.handle_get_ok(method, header, body) if queue
|
442
|
-
end
|
443
|
-
|
444
|
-
|
445
|
-
self.handle(Protocol::Basic::GetEmpty) do |connection, frame|
|
446
|
-
channel = connection.channels[frame.channel]
|
447
|
-
queue = channel.queues_awaiting_get_response.shift
|
448
|
-
|
449
|
-
queue.handle_get_empty(frame.decode_payload)
|
450
|
-
end
|
451
|
-
end # Queue
|
452
|
-
end # Client
|
453
|
-
end # AMQ
|
5
|
+
Queue = Async::Queue
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|