bunny 2.24.0 → 3.1.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.
- checksums.yaml +4 -4
- data/README.md +15 -9
- data/lib/bunny/channel.rb +727 -124
- data/lib/bunny/concurrent/exception_accumulator.rb +115 -0
- data/lib/bunny/consumer.rb +2 -11
- data/lib/bunny/cruby/socket.rb +33 -1
- data/lib/bunny/cruby/ssl_socket.rb +41 -0
- data/lib/bunny/delivery_info.rb +22 -16
- data/lib/bunny/exceptions.rb +31 -2
- data/lib/bunny/exchange.rb +25 -13
- data/lib/bunny/get_response.rb +19 -15
- data/lib/bunny/heartbeat_sender.rb +2 -2
- data/lib/bunny/queue.rb +22 -38
- data/lib/bunny/reader_loop.rb +6 -6
- data/lib/bunny/return_info.rb +16 -11
- data/lib/bunny/session.rb +388 -36
- data/lib/bunny/timestamp.rb +1 -1
- data/lib/bunny/topology_recovery_filter.rb +71 -0
- data/lib/bunny/topology_registry.rb +824 -0
- data/lib/bunny/transport.rb +36 -9
- data/lib/bunny/version.rb +1 -1
- data/lib/bunny.rb +1 -1
- metadata +29 -7
- data/lib/bunny/versioned_delivery_tag.rb +0 -30
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "set"
|
|
5
|
+
require "bunny/topology_recovery_filter"
|
|
6
|
+
|
|
7
|
+
module Bunny
|
|
8
|
+
# As queues, exchanges, bindings are created and deleted,
|
|
9
|
+
# connections keep track of the topology using this registry.
|
|
10
|
+
#
|
|
11
|
+
# Then, when the connection and its channels are recovered,
|
|
12
|
+
# this registry is used as the source of truth during topology
|
|
13
|
+
# recovery.
|
|
14
|
+
#
|
|
15
|
+
# This registry takes care of dropping auto-delete exchanges or queues
|
|
16
|
+
# when their respective conditions for removal hold.
|
|
17
|
+
#
|
|
18
|
+
# @param opts [Hash<Symbol, Object>]
|
|
19
|
+
# @option opts :topology_recovery_filter Filters out objects so that they are skipped during topology recovery
|
|
20
|
+
#
|
|
21
|
+
# @see #record_queue
|
|
22
|
+
# @see #delete_recorded_queue
|
|
23
|
+
# @see #delete_recorded_queue_named
|
|
24
|
+
# @see #record_exchange
|
|
25
|
+
# @see #delete_recorded_exchange
|
|
26
|
+
# @see #delete_recorded_exchange_named
|
|
27
|
+
# @see #record_exchange_binding_with
|
|
28
|
+
# @see #delete_recorded_exchange_binding
|
|
29
|
+
# @see #record_queue_binding_with
|
|
30
|
+
# @see #delete_recorded_queue_binding
|
|
31
|
+
# @see #record_consumer_with
|
|
32
|
+
# @see #delete_recorded_consumer
|
|
33
|
+
class TopologyRegistry
|
|
34
|
+
def initialize(opts = {})
|
|
35
|
+
@filter = opts.fetch(:topology_recovery_filter, DefaultTopologyRecoveryFilter.new)
|
|
36
|
+
|
|
37
|
+
self.reset!
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset!
|
|
41
|
+
@queues = {}
|
|
42
|
+
@exchanges = {}
|
|
43
|
+
@queue_bindings = Set.new
|
|
44
|
+
@exchange_bindings = Set.new
|
|
45
|
+
@consumers = {}
|
|
46
|
+
|
|
47
|
+
@queue_mutex = Monitor.new
|
|
48
|
+
@exchange_mutex = Monitor.new
|
|
49
|
+
@binding_mutex = Monitor.new
|
|
50
|
+
@consumer_mutex = Monitor.new
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# Queues
|
|
55
|
+
#
|
|
56
|
+
|
|
57
|
+
# @!group Queues
|
|
58
|
+
|
|
59
|
+
# @return [Hash<String, Bunny::RecordedQueue>]
|
|
60
|
+
attr_reader :queues
|
|
61
|
+
|
|
62
|
+
# @return [Array<Bunny::RecordedQueue>]
|
|
63
|
+
# @see Bunny::TopologyRecoveryFilter
|
|
64
|
+
def filtered_queues
|
|
65
|
+
@filter.filter_queues(@queues.values)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param [Bunny::Queue] queue
|
|
69
|
+
def record_queue(queue)
|
|
70
|
+
@queue_mutex.synchronize { @queues[queue.name] = RecordedQueue::from(queue) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @param [Bunny::Channel] ch
|
|
74
|
+
# @param [String] name
|
|
75
|
+
# @param [Boolean] server_named
|
|
76
|
+
# @param [Boolean] durable
|
|
77
|
+
# @param [Boolean] auto_delete
|
|
78
|
+
# @param [Boolean] exclusive
|
|
79
|
+
# @param [Hash] arguments
|
|
80
|
+
def record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
|
|
81
|
+
queue = RecordedQueue.new(ch, name)
|
|
82
|
+
.with_server_named(server_named)
|
|
83
|
+
.with_durable(durable)
|
|
84
|
+
.with_auto_delete(auto_delete)
|
|
85
|
+
.with_exclusive(exclusive)
|
|
86
|
+
.with_arguments(arguments)
|
|
87
|
+
|
|
88
|
+
@queue_mutex.synchronize { @queues[queue.name] = queue }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @param [Bunny::Queue, Bunny::RecordedQueue] queue
|
|
92
|
+
def delete_recorded_queue(queue)
|
|
93
|
+
self.delete_recorded_queue_named(queue.name)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @param [String] name
|
|
97
|
+
def delete_recorded_queue_named_without_cascading(name)
|
|
98
|
+
@queue_mutex.synchronize do
|
|
99
|
+
@queues.delete(name)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @param [String] name
|
|
104
|
+
def delete_recorded_queue_named(name)
|
|
105
|
+
@queue_mutex.synchronize do
|
|
106
|
+
@queues.delete(name)
|
|
107
|
+
|
|
108
|
+
bs = self.remove_recorded_bindings_with_queue_destination(name)
|
|
109
|
+
bs.each do |b|
|
|
110
|
+
self.maybe_delete_recorded_auto_delete_exchange(b.source)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @!endgroup
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# Consumers
|
|
119
|
+
#
|
|
120
|
+
|
|
121
|
+
# @!group Consumers
|
|
122
|
+
|
|
123
|
+
# @return [Hash<String, Bunny::RecordedConsumer>]
|
|
124
|
+
attr_reader :consumers
|
|
125
|
+
|
|
126
|
+
# @return [Array<Bunny::RecordedConsumer>]
|
|
127
|
+
# @see Bunny::TopologyRecoveryFilter
|
|
128
|
+
def filtered_consumers
|
|
129
|
+
@filter.filter_consumers(@consumers.values)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @param [Bunny::Channel] ch
|
|
133
|
+
# @param [String] consumer_tag
|
|
134
|
+
# @param [String] queue_name
|
|
135
|
+
# @param [#call] callable
|
|
136
|
+
# @param [Boolean] manual_ack
|
|
137
|
+
# @param [Boolean] exclusive
|
|
138
|
+
# @param [Hash] arguments
|
|
139
|
+
def record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
|
|
140
|
+
@consumer_mutex.synchronize do
|
|
141
|
+
cons = RecordedConsumer.new(ch, queue_name)
|
|
142
|
+
.with_consumer_tag(consumer_tag)
|
|
143
|
+
.with_callable(callable)
|
|
144
|
+
.with_manual_ack(manual_ack)
|
|
145
|
+
.with_exclusive(exclusive)
|
|
146
|
+
.with_arguments(arguments)
|
|
147
|
+
|
|
148
|
+
@consumers[consumer_tag] = cons
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# @param [String] consumer_tag
|
|
153
|
+
def delete_recorded_consumer(consumer_tag)
|
|
154
|
+
@consumer_mutex.synchronize do
|
|
155
|
+
if (val = @consumers.delete(consumer_tag))
|
|
156
|
+
self.maybe_delete_recorded_auto_delete_queue(val.queue_name)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @param [String] old_name
|
|
162
|
+
# @param [String] new_name
|
|
163
|
+
# @private
|
|
164
|
+
def propagate_queue_name_change_to_consumers(old_name, new_name)
|
|
165
|
+
@consumer_mutex.synchronize do
|
|
166
|
+
@consumers.each do |_, rc|
|
|
167
|
+
rc.update_queue_name_to(new_name) if rc.queue_name == old_name
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @!endgroup
|
|
173
|
+
|
|
174
|
+
#
|
|
175
|
+
# Exchanges
|
|
176
|
+
#
|
|
177
|
+
|
|
178
|
+
# @!group Exchanges
|
|
179
|
+
|
|
180
|
+
# @return [Hash<String, Bunny::RecordedExchange>]
|
|
181
|
+
attr_reader :exchanges
|
|
182
|
+
|
|
183
|
+
# @return [Array<Bunny::RecordedExchange>]
|
|
184
|
+
# @see Bunny::TopologyRecoveryFilter
|
|
185
|
+
def filtered_exchanges
|
|
186
|
+
@filter.filter_exchanges(@exchanges.values)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# @param [Bunny::Exchange] exchange
|
|
190
|
+
def record_exchange(exchange)
|
|
191
|
+
@exchange_mutex.synchronize { @exchanges[exchange.name] = RecordedExchange::from(exchange) }
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @param [Bunny::Channel] ch
|
|
195
|
+
# @param [String] name
|
|
196
|
+
# @param [String] type
|
|
197
|
+
# @param [Boolean] durable
|
|
198
|
+
# @param [Boolean] auto_delete
|
|
199
|
+
# @param [Hash] arguments
|
|
200
|
+
def record_exchange_with(ch, name, type, durable, auto_delete, arguments)
|
|
201
|
+
exchange = RecordedExchange.new(ch, name)
|
|
202
|
+
.with_type(type)
|
|
203
|
+
.with_durable(durable)
|
|
204
|
+
.with_auto_delete(auto_delete)
|
|
205
|
+
.with_arguments(arguments)
|
|
206
|
+
|
|
207
|
+
@exchange_mutex.synchronize { @exchanges[exchange.name] = exchange }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @param [Bunny::Exchange, Bunny::RecordedExchange] exchange
|
|
211
|
+
def delete_recorded_exchange(exchange)
|
|
212
|
+
self.delete_recorded_exchange_named(exchange.name)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# @param [String] name
|
|
216
|
+
def delete_recorded_exchange_named(name)
|
|
217
|
+
@exchange_mutex.synchronize do
|
|
218
|
+
@exchanges.delete(name)
|
|
219
|
+
bs1 = self.remove_recorded_bindings_with_source(name)
|
|
220
|
+
bs2 = self.remove_recorded_bindings_with_exchange_destination(name)
|
|
221
|
+
|
|
222
|
+
bs1.each do |b|
|
|
223
|
+
self.maybe_delete_recorded_auto_delete_exchange(b.source)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
bs2.each do |b|
|
|
227
|
+
self.maybe_delete_recorded_auto_delete_exchange(b.source)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# @!endgroup
|
|
233
|
+
|
|
234
|
+
#
|
|
235
|
+
# Bindings
|
|
236
|
+
#
|
|
237
|
+
|
|
238
|
+
# !@group Bindings
|
|
239
|
+
|
|
240
|
+
# @return [Set<Bunny::RecordedQueueBinding>]
|
|
241
|
+
attr_reader :queue_bindings
|
|
242
|
+
|
|
243
|
+
# @return [Array<Bunny::RecordedQueueBinding>]
|
|
244
|
+
# @see Bunny::TopologyRecoveryFilter
|
|
245
|
+
def filtered_queue_bindings
|
|
246
|
+
@filter.filter_queue_bindings(@queue_bindings)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# @return [Set<Bunny::RecordedExchangeBinding>]
|
|
250
|
+
attr_reader :exchange_bindings
|
|
251
|
+
|
|
252
|
+
# @return [Array<Bunny::RecordedExchangeBinding>]
|
|
253
|
+
# @see Bunny::TopologyRecoveryFilter
|
|
254
|
+
def filtered_exchange_bindings
|
|
255
|
+
@filter.filter_exchange_bindings(@exchange_bindings)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# @param [Bunny::Channel] ch
|
|
259
|
+
# @param [String] exchange_name
|
|
260
|
+
# @param [String] queue_name
|
|
261
|
+
# @param [String] routing_key
|
|
262
|
+
# @param [Hash] arguments
|
|
263
|
+
def record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
|
|
264
|
+
b = RecordedQueueBinding.new(ch)
|
|
265
|
+
.with_source(exchange_name)
|
|
266
|
+
.with_destination(queue_name)
|
|
267
|
+
.with_routing_key(routing_key)
|
|
268
|
+
.with_arguments(arguments)
|
|
269
|
+
|
|
270
|
+
@binding_mutex.synchronize { @queue_bindings.add(b) }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# @param [Bunny::Channel] ch
|
|
274
|
+
# @param [String] exchange_name
|
|
275
|
+
# @param [String] queue_name
|
|
276
|
+
# @param [String] routing_key
|
|
277
|
+
# @param [Hash] arguments
|
|
278
|
+
def delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
|
|
279
|
+
b = RecordedQueueBinding.new(ch)
|
|
280
|
+
.with_source(exchange_name)
|
|
281
|
+
.with_destination(queue_name)
|
|
282
|
+
.with_routing_key(routing_key)
|
|
283
|
+
.with_arguments(arguments)
|
|
284
|
+
|
|
285
|
+
@binding_mutex.synchronize { @queue_bindings.delete(b) }
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# @param [Bunny::Channel] ch
|
|
289
|
+
# @param [String] source_name
|
|
290
|
+
# @param [String] destination_name
|
|
291
|
+
# @param [String] routing_key
|
|
292
|
+
# @param [Hash] arguments
|
|
293
|
+
def record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
|
|
294
|
+
b = RecordedExchangeBinding.new(ch)
|
|
295
|
+
.with_source(source_name)
|
|
296
|
+
.with_destination(destination_name)
|
|
297
|
+
.with_routing_key(routing_key)
|
|
298
|
+
.with_arguments(arguments)
|
|
299
|
+
|
|
300
|
+
@binding_mutex.synchronize { @exchange_bindings.add(b) }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# @param [Bunny::Channel] ch
|
|
304
|
+
# @param [String] source_name
|
|
305
|
+
# @param [String] destination_name
|
|
306
|
+
# @param [String] routing_key
|
|
307
|
+
# @param [Hash] arguments
|
|
308
|
+
def delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
|
|
309
|
+
b = RecordedExchangeBinding.new(ch)
|
|
310
|
+
.with_source(source_name)
|
|
311
|
+
.with_destination(destination_name)
|
|
312
|
+
.with_routing_key(routing_key)
|
|
313
|
+
.with_arguments(arguments)
|
|
314
|
+
|
|
315
|
+
@binding_mutex.synchronize do
|
|
316
|
+
if @exchange_bindings.delete?(b)
|
|
317
|
+
self.maybe_delete_recorded_auto_delete_exchange(source_name)
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# @param [String] old_name
|
|
323
|
+
# @param [String] new_name
|
|
324
|
+
# @private
|
|
325
|
+
def record_queue_name_change(old_name, new_name)
|
|
326
|
+
# update the recorded queue itself
|
|
327
|
+
@queue_mutex.synchronize do
|
|
328
|
+
if (orig = @queues[old_name])
|
|
329
|
+
@queues.delete(old_name)
|
|
330
|
+
|
|
331
|
+
orig.update_name_to(new_name)
|
|
332
|
+
@queues[new_name] = orig.dup
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
self.propagate_queue_name_change_to_bindings(old_name, new_name)
|
|
337
|
+
self.propagate_queue_name_change_to_consumers(old_name, new_name)
|
|
338
|
+
# Make sure the original name is removed and won't be recovered
|
|
339
|
+
# but do not cascade
|
|
340
|
+
self.delete_recorded_queue_named_without_cascading(old_name)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# @param [String] old_name
|
|
344
|
+
# @param [String] new_name
|
|
345
|
+
# @private
|
|
346
|
+
def propagate_queue_name_change_to_bindings(old_name, new_name)
|
|
347
|
+
@binding_mutex.synchronize do
|
|
348
|
+
@queue_bindings.each do |rb|
|
|
349
|
+
rb.update_destination_to(new_name) if rb.destination == old_name
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# @!endgroup
|
|
355
|
+
|
|
356
|
+
#
|
|
357
|
+
# Implementation
|
|
358
|
+
#
|
|
359
|
+
|
|
360
|
+
# @param name [String] Auto-delete queue name
|
|
361
|
+
def maybe_delete_recorded_auto_delete_queue(name)
|
|
362
|
+
@queue_mutex.synchronize do
|
|
363
|
+
if (q = @queues[name]) && q.auto_delete?
|
|
364
|
+
unless self.has_more_consumers_on_queue?(@consumers.values, name)
|
|
365
|
+
self.delete_recorded_queue(q)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# @param name [String] Auto-delete exchange name
|
|
372
|
+
def maybe_delete_recorded_auto_delete_exchange(name)
|
|
373
|
+
@exchange_mutex.synchronize do
|
|
374
|
+
if (x = @exchanges[name]) && x.auto_delete
|
|
375
|
+
unless self.has_more_destinations_bound_to_exchange?(@queue_bindings.dup, @exchange_bindings.dup, name)
|
|
376
|
+
self.delete_recorded_exchange_named(name)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# @param name [String]
|
|
383
|
+
# @return [Array<Bunny::RecordedBinding>]
|
|
384
|
+
def remove_recorded_bindings_with_source(name)
|
|
385
|
+
@binding_mutex.synchronize do
|
|
386
|
+
matching_qbs = self.queue_bindings.filter { |b| b.source == name }
|
|
387
|
+
matching_xbs = self.exchange_bindings.filter { |b| b.source == name }
|
|
388
|
+
|
|
389
|
+
matches = matching_qbs + matching_xbs
|
|
390
|
+
matches.each do |b|
|
|
391
|
+
@queue_bindings.delete(b)
|
|
392
|
+
@exchange_bindings.delete(b)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
matches
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# @param name [String]
|
|
400
|
+
# @return [Array<Bunny::RecordedBinding>]
|
|
401
|
+
def remove_recorded_bindings_with_queue_destination(name)
|
|
402
|
+
@binding_mutex.synchronize do
|
|
403
|
+
matches = self.queue_bindings.filter { |b| b.destination == name }
|
|
404
|
+
@queue_bindings = Set.new(@queue_bindings.reject { |b| b.destination == name })
|
|
405
|
+
matches
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# @param name [String]
|
|
410
|
+
# @return [Array<Bunny::RecordedBinding>]
|
|
411
|
+
def remove_recorded_bindings_with_exchange_destination(name)
|
|
412
|
+
@binding_mutex.synchronize do
|
|
413
|
+
matches = self.exchange_bindings.filter { |b| b.destination == name }
|
|
414
|
+
@exchange_bindings = Set.new(@exchange_bindings.reject { |b| b.destination == name })
|
|
415
|
+
matches
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# @param consumers [Array<Bunny::RecordedConsumer]
|
|
420
|
+
# @param name [String]
|
|
421
|
+
def has_more_consumers_on_queue?(consumers, name)
|
|
422
|
+
return false if consumers.empty?
|
|
423
|
+
|
|
424
|
+
consumers.any? { |val| val.queue_name == name }
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# @param queue_bindings [Set<Bunny::RecordedBinding>]
|
|
428
|
+
# @param exchange_bindings [Set<Bunny::RecordedBinding>]
|
|
429
|
+
# @param name [String] Auto-delete exchange name
|
|
430
|
+
def has_more_destinations_bound_to_exchange?(queue_bindings, exchange_bindings, name)
|
|
431
|
+
return false if queue_bindings.empty? && exchange_bindings.empty?
|
|
432
|
+
|
|
433
|
+
condition_one = queue_bindings.any? { |val| val.source == name }
|
|
434
|
+
condition_two = exchange_bindings.any? { |val| val.source == name }
|
|
435
|
+
|
|
436
|
+
condition_one || condition_two
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
#
|
|
441
|
+
# Recordable, Recoverable Entities
|
|
442
|
+
#
|
|
443
|
+
|
|
444
|
+
# @abstract
|
|
445
|
+
class RecordedEntity
|
|
446
|
+
# @return [Bunny::Channel]
|
|
447
|
+
attr_reader :channel
|
|
448
|
+
|
|
449
|
+
# @param ch [Bunny::Channel]
|
|
450
|
+
def initialize(ch)
|
|
451
|
+
@channel = ch
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
# @abstract Represents a named topology entity
|
|
455
|
+
class RecordedNamedEntity < RecordedEntity
|
|
456
|
+
# @return [String]
|
|
457
|
+
attr_reader :name
|
|
458
|
+
|
|
459
|
+
# @param ch [Bunny::Channel]
|
|
460
|
+
# @param name [String]
|
|
461
|
+
def initialize(ch, name)
|
|
462
|
+
@name = name
|
|
463
|
+
|
|
464
|
+
super(ch)
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# Represents an exchange declaration intent that can be repeated.
|
|
469
|
+
class RecordedExchange < RecordedNamedEntity
|
|
470
|
+
# @return [String]
|
|
471
|
+
attr_reader :type
|
|
472
|
+
# @return [Boolean]
|
|
473
|
+
attr_reader :durable
|
|
474
|
+
# @return [Boolean]
|
|
475
|
+
attr_reader :auto_delete
|
|
476
|
+
# @return [Hash]
|
|
477
|
+
attr_reader :arguments
|
|
478
|
+
|
|
479
|
+
# @param ch [Bunny::Channel]
|
|
480
|
+
# @param name [String]
|
|
481
|
+
def initialize(ch, name)
|
|
482
|
+
super(ch, name)
|
|
483
|
+
|
|
484
|
+
@type = nil
|
|
485
|
+
@durable = true
|
|
486
|
+
@auto_delete = false
|
|
487
|
+
@arguments = nil
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# @return [Boolean] true if this exchange is a pre-defined one (amq.direct, amq.fanout, amq.match and so on)
|
|
491
|
+
def predefined?
|
|
492
|
+
(@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\.(direct|fanout|topic|headers|match)/i)
|
|
493
|
+
end # predefined?
|
|
494
|
+
alias predeclared? predefined?
|
|
495
|
+
|
|
496
|
+
# @param value [Boolean]
|
|
497
|
+
def with_durable(value)
|
|
498
|
+
@durable = value
|
|
499
|
+
self
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# @param value [Boolean]
|
|
503
|
+
def with_auto_delete(value)
|
|
504
|
+
@auto_delete = value
|
|
505
|
+
self
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
# @param value [Symbol]
|
|
509
|
+
def with_type(value)
|
|
510
|
+
@type = value
|
|
511
|
+
self
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
# @param value [Hash]
|
|
515
|
+
def with_arguments(value)
|
|
516
|
+
@arguments = value
|
|
517
|
+
self
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# @return [Integer]
|
|
521
|
+
def hash
|
|
522
|
+
[self.class, self.channel, self.name, @type, @durable, @auto_delete, @arguments].hash
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
# @return [Boolean]
|
|
526
|
+
def eql?(other)
|
|
527
|
+
self == other
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
# @return [Boolean]
|
|
531
|
+
def ==(other)
|
|
532
|
+
other.class == self.class &&
|
|
533
|
+
other.name == self.name &&
|
|
534
|
+
other.channel == self.channel &&
|
|
535
|
+
other.durable == self.durable &&
|
|
536
|
+
other.auto_delete == self.auto_delete &&
|
|
537
|
+
other.type == self.type &&
|
|
538
|
+
other.arguments == self.arguments
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# @param [Bunny::Exchange] x
|
|
542
|
+
def self.from(x)
|
|
543
|
+
new(x.channel, x.name)
|
|
544
|
+
.with_type(x.type)
|
|
545
|
+
.with_durable(x.durable?)
|
|
546
|
+
.with_auto_delete(x.auto_delete?)
|
|
547
|
+
.with_arguments(x.arguments)
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# Represents an exchange declaration intent that can be repeated.
|
|
552
|
+
#
|
|
553
|
+
# Server-named queues will acquire a new server-generated name.
|
|
554
|
+
class RecordedQueue < RecordedNamedEntity
|
|
555
|
+
EMPTY_STRING = "".freeze
|
|
556
|
+
|
|
557
|
+
# @return [Boolean]
|
|
558
|
+
attr_reader :durable, :auto_delete, :exclusive
|
|
559
|
+
# @return [Hash]
|
|
560
|
+
attr_reader :arguments
|
|
561
|
+
|
|
562
|
+
# @param ch [Bunny::Channel]
|
|
563
|
+
# @param name [String]
|
|
564
|
+
def initialize(ch, name)
|
|
565
|
+
super ch, name
|
|
566
|
+
|
|
567
|
+
@durable = true
|
|
568
|
+
@auto_delete = false
|
|
569
|
+
@exclusive = false
|
|
570
|
+
@server_named = false
|
|
571
|
+
@arguments = nil
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# @param value [String]
|
|
575
|
+
def update_name_to(value)
|
|
576
|
+
@name = value
|
|
577
|
+
self
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# @param value [Boolean]
|
|
581
|
+
def with_durable(value)
|
|
582
|
+
@durable = value
|
|
583
|
+
self
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# @param value [Boolean]
|
|
587
|
+
def with_auto_delete(value)
|
|
588
|
+
@auto_delete = value
|
|
589
|
+
self
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
def auto_delete?
|
|
593
|
+
@auto_delete
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
# @param value [Boolean]
|
|
597
|
+
def with_exclusive(value)
|
|
598
|
+
@exclusive = value
|
|
599
|
+
self
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def exclusive?
|
|
603
|
+
@exclusive
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# @param value [Boolean]
|
|
607
|
+
def with_server_named(value)
|
|
608
|
+
@server_named = value
|
|
609
|
+
self
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
# @return [Boolean]
|
|
613
|
+
def server_named?
|
|
614
|
+
!!@server_named
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# @param value [Hash]
|
|
618
|
+
def with_arguments(value)
|
|
619
|
+
@arguments = value
|
|
620
|
+
self
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
# @return [String]
|
|
624
|
+
def name_to_use_for_recovery
|
|
625
|
+
if server_named?
|
|
626
|
+
EMPTY_STRING
|
|
627
|
+
else
|
|
628
|
+
self.name
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
# @return [Boolean]
|
|
633
|
+
def eql?(other)
|
|
634
|
+
self == other
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# @return [Boolean]
|
|
638
|
+
def ==(other)
|
|
639
|
+
other.class == self.class &&
|
|
640
|
+
other.name == self.name &&
|
|
641
|
+
other.channel == self.channel &&
|
|
642
|
+
other.durable == self.durable &&
|
|
643
|
+
other.auto_delete == self.auto_delete &&
|
|
644
|
+
other.exclusive == self.exclusive &&
|
|
645
|
+
other.arguments == self.arguments
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def hash
|
|
649
|
+
[self.class, self.channel, @name, @durable].hash
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# @param [Bunny::Queue] q
|
|
653
|
+
def self.from(q)
|
|
654
|
+
new(q.channel, q.name)
|
|
655
|
+
.with_server_named(q.server_named?)
|
|
656
|
+
.with_durable(q.durable?)
|
|
657
|
+
.with_auto_delete(q.auto_delete?)
|
|
658
|
+
.with_exclusive(q.exclusive?)
|
|
659
|
+
.with_arguments(q.arguments)
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
# Represents a consumer (subscription) registration intent that can be repeated.
|
|
664
|
+
class RecordedConsumer < RecordedEntity
|
|
665
|
+
# @return [String]
|
|
666
|
+
attr_reader :queue_name, :consumer_tag
|
|
667
|
+
# @return [#call]
|
|
668
|
+
attr_reader :callable
|
|
669
|
+
# @return [Boolean]
|
|
670
|
+
attr_reader :exclusive, :manual_ack
|
|
671
|
+
# @return [Hash]
|
|
672
|
+
attr_reader :arguments
|
|
673
|
+
|
|
674
|
+
# @param ch [Bunny::Channel]
|
|
675
|
+
# @param queue_name [String]
|
|
676
|
+
def initialize(ch, queue_name)
|
|
677
|
+
super ch
|
|
678
|
+
|
|
679
|
+
@queue_name = queue_name
|
|
680
|
+
@consumer_tag = nil
|
|
681
|
+
@callable = nil
|
|
682
|
+
@exclusive = false
|
|
683
|
+
@manual_ack = true
|
|
684
|
+
@arguments = Hash.new
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
# @param value [String]
|
|
688
|
+
def update_queue_name_to(value)
|
|
689
|
+
@queue_name = value
|
|
690
|
+
self
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# @param value [String]
|
|
694
|
+
def with_queue_name(value)
|
|
695
|
+
@queue_name = value
|
|
696
|
+
self
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
# @param value [String]
|
|
700
|
+
def with_consumer_tag(value)
|
|
701
|
+
@consumer_tag = value
|
|
702
|
+
self
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
# @param value [#call, Proc]
|
|
706
|
+
def with_callable(value)
|
|
707
|
+
@callable = value
|
|
708
|
+
self
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
def with_manual_ack(value)
|
|
712
|
+
@manual_ack = value
|
|
713
|
+
self
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def with_exclusive(value)
|
|
717
|
+
@exclusive = value
|
|
718
|
+
self
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
# @param value [Hash]
|
|
722
|
+
def with_arguments(value)
|
|
723
|
+
@arguments = value
|
|
724
|
+
self
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
def eql?(other)
|
|
728
|
+
self == other
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
# @param other [Bunny::RecordedConsumer]
|
|
732
|
+
# @return [Boolean]
|
|
733
|
+
def ==(other)
|
|
734
|
+
other.class == self.class &&
|
|
735
|
+
other.channel == self.channel &&
|
|
736
|
+
other.queue_name == self.queue_name &&
|
|
737
|
+
other.callable == self.callable &&
|
|
738
|
+
other.manual_ack == self.manual_ack &&
|
|
739
|
+
other.exclusive == self.exclusive &&
|
|
740
|
+
other.arguments == self.arguments
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
def hash
|
|
744
|
+
[self.class, self.channel, @queue_name, @consumer_tag, @callable, @exclusive, @manual_ack, @arguments].hash
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
class RecordedBinding < RecordedEntity
|
|
749
|
+
# @return [String]
|
|
750
|
+
attr_reader :source
|
|
751
|
+
# @return [String]
|
|
752
|
+
attr_reader :destination
|
|
753
|
+
# @return [String]
|
|
754
|
+
attr_reader :routing_key
|
|
755
|
+
# @return [Hash]
|
|
756
|
+
attr_reader :arguments
|
|
757
|
+
|
|
758
|
+
def initialize(ch)
|
|
759
|
+
super ch
|
|
760
|
+
|
|
761
|
+
@source = nil
|
|
762
|
+
@destination = nil
|
|
763
|
+
@routing_key = nil
|
|
764
|
+
@arguments = Hash.new
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# @param value [String]
|
|
768
|
+
def with_source(value)
|
|
769
|
+
@source = value
|
|
770
|
+
self
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
# @param value [String]
|
|
774
|
+
def with_destination(value)
|
|
775
|
+
@destination = value
|
|
776
|
+
self
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
# @param value [String]
|
|
780
|
+
def with_routing_key(value)
|
|
781
|
+
@routing_key = value
|
|
782
|
+
self
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
# @param value [Hash]
|
|
786
|
+
def with_arguments(value)
|
|
787
|
+
@arguments = value
|
|
788
|
+
self
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
def hash
|
|
792
|
+
[self.class, @source, @destination, @routing_key, @arguments].hash
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
# @param other [Bunny::RecordedBinding]
|
|
796
|
+
# @return [Boolean]
|
|
797
|
+
def eql?(other)
|
|
798
|
+
self == other
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
# @param other [Bunny::RecordedBinding]
|
|
802
|
+
# @return [Boolean]
|
|
803
|
+
def ==(other)
|
|
804
|
+
other.class == self.class &&
|
|
805
|
+
other.source == self.source &&
|
|
806
|
+
other.destination == self.destination &&
|
|
807
|
+
other.routing_key == self.routing_key &&
|
|
808
|
+
other.arguments == self.arguments
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
# Represents a queue binding intent that can be repeated.
|
|
813
|
+
class RecordedQueueBinding < RecordedBinding
|
|
814
|
+
# @param value [String]
|
|
815
|
+
def update_destination_to(value)
|
|
816
|
+
@destination = value
|
|
817
|
+
self
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
# Represents an exchange binding intent that can be repeated.
|
|
822
|
+
class RecordedExchangeBinding < RecordedBinding
|
|
823
|
+
end
|
|
824
|
+
end
|