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
data/lib/bunny/channel.rb
CHANGED
|
@@ -153,6 +153,12 @@ module Bunny
|
|
|
153
153
|
attr_reader :unconfirmed_set
|
|
154
154
|
# @return [Set<Integer>] Set of nacked message indexes that have been nacked
|
|
155
155
|
attr_reader :nacked_set
|
|
156
|
+
# @return [Boolean] true if publisher confirm tracking is enabled
|
|
157
|
+
attr_reader :confirms_tracking_enabled
|
|
158
|
+
# @return [Integer, nil] Maximum outstanding unconfirmed messages before throttling
|
|
159
|
+
attr_reader :outstanding_limit
|
|
160
|
+
# @return [Integer, nil] Timeout in milliseconds for waiting on publisher confirms
|
|
161
|
+
attr_reader :confirm_timeout
|
|
156
162
|
# @return [Hash<String, Bunny::Consumer>] Consumer instances declared on this channel
|
|
157
163
|
attr_reader :consumers
|
|
158
164
|
|
|
@@ -164,12 +170,19 @@ module Bunny
|
|
|
164
170
|
attr_reader :cancel_consumers_before_closing
|
|
165
171
|
|
|
166
172
|
DEFAULT_CONTENT_TYPE = "application/octet-stream".freeze
|
|
173
|
+
|
|
174
|
+
# Default outstanding limit for publisher confirms with tracking.
|
|
175
|
+
# Batch size of 1000 provides optimal throughput per benchmarks.
|
|
176
|
+
DEFAULT_OUTSTANDING_CONFIRMS_LIMIT = 1000
|
|
167
177
|
SHORTSTR_LIMIT = 255
|
|
168
178
|
|
|
169
179
|
# @param [Bunny::Session] connection AMQP 0.9.1 connection
|
|
170
180
|
# @param [Integer] id Channel id, pass nil to make Bunny automatically allocate it
|
|
171
|
-
# @param [
|
|
172
|
-
|
|
181
|
+
# @param [HashMap] opts Additional options
|
|
182
|
+
# @option opts [Bunny::ConsumerWorkPool] work_pool Thread pool for delivery processing, by default of size 1
|
|
183
|
+
def initialize(connection = nil, id = nil, opts = {})
|
|
184
|
+
work_pool = opts.fetch(:work_pool, ConsumerWorkPool.new(1))
|
|
185
|
+
|
|
173
186
|
@connection = connection
|
|
174
187
|
@logger = connection.logger
|
|
175
188
|
@id = id || @connection.next_channel_id
|
|
@@ -185,7 +198,6 @@ module Bunny
|
|
|
185
198
|
end
|
|
186
199
|
|
|
187
200
|
@status = :opening
|
|
188
|
-
|
|
189
201
|
@connection.register_channel(self)
|
|
190
202
|
|
|
191
203
|
@queues = Hash.new
|
|
@@ -202,6 +214,15 @@ module Bunny
|
|
|
202
214
|
|
|
203
215
|
@unconfirmed_set_mutex = @connection.mutex_impl.new
|
|
204
216
|
|
|
217
|
+
# Publisher confirm tracking (initialized before reset_continuations)
|
|
218
|
+
@confirms_tracking_enabled = false
|
|
219
|
+
@outstanding_limit = nil
|
|
220
|
+
@confirm_timeout = nil
|
|
221
|
+
@throttle_publishes = false
|
|
222
|
+
@per_message_continuations = {}
|
|
223
|
+
@per_message_continuations_mutex = @connection.mutex_impl.new
|
|
224
|
+
@outstanding_limit_cond = nil
|
|
225
|
+
|
|
205
226
|
self.reset_continuations
|
|
206
227
|
|
|
207
228
|
# threads awaiting on continuations. Used to unblock
|
|
@@ -214,15 +235,15 @@ module Bunny
|
|
|
214
235
|
@next_publish_seq_no = 0
|
|
215
236
|
@delivery_tag_offset = 0
|
|
216
237
|
|
|
217
|
-
@recoveries_counter = Bunny::Concurrent::AtomicFixnum.new(0)
|
|
218
238
|
@uncaught_exception_handler = Proc.new do |e, consumer|
|
|
219
239
|
@logger.error "Uncaught exception from consumer #{consumer.to_s}: #{e.inspect} @ #{e.backtrace[0]}"
|
|
220
240
|
end
|
|
221
241
|
|
|
222
242
|
@cancel_consumers_before_closing = false
|
|
223
|
-
end
|
|
224
243
|
|
|
225
|
-
|
|
244
|
+
@last_consumer_tag = nil
|
|
245
|
+
@last_consumer = nil
|
|
246
|
+
end
|
|
226
247
|
|
|
227
248
|
# @private
|
|
228
249
|
def wait_on_continuations_timeout
|
|
@@ -240,6 +261,7 @@ module Bunny
|
|
|
240
261
|
@connection.open_channel(self)
|
|
241
262
|
# clear last channel error
|
|
242
263
|
@last_channel_error = nil
|
|
264
|
+
@frame_max = @connection.frame_max
|
|
243
265
|
|
|
244
266
|
@status = :open
|
|
245
267
|
|
|
@@ -276,6 +298,35 @@ module Bunny
|
|
|
276
298
|
maybe_kill_consumer_work_pool!
|
|
277
299
|
end
|
|
278
300
|
|
|
301
|
+
# Reopens a channel that was closed by the server (e.g. due to a consumer
|
|
302
|
+
# delivery acknowledgement timeout). The channel is reopened on the same
|
|
303
|
+
# connection, reusing its original channel id, and its prefetch, confirm,
|
|
304
|
+
# and transactional settings are recovered.
|
|
305
|
+
#
|
|
306
|
+
# This does NOT recover topology (queues, exchanges, bindings, consumers).
|
|
307
|
+
# Use {Bunny::Session#recover_channel_topology} for that.
|
|
308
|
+
#
|
|
309
|
+
# @return [Bunny::Channel] self
|
|
310
|
+
# @see Bunny::Session#recover_channel_topology
|
|
311
|
+
# @api public
|
|
312
|
+
def reopen
|
|
313
|
+
raise "Cannot reopen a channel that is not closed" unless closed?
|
|
314
|
+
|
|
315
|
+
existing = @connection.synchronised_find_channel(@id)
|
|
316
|
+
if existing && existing != self
|
|
317
|
+
raise "Channel id #{@id} has been reassigned to another channel"
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
@work_pool = ConsumerWorkPool.new(@work_pool.size, @work_pool.abort_on_exception)
|
|
321
|
+
@work_pool.start
|
|
322
|
+
|
|
323
|
+
open
|
|
324
|
+
|
|
325
|
+
recover_from_network_failure
|
|
326
|
+
|
|
327
|
+
self
|
|
328
|
+
end
|
|
329
|
+
|
|
279
330
|
# @return [Boolean] true if this channel is open, false otherwise
|
|
280
331
|
# @api public
|
|
281
332
|
def open?
|
|
@@ -288,6 +339,21 @@ module Bunny
|
|
|
288
339
|
@status == :closed
|
|
289
340
|
end
|
|
290
341
|
|
|
342
|
+
# @private
|
|
343
|
+
def connection_closed!
|
|
344
|
+
@status = :closed
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# @private
|
|
348
|
+
def recovering!
|
|
349
|
+
@status = :recovering
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# @private
|
|
353
|
+
def recovery_completed!
|
|
354
|
+
@status = :open
|
|
355
|
+
end
|
|
356
|
+
|
|
291
357
|
#
|
|
292
358
|
# @group Backwards compatibility with 0.8.0
|
|
293
359
|
#
|
|
@@ -423,7 +489,7 @@ module Bunny
|
|
|
423
489
|
# @param [String] name Exchange name
|
|
424
490
|
# @param [Hash] opts Exchange parameters
|
|
425
491
|
#
|
|
426
|
-
# @option opts [String,Symbol] :type (:direct) Exchange type, e.g. :fanout or "x-consistent-hash"
|
|
492
|
+
# @option opts [String,Symbol] :type (:direct) Exchange type, e.g. :fanout or "x-consistent-hash" or "x-modulus-hash"
|
|
427
493
|
# @option opts [Boolean] :durable (false) Should the exchange be durable?
|
|
428
494
|
# @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
|
|
429
495
|
# @option opts [Hash] :arguments ({}) Optional exchange arguments
|
|
@@ -459,6 +525,7 @@ module Bunny
|
|
|
459
525
|
|
|
460
526
|
q = find_queue(name) || Bunny::Queue.new(self, name, opts)
|
|
461
527
|
|
|
528
|
+
record_queue(q)
|
|
462
529
|
register_queue(q)
|
|
463
530
|
end
|
|
464
531
|
|
|
@@ -502,6 +569,67 @@ module Bunny
|
|
|
502
569
|
durable_queue(name, Bunny::Queue::Types::STREAM, opts)
|
|
503
570
|
end
|
|
504
571
|
|
|
572
|
+
# Declares a Tanzu RabbitMQ delayed queue (a durable, replicated queue type).
|
|
573
|
+
# This queue type must be durable, non-exclusive, and non-auto-delete.
|
|
574
|
+
#
|
|
575
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
|
576
|
+
# @param [Hash] opts Queue properties
|
|
577
|
+
#
|
|
578
|
+
# @option opts [String] :delayed_retry_type ("all") Retry strategy: "all", "failed", or "returned"
|
|
579
|
+
# @option opts [Integer] :delayed_retry_min (nil) Minimum retry delay in milliseconds
|
|
580
|
+
# @option opts [Integer] :delayed_retry_max (nil) Maximum retry delay in milliseconds
|
|
581
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
|
582
|
+
#
|
|
583
|
+
# @return [Bunny::Queue] Queue that was declared
|
|
584
|
+
# @see #durable_queue
|
|
585
|
+
# @see #queue
|
|
586
|
+
# @api public
|
|
587
|
+
def delayed_queue(name, opts = {})
|
|
588
|
+
throw ArgumentError.new("delayed queue name must not be nil") if name.nil?
|
|
589
|
+
throw ArgumentError.new("delayed queue name must not be empty") if name.empty?
|
|
590
|
+
|
|
591
|
+
args = opts[:arguments] || {}
|
|
592
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_TYPE] = opts[:delayed_retry_type] if opts[:delayed_retry_type]
|
|
593
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_MIN] = opts[:delayed_retry_min] if opts[:delayed_retry_min]
|
|
594
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_MAX] = opts[:delayed_retry_max] if opts[:delayed_retry_max]
|
|
595
|
+
|
|
596
|
+
final_opts = opts.merge(:arguments => args)
|
|
597
|
+
final_opts.delete(:delayed_retry_type)
|
|
598
|
+
final_opts.delete(:delayed_retry_min)
|
|
599
|
+
final_opts.delete(:delayed_retry_max)
|
|
600
|
+
|
|
601
|
+
durable_queue(name, Bunny::Queue::Types::DELAYED, final_opts)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Declares a Tanzu RabbitMQ JMS queue (a durable, replicated queue type).
|
|
605
|
+
# This queue type must be durable, non-exclusive, and non-auto-delete.
|
|
606
|
+
#
|
|
607
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
|
608
|
+
# @param [Hash] opts Queue properties
|
|
609
|
+
#
|
|
610
|
+
# @option opts [Array<String>] :selector_fields (nil) Fields available for JMS selector expressions (e.g. ["priority", "region"], or ["*"] for all)
|
|
611
|
+
# @option opts [Integer] :selector_field_max_bytes (nil) Maximum byte size per selector field
|
|
612
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
|
613
|
+
#
|
|
614
|
+
# @return [Bunny::Queue] Queue that was declared
|
|
615
|
+
# @see #durable_queue
|
|
616
|
+
# @see #queue
|
|
617
|
+
# @api public
|
|
618
|
+
def jms_queue(name, opts = {})
|
|
619
|
+
throw ArgumentError.new("JMS queue name must not be nil") if name.nil?
|
|
620
|
+
throw ArgumentError.new("JMS queue name must not be empty") if name.empty?
|
|
621
|
+
|
|
622
|
+
args = opts[:arguments] || {}
|
|
623
|
+
args[Bunny::Queue::XArgs::SELECTOR_FIELDS] = opts[:selector_fields] if opts[:selector_fields]
|
|
624
|
+
args[Bunny::Queue::XArgs::SELECTOR_FIELD_MAX_BYTES] = opts[:selector_field_max_bytes] if opts[:selector_field_max_bytes]
|
|
625
|
+
|
|
626
|
+
final_opts = opts.merge(:arguments => args)
|
|
627
|
+
final_opts.delete(:selector_fields)
|
|
628
|
+
final_opts.delete(:selector_field_max_bytes)
|
|
629
|
+
|
|
630
|
+
durable_queue(name, Bunny::Queue::Types::JMS, final_opts)
|
|
631
|
+
end
|
|
632
|
+
|
|
505
633
|
# Declares a new server-named queue that is automatically deleted when the
|
|
506
634
|
# connection is closed.
|
|
507
635
|
#
|
|
@@ -526,6 +654,7 @@ module Bunny
|
|
|
526
654
|
})
|
|
527
655
|
q = find_queue(name) || Bunny::Queue.new(self, name, final_opts)
|
|
528
656
|
|
|
657
|
+
record_queue(q)
|
|
529
658
|
register_queue(q)
|
|
530
659
|
end
|
|
531
660
|
|
|
@@ -660,10 +789,25 @@ module Bunny
|
|
|
660
789
|
opts[:content_type] ||= DEFAULT_CONTENT_TYPE
|
|
661
790
|
opts[:priority] ||= 0
|
|
662
791
|
|
|
792
|
+
seq_no = nil
|
|
793
|
+
continuation = nil
|
|
794
|
+
|
|
663
795
|
if @next_publish_seq_no > 0
|
|
664
796
|
@unconfirmed_set_mutex.synchronize do
|
|
665
|
-
|
|
797
|
+
# With outstanding_limit: wait for slot if at the limit
|
|
798
|
+
wait_for_outstanding_slot_locked if @throttle_publishes
|
|
799
|
+
|
|
800
|
+
seq_no = @next_publish_seq_no
|
|
801
|
+
@unconfirmed_set.add(seq_no)
|
|
666
802
|
@next_publish_seq_no += 1
|
|
803
|
+
|
|
804
|
+
# Only create per-message continuation when blocking individually (no limit)
|
|
805
|
+
if @confirms_tracking_enabled && !@throttle_publishes
|
|
806
|
+
continuation = new_continuation
|
|
807
|
+
@per_message_continuations_mutex.synchronize do
|
|
808
|
+
@per_message_continuations[seq_no] = continuation
|
|
809
|
+
end
|
|
810
|
+
end
|
|
667
811
|
end
|
|
668
812
|
end
|
|
669
813
|
|
|
@@ -674,9 +818,90 @@ module Bunny
|
|
|
674
818
|
routing_key,
|
|
675
819
|
opts[:mandatory],
|
|
676
820
|
false,
|
|
677
|
-
@
|
|
821
|
+
@frame_max)
|
|
678
822
|
@connection.send_frameset(frames, self)
|
|
679
823
|
|
|
824
|
+
wait_for_publish_confirm(seq_no, continuation) if continuation
|
|
825
|
+
|
|
826
|
+
self
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
# Publishes multiple messages in a batch with a single mutex acquisition.
|
|
830
|
+
# More efficient than calling basic_publish repeatedly when using publisher
|
|
831
|
+
# confirms with tracking. Recommended batch sizes: 500-3000.
|
|
832
|
+
#
|
|
833
|
+
# @param [Array<String>] payloads Array of message payloads to publish
|
|
834
|
+
# @param [String, Bunny::Exchange] exchange Exchange name or object
|
|
835
|
+
# @param [String] routing_key Routing key
|
|
836
|
+
# @param [Hash] opts Publishing options (applied to all messages)
|
|
837
|
+
# @return [self]
|
|
838
|
+
#
|
|
839
|
+
# @example Batch publishing with confirms
|
|
840
|
+
# ch.confirm_select(tracking: true)
|
|
841
|
+
# messages = 100.times.map { |i| "message #{i}" }
|
|
842
|
+
# ch.basic_publish_batch(messages, "", queue.name)
|
|
843
|
+
#
|
|
844
|
+
# @api public
|
|
845
|
+
def basic_publish_batch(payloads, exchange, routing_key, opts = {})
|
|
846
|
+
raise_if_no_longer_open!
|
|
847
|
+
raise ArgumentError, "payloads must be an Array" unless payloads.is_a?(Array)
|
|
848
|
+
raise ArgumentError, "routing key cannot be longer than #{SHORTSTR_LIMIT} characters" if routing_key && routing_key.size > SHORTSTR_LIMIT
|
|
849
|
+
return self if payloads.empty?
|
|
850
|
+
|
|
851
|
+
exchange_name = if exchange.respond_to?(:name)
|
|
852
|
+
exchange.name
|
|
853
|
+
else
|
|
854
|
+
exchange
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
mode = opts.fetch(:persistent, true) ? 2 : 1
|
|
858
|
+
opts = opts.dup
|
|
859
|
+
opts[:delivery_mode] ||= mode
|
|
860
|
+
opts[:content_type] ||= DEFAULT_CONTENT_TYPE
|
|
861
|
+
opts[:priority] ||= 0
|
|
862
|
+
|
|
863
|
+
batch_size = payloads.size
|
|
864
|
+
|
|
865
|
+
if @next_publish_seq_no > 0
|
|
866
|
+
@unconfirmed_set_mutex.synchronize do
|
|
867
|
+
# With throttling: wait until we have room for the batch
|
|
868
|
+
if @throttle_publishes
|
|
869
|
+
limit = @outstanding_limit
|
|
870
|
+
target = [limit - batch_size, 0].max
|
|
871
|
+
timeout_sec = (@confirm_timeout || @connection.continuation_timeout) / 1000.0
|
|
872
|
+
deadline = nil
|
|
873
|
+
|
|
874
|
+
while @unconfirmed_set.size > target
|
|
875
|
+
raise_if_no_longer_open!
|
|
876
|
+
deadline ||= Bunny::Timestamp.monotonic + timeout_sec
|
|
877
|
+
remaining = deadline - Bunny::Timestamp.monotonic
|
|
878
|
+
raise Timeout::Error, "Timed out waiting for publisher confirms (batch: #{batch_size}, limit: #{limit})" if remaining <= 0
|
|
879
|
+
@outstanding_limit_cond.wait(remaining)
|
|
880
|
+
end
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
# Register all sequence numbers at once
|
|
884
|
+
start_seq = @next_publish_seq_no
|
|
885
|
+
batch_size.times { |i| @unconfirmed_set.add(start_seq + i) }
|
|
886
|
+
@next_publish_seq_no = start_seq + batch_size
|
|
887
|
+
end
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
# Encode all messages into a single buffer and write once
|
|
891
|
+
data = +""
|
|
892
|
+
payloads.each do |payload|
|
|
893
|
+
frames = AMQ::Protocol::Basic::Publish.encode(@id,
|
|
894
|
+
payload,
|
|
895
|
+
opts,
|
|
896
|
+
exchange_name,
|
|
897
|
+
routing_key,
|
|
898
|
+
opts[:mandatory],
|
|
899
|
+
false,
|
|
900
|
+
@frame_max)
|
|
901
|
+
frames.each { |frame| data << frame.encode }
|
|
902
|
+
end
|
|
903
|
+
@connection.send_raw_without_timeout(data, self)
|
|
904
|
+
|
|
680
905
|
self
|
|
681
906
|
end
|
|
682
907
|
|
|
@@ -753,19 +978,19 @@ module Bunny
|
|
|
753
978
|
# @see Bunny::Channel#prefetch
|
|
754
979
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
755
980
|
# @api public
|
|
756
|
-
def basic_qos(
|
|
757
|
-
raise ArgumentError.new("prefetch count must be a positive integer, given: #{
|
|
758
|
-
raise ArgumentError.new("prefetch count must be no greater than #{MAX_PREFETCH_COUNT}, given: #{
|
|
981
|
+
def basic_qos(prefetch_count, global = false)
|
|
982
|
+
raise ArgumentError.new("prefetch count must be a positive integer, given: #{prefetch_count}") if prefetch_count < 0
|
|
983
|
+
raise ArgumentError.new("prefetch count must be no greater than #{MAX_PREFETCH_COUNT}, given: #{prefetch_count}") if prefetch_count > MAX_PREFETCH_COUNT
|
|
759
984
|
raise_if_no_longer_open!
|
|
760
985
|
|
|
761
|
-
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0,
|
|
986
|
+
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, prefetch_count, global))
|
|
762
987
|
|
|
763
988
|
with_continuation_timeout do
|
|
764
989
|
@last_basic_qos_ok = wait_on_continuations
|
|
765
990
|
end
|
|
766
991
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
767
992
|
|
|
768
|
-
@prefetch_count =
|
|
993
|
+
@prefetch_count = prefetch_count
|
|
769
994
|
@prefetch_global = global
|
|
770
995
|
|
|
771
996
|
@last_basic_qos_ok
|
|
@@ -828,12 +1053,10 @@ module Bunny
|
|
|
828
1053
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
829
1054
|
# @api public
|
|
830
1055
|
def basic_reject(delivery_tag, requeue = false)
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
|
1056
|
+
raise_if_no_longer_open!
|
|
1057
|
+
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
|
834
1058
|
|
|
835
|
-
|
|
836
|
-
end
|
|
1059
|
+
nil
|
|
837
1060
|
end
|
|
838
1061
|
|
|
839
1062
|
# Acknowledges a delivery (message).
|
|
@@ -952,7 +1175,7 @@ module Bunny
|
|
|
952
1175
|
# Registers a consumer for queue. Delivered messages will be handled with the block
|
|
953
1176
|
# provided to this method.
|
|
954
1177
|
#
|
|
955
|
-
# @param [String
|
|
1178
|
+
# @param [String] queue Queue to consume from
|
|
956
1179
|
# @param [String] consumer_tag Consumer tag (unique identifier), generated by Bunny by default
|
|
957
1180
|
# @param [Boolean] no_ack (false) If true, delivered messages will be automatically acknowledged.
|
|
958
1181
|
# If false, manual acknowledgements will be necessary.
|
|
@@ -975,7 +1198,7 @@ module Bunny
|
|
|
975
1198
|
# helps avoid race condition between basic.consume-ok and basic.deliver if there are messages
|
|
976
1199
|
# in the queue already. MK.
|
|
977
1200
|
if consumer_tag && consumer_tag.strip != AMQ::Protocol::EMPTY_STRING
|
|
978
|
-
add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1201
|
+
add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments || {}, &block)
|
|
979
1202
|
end
|
|
980
1203
|
|
|
981
1204
|
@connection.send_frame(AMQ::Protocol::Basic::Consume.encode(@id,
|
|
@@ -995,6 +1218,8 @@ module Bunny
|
|
|
995
1218
|
# if basic.consume-ok never arrives, unregister the proactively
|
|
996
1219
|
# registered consumer. MK.
|
|
997
1220
|
unregister_consumer(@last_basic_consume_ok.consumer_tag)
|
|
1221
|
+
# #add_consumer records a consumer, make sure to undo it here. MK.
|
|
1222
|
+
delete_recorded_consumer(@last_basic_consume_ok.consumer_tag)
|
|
998
1223
|
|
|
999
1224
|
raise e
|
|
1000
1225
|
end
|
|
@@ -1004,7 +1229,7 @@ module Bunny
|
|
|
1004
1229
|
raise_if_channel_close!(@last_basic_consume_ok)
|
|
1005
1230
|
|
|
1006
1231
|
# covers server-generated consumer tags
|
|
1007
|
-
add_consumer(queue_name, @last_basic_consume_ok.consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1232
|
+
add_consumer(queue_name, @last_basic_consume_ok.consumer_tag, no_ack, exclusive, arguments || {}, &block)
|
|
1008
1233
|
|
|
1009
1234
|
@last_basic_consume_ok
|
|
1010
1235
|
end
|
|
@@ -1055,6 +1280,12 @@ module Bunny
|
|
|
1055
1280
|
|
|
1056
1281
|
# covers server-generated consumer tags
|
|
1057
1282
|
register_consumer(@last_basic_consume_ok.consumer_tag, consumer)
|
|
1283
|
+
record_consumer_with(self, @last_basic_consume_ok.consumer_tag,
|
|
1284
|
+
consumer.queue_name,
|
|
1285
|
+
consumer,
|
|
1286
|
+
consumer.manual_acknowledgement?,
|
|
1287
|
+
consumer.exclusive,
|
|
1288
|
+
consumer.arguments)
|
|
1058
1289
|
|
|
1059
1290
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1060
1291
|
|
|
@@ -1066,12 +1297,12 @@ module Bunny
|
|
|
1066
1297
|
# it was on is auto-deleted and this consumer was the last one, the queue will be deleted.
|
|
1067
1298
|
#
|
|
1068
1299
|
# @param [String] consumer_tag Consumer tag (unique identifier) to cancel
|
|
1069
|
-
# @param [Hash]
|
|
1300
|
+
# @param [Hash] opts ({}) Optional arguments
|
|
1070
1301
|
#
|
|
1071
1302
|
# @option opts [Boolean] :no_wait (false) if set to true, this method won't receive a response and will
|
|
1072
1303
|
# immediately return nil
|
|
1073
1304
|
#
|
|
1074
|
-
# @return [AMQ::Protocol::Basic::CancelOk] RabbitMQ response or nil, if the no_wait option is used
|
|
1305
|
+
# @return [AMQ::Protocol::Basic::CancelOk, nil] RabbitMQ response or nil, if the no_wait option is used
|
|
1075
1306
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
1076
1307
|
# @api public
|
|
1077
1308
|
def basic_cancel(consumer_tag, opts = {})
|
|
@@ -1089,6 +1320,7 @@ module Bunny
|
|
|
1089
1320
|
# reduces thread usage for channels that don't have any
|
|
1090
1321
|
# consumers
|
|
1091
1322
|
@work_pool.shutdown(true) unless self.any_consumers?
|
|
1323
|
+
self.delete_recorded_consumer(consumer_tag)
|
|
1092
1324
|
|
|
1093
1325
|
@last_basic_cancel_ok
|
|
1094
1326
|
end
|
|
@@ -1123,6 +1355,26 @@ module Bunny
|
|
|
1123
1355
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
1124
1356
|
# @api public
|
|
1125
1357
|
def queue_declare(name, opts = {})
|
|
1358
|
+
# strip trailing new line and carriage returns
|
|
1359
|
+
# just like RabbitMQ does
|
|
1360
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
|
1361
|
+
is_server_named = (safe_name == AMQ::Protocol::EMPTY_STRING)
|
|
1362
|
+
passive = opts.fetch(:passive, false)
|
|
1363
|
+
durable = opts.fetch(:durable, false)
|
|
1364
|
+
exclusive = opts.fetch(:exclusive, false)
|
|
1365
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1366
|
+
args = opts[:arguments]
|
|
1367
|
+
|
|
1368
|
+
result = self.queue_declare_without_recording_topology(name, opts)
|
|
1369
|
+
self.record_queue_with(self, result.queue, is_server_named, durable, exclusive, auto_delete, args) unless passive
|
|
1370
|
+
|
|
1371
|
+
result
|
|
1372
|
+
end
|
|
1373
|
+
|
|
1374
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1375
|
+
# as we iterate over them during topology recovery.
|
|
1376
|
+
# @private
|
|
1377
|
+
def queue_declare_without_recording_topology(name, opts = {})
|
|
1126
1378
|
raise_if_no_longer_open!
|
|
1127
1379
|
|
|
1128
1380
|
Bunny::Queue.verify_type!(opts[:arguments]) if opts[:arguments]
|
|
@@ -1130,16 +1382,24 @@ module Bunny
|
|
|
1130
1382
|
# strip trailing new line and carriage returns
|
|
1131
1383
|
# just like RabbitMQ does
|
|
1132
1384
|
safe_name = name.gsub(/[\r\n]/, "")
|
|
1385
|
+
is_server_named = (safe_name == AMQ::Protocol::EMPTY_STRING)
|
|
1133
1386
|
@pending_queue_declare_name = safe_name
|
|
1387
|
+
|
|
1388
|
+
passive = opts.fetch(:passive, false)
|
|
1389
|
+
durable = opts.fetch(:durable, false)
|
|
1390
|
+
exclusive = opts.fetch(:exclusive, false)
|
|
1391
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1392
|
+
args = opts[:arguments]
|
|
1393
|
+
|
|
1134
1394
|
@connection.send_frame(
|
|
1135
1395
|
AMQ::Protocol::Queue::Declare.encode(@id,
|
|
1136
1396
|
@pending_queue_declare_name,
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1397
|
+
passive,
|
|
1398
|
+
durable,
|
|
1399
|
+
exclusive,
|
|
1400
|
+
auto_delete,
|
|
1141
1401
|
false,
|
|
1142
|
-
|
|
1402
|
+
args))
|
|
1143
1403
|
|
|
1144
1404
|
begin
|
|
1145
1405
|
with_continuation_timeout do
|
|
@@ -1177,6 +1437,8 @@ module Bunny
|
|
|
1177
1437
|
@last_queue_delete_ok = wait_on_continuations
|
|
1178
1438
|
end
|
|
1179
1439
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1440
|
+
self.delete_recorded_queue_named(name)
|
|
1441
|
+
self.deregister_queue_named(name)
|
|
1180
1442
|
|
|
1181
1443
|
@last_queue_delete_ok
|
|
1182
1444
|
end
|
|
@@ -1217,23 +1479,48 @@ module Bunny
|
|
|
1217
1479
|
def queue_bind(name, exchange, opts = {})
|
|
1218
1480
|
raise_if_no_longer_open!
|
|
1219
1481
|
|
|
1482
|
+
exchange_name = if exchange.respond_to?(:name)
|
|
1483
|
+
exchange.name
|
|
1484
|
+
else
|
|
1485
|
+
exchange
|
|
1486
|
+
end
|
|
1487
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1488
|
+
args = opts[:arguments]
|
|
1489
|
+
|
|
1490
|
+
result = self.queue_bind_without_recording_topology(name, exchange, opts)
|
|
1491
|
+
self.record_queue_binding_with(self, exchange_name, name, rk, args)
|
|
1492
|
+
|
|
1493
|
+
result
|
|
1494
|
+
end
|
|
1495
|
+
|
|
1496
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1497
|
+
# as we iterate over them during topology recovery.
|
|
1498
|
+
# @private
|
|
1499
|
+
def queue_bind_without_recording_topology(name, exchange, opts = {})
|
|
1500
|
+
raise_if_no_longer_open!
|
|
1501
|
+
|
|
1220
1502
|
exchange_name = if exchange.respond_to?(:name)
|
|
1221
1503
|
exchange.name
|
|
1222
1504
|
else
|
|
1223
1505
|
exchange
|
|
1224
1506
|
end
|
|
1225
1507
|
|
|
1508
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1509
|
+
args = opts[:arguments]
|
|
1226
1510
|
@connection.send_frame(AMQ::Protocol::Queue::Bind.encode(@id,
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1511
|
+
name,
|
|
1512
|
+
exchange_name,
|
|
1513
|
+
rk,
|
|
1514
|
+
false,
|
|
1515
|
+
args))
|
|
1516
|
+
|
|
1232
1517
|
with_continuation_timeout do
|
|
1233
1518
|
@last_queue_bind_ok = wait_on_continuations
|
|
1234
1519
|
end
|
|
1235
1520
|
|
|
1236
1521
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1522
|
+
|
|
1523
|
+
|
|
1237
1524
|
@last_queue_bind_ok
|
|
1238
1525
|
end
|
|
1239
1526
|
|
|
@@ -1259,16 +1546,20 @@ module Bunny
|
|
|
1259
1546
|
exchange
|
|
1260
1547
|
end
|
|
1261
1548
|
|
|
1549
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1550
|
+
args = opts[:arguments]
|
|
1262
1551
|
@connection.send_frame(AMQ::Protocol::Queue::Unbind.encode(@id,
|
|
1263
1552
|
name,
|
|
1264
1553
|
exchange_name,
|
|
1265
|
-
|
|
1266
|
-
|
|
1554
|
+
rk,
|
|
1555
|
+
args))
|
|
1267
1556
|
with_continuation_timeout do
|
|
1268
1557
|
@last_queue_unbind_ok = wait_on_continuations
|
|
1269
1558
|
end
|
|
1270
1559
|
|
|
1271
1560
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1561
|
+
self.delete_recorded_queue_binding(self, exchange_name, name, rk, args)
|
|
1562
|
+
|
|
1272
1563
|
@last_queue_unbind_ok
|
|
1273
1564
|
end
|
|
1274
1565
|
|
|
@@ -1294,25 +1585,65 @@ module Bunny
|
|
|
1294
1585
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
|
1295
1586
|
# @api public
|
|
1296
1587
|
def exchange_declare(name, type, opts = {})
|
|
1588
|
+
result = self.exchange_declare_without_recording_topology(name, type, opts)
|
|
1589
|
+
|
|
1590
|
+
# strip trailing new line and carriage returns
|
|
1591
|
+
# just like RabbitMQ does
|
|
1592
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
|
1593
|
+
passive = opts.fetch(:passive, false)
|
|
1594
|
+
durable = opts.fetch(:durable, false)
|
|
1595
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1596
|
+
args = opts[:arguments]
|
|
1597
|
+
self.record_exchange_with(self,
|
|
1598
|
+
safe_name,
|
|
1599
|
+
type.to_s,
|
|
1600
|
+
durable,
|
|
1601
|
+
auto_delete,
|
|
1602
|
+
args) unless passive
|
|
1603
|
+
|
|
1604
|
+
result
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1608
|
+
# as we iterate over them during topology recovery.
|
|
1609
|
+
#
|
|
1610
|
+
# @param [String] name The name of the exchange. Note that LF and CR characters
|
|
1611
|
+
# will be stripped from the value.
|
|
1612
|
+
# @param [String,Symbol] type Exchange type, e.g. :fanout or :topic
|
|
1613
|
+
# @param [Hash] opts Exchange properties
|
|
1614
|
+
#
|
|
1615
|
+
# @option opts [Boolean] durable (false) Should information about this exchange be persisted to disk so that it
|
|
1616
|
+
# can survive broker restarts? Typically set to true for long-lived exchanges.
|
|
1617
|
+
# @option opts [Boolean] auto_delete (false) Should this exchange be deleted when it is no longer used?
|
|
1618
|
+
# @option opts [Boolean] passive (false) If true, exchange will be checked for existence. If it does not
|
|
1619
|
+
# exist, {Bunny::NotFound} will be raised.
|
|
1620
|
+
# @private
|
|
1621
|
+
def exchange_declare_without_recording_topology(name, type, opts = {})
|
|
1297
1622
|
raise_if_no_longer_open!
|
|
1298
1623
|
|
|
1299
1624
|
# strip trailing new line and carriage returns
|
|
1300
1625
|
# just like RabbitMQ does
|
|
1301
1626
|
safe_name = name.gsub(/[\r\n]/, "")
|
|
1627
|
+
passive = opts.fetch(:passive, false)
|
|
1628
|
+
durable = opts.fetch(:durable, false)
|
|
1629
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1630
|
+
args = opts[:arguments]
|
|
1631
|
+
|
|
1302
1632
|
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@id,
|
|
1303
1633
|
safe_name,
|
|
1304
1634
|
type.to_s,
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1635
|
+
passive,
|
|
1636
|
+
durable,
|
|
1637
|
+
auto_delete,
|
|
1308
1638
|
opts.fetch(:internal, false),
|
|
1309
1639
|
opts.fetch(:no_wait, false),
|
|
1310
|
-
|
|
1640
|
+
args))
|
|
1311
1641
|
with_continuation_timeout do
|
|
1312
1642
|
@last_exchange_declare_ok = wait_on_continuations
|
|
1313
1643
|
end
|
|
1314
1644
|
|
|
1315
1645
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1646
|
+
|
|
1316
1647
|
@last_exchange_declare_ok
|
|
1317
1648
|
end
|
|
1318
1649
|
|
|
@@ -1338,6 +1669,9 @@ module Bunny
|
|
|
1338
1669
|
end
|
|
1339
1670
|
|
|
1340
1671
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1672
|
+
self.delete_recorded_exchange_named(name)
|
|
1673
|
+
self.deregister_exchange_named(name)
|
|
1674
|
+
|
|
1341
1675
|
@last_exchange_delete_ok
|
|
1342
1676
|
end
|
|
1343
1677
|
|
|
@@ -1357,6 +1691,29 @@ module Bunny
|
|
|
1357
1691
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
|
1358
1692
|
# @api public
|
|
1359
1693
|
def exchange_bind(source, destination, opts = {})
|
|
1694
|
+
result = self.exchange_bind_without_recording_topology(source, destination, opts)
|
|
1695
|
+
|
|
1696
|
+
source_name = if source.respond_to?(:name)
|
|
1697
|
+
source.name
|
|
1698
|
+
else
|
|
1699
|
+
source
|
|
1700
|
+
end
|
|
1701
|
+
destination_name = if destination.respond_to?(:name)
|
|
1702
|
+
destination.name
|
|
1703
|
+
else
|
|
1704
|
+
destination
|
|
1705
|
+
end
|
|
1706
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1707
|
+
args = opts[:arguments]
|
|
1708
|
+
self.record_exchange_binding_with(self, source_name, destination_name, rk, args)
|
|
1709
|
+
|
|
1710
|
+
result
|
|
1711
|
+
end
|
|
1712
|
+
|
|
1713
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1714
|
+
# as we iterate over them during topology recovery.
|
|
1715
|
+
# @private
|
|
1716
|
+
def exchange_bind_without_recording_topology(source, destination, opts = {})
|
|
1360
1717
|
raise_if_no_longer_open!
|
|
1361
1718
|
|
|
1362
1719
|
source_name = if source.respond_to?(:name)
|
|
@@ -1371,17 +1728,21 @@ module Bunny
|
|
|
1371
1728
|
destination
|
|
1372
1729
|
end
|
|
1373
1730
|
|
|
1731
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1732
|
+
args = opts[:arguments]
|
|
1374
1733
|
@connection.send_frame(AMQ::Protocol::Exchange::Bind.encode(@id,
|
|
1375
1734
|
destination_name,
|
|
1376
1735
|
source_name,
|
|
1377
|
-
|
|
1736
|
+
rk,
|
|
1378
1737
|
false,
|
|
1379
|
-
|
|
1738
|
+
args))
|
|
1380
1739
|
with_continuation_timeout do
|
|
1381
1740
|
@last_exchange_bind_ok = wait_on_continuations
|
|
1382
1741
|
end
|
|
1383
1742
|
|
|
1384
1743
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1744
|
+
self.record_exchange_binding_with(self, source_name, destination_name, rk, args)
|
|
1745
|
+
|
|
1385
1746
|
@last_exchange_bind_ok
|
|
1386
1747
|
end
|
|
1387
1748
|
|
|
@@ -1415,17 +1776,21 @@ module Bunny
|
|
|
1415
1776
|
destination
|
|
1416
1777
|
end
|
|
1417
1778
|
|
|
1779
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1780
|
+
args = opts[:arguments]
|
|
1418
1781
|
@connection.send_frame(AMQ::Protocol::Exchange::Unbind.encode(@id,
|
|
1419
1782
|
destination_name,
|
|
1420
1783
|
source_name,
|
|
1421
|
-
|
|
1784
|
+
rk,
|
|
1422
1785
|
false,
|
|
1423
|
-
|
|
1786
|
+
args))
|
|
1424
1787
|
with_continuation_timeout do
|
|
1425
1788
|
@last_exchange_unbind_ok = wait_on_continuations
|
|
1426
1789
|
end
|
|
1427
1790
|
|
|
1428
1791
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1792
|
+
self.delete_recorded_exchange_binding(self, source_name, destination_name, rk, args)
|
|
1793
|
+
|
|
1429
1794
|
@last_exchange_unbind_ok
|
|
1430
1795
|
end
|
|
1431
1796
|
|
|
@@ -1528,14 +1893,25 @@ module Bunny
|
|
|
1528
1893
|
alias using_publisher_confirms? using_publisher_confirmations?
|
|
1529
1894
|
|
|
1530
1895
|
# Enables publisher confirms for the channel.
|
|
1896
|
+
#
|
|
1897
|
+
# @param [Proc] callback Optional callback invoked for each confirm. Receives (delivery_tag, multiple, nack).
|
|
1898
|
+
# @param [Boolean] tracking When true, basic_publish blocks until the broker confirms receipt.
|
|
1899
|
+
# Raises Bunny::MessageNacked if the message is nacked.
|
|
1900
|
+
# @param [Integer] outstanding_limit Max unconfirmed messages before basic_publish blocks.
|
|
1901
|
+
# Defaults to 1000 when tracking: true (optimal for throughput). Pass explicit value to override.
|
|
1902
|
+
# @param [Integer] confirm_timeout Timeout in ms for confirms. Defaults to connection's continuation_timeout.
|
|
1903
|
+
#
|
|
1531
1904
|
# @return [AMQ::Protocol::Confirm::SelectOk] RabbitMQ response
|
|
1532
1905
|
# @see #wait_for_confirms
|
|
1533
1906
|
# @see #unconfirmed_set
|
|
1534
1907
|
# @see #nacked_set
|
|
1535
1908
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
|
1536
1909
|
# @api public
|
|
1537
|
-
def confirm_select(callback = nil)
|
|
1910
|
+
def confirm_select(callback = nil, tracking: false, outstanding_limit: nil, confirm_timeout: nil)
|
|
1538
1911
|
raise_if_no_longer_open!
|
|
1912
|
+
raise ArgumentError, "outstanding_limit requires tracking: true" if outstanding_limit && !tracking
|
|
1913
|
+
raise ArgumentError, "outstanding_limit must be positive" if outstanding_limit && outstanding_limit < 1
|
|
1914
|
+
raise ArgumentError, "confirm_timeout must be positive" if confirm_timeout && confirm_timeout < 1
|
|
1539
1915
|
|
|
1540
1916
|
if @next_publish_seq_no == 0
|
|
1541
1917
|
@confirms_continuations = new_continuation
|
|
@@ -1546,6 +1922,17 @@ module Bunny
|
|
|
1546
1922
|
end
|
|
1547
1923
|
|
|
1548
1924
|
@confirms_callback = callback
|
|
1925
|
+
@confirms_tracking_enabled = tracking
|
|
1926
|
+
# Default to optimal limit when tracking enabled (avoids per-message mutex)
|
|
1927
|
+
@outstanding_limit = outstanding_limit || (tracking ? DEFAULT_OUTSTANDING_CONFIRMS_LIMIT : nil)
|
|
1928
|
+
@confirm_timeout = confirm_timeout
|
|
1929
|
+
|
|
1930
|
+
# Cache combined check for fast path in basic_publish
|
|
1931
|
+
@throttle_publishes = tracking && @outstanding_limit
|
|
1932
|
+
|
|
1933
|
+
if @outstanding_limit && !@outstanding_limit_cond
|
|
1934
|
+
@outstanding_limit_cond = @unconfirmed_set_mutex.new_cond
|
|
1935
|
+
end
|
|
1549
1936
|
|
|
1550
1937
|
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
|
1551
1938
|
with_continuation_timeout do
|
|
@@ -1585,9 +1972,9 @@ module Bunny
|
|
|
1585
1972
|
#
|
|
1586
1973
|
# @return [String] Unique string.
|
|
1587
1974
|
# @api plugin
|
|
1588
|
-
def generate_consumer_tag(
|
|
1975
|
+
def generate_consumer_tag(prefix = "bunny")
|
|
1589
1976
|
t = Bunny::Timestamp.now
|
|
1590
|
-
"#{
|
|
1977
|
+
"#{prefix}-#{t.to_i * 1000}-#{Kernel.rand(999_999_999_999)}"
|
|
1591
1978
|
end
|
|
1592
1979
|
|
|
1593
1980
|
# @endgroup
|
|
@@ -1630,11 +2017,8 @@ module Bunny
|
|
|
1630
2017
|
recover_prefetch_setting
|
|
1631
2018
|
recover_confirm_mode
|
|
1632
2019
|
recover_tx_mode
|
|
1633
|
-
|
|
1634
|
-
#
|
|
1635
|
-
recover_queues
|
|
1636
|
-
recover_consumers
|
|
1637
|
-
increment_recoveries_counter
|
|
2020
|
+
|
|
2021
|
+
# Topology is now recovered by [Bunny::Session] via the data in [Bunny::TopologyRegistry].
|
|
1638
2022
|
end
|
|
1639
2023
|
|
|
1640
2024
|
# Recovers basic.qos setting. Used by the Automatic Network Failure
|
|
@@ -1651,13 +2035,26 @@ module Bunny
|
|
|
1651
2035
|
#
|
|
1652
2036
|
# @api plugin
|
|
1653
2037
|
def recover_confirm_mode
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2038
|
+
return unless using_publisher_confirmations?
|
|
2039
|
+
|
|
2040
|
+
@unconfirmed_set_mutex.synchronize do
|
|
2041
|
+
@unconfirmed_set.clear
|
|
2042
|
+
@delivery_tag_offset = @next_publish_seq_no - 1
|
|
2043
|
+
|
|
2044
|
+
if @confirms_tracking_enabled
|
|
2045
|
+
@per_message_continuations_mutex.synchronize do
|
|
2046
|
+
@per_message_continuations.each_value { |c| c.push(:network_error) }
|
|
2047
|
+
@per_message_continuations.clear
|
|
2048
|
+
end
|
|
1658
2049
|
end
|
|
1659
|
-
|
|
2050
|
+
|
|
2051
|
+
@outstanding_limit_cond&.broadcast
|
|
1660
2052
|
end
|
|
2053
|
+
|
|
2054
|
+
confirm_select(@confirms_callback,
|
|
2055
|
+
tracking: @confirms_tracking_enabled,
|
|
2056
|
+
outstanding_limit: @outstanding_limit,
|
|
2057
|
+
confirm_timeout: @confirm_timeout)
|
|
1661
2058
|
end
|
|
1662
2059
|
|
|
1663
2060
|
# Recovers transaction mode. Used by the Automatic Network Failure
|
|
@@ -1668,45 +2065,31 @@ module Bunny
|
|
|
1668
2065
|
tx_select if @tx_mode
|
|
1669
2066
|
end
|
|
1670
2067
|
|
|
1671
|
-
#
|
|
2068
|
+
# Used by the Automatic Network Failure
|
|
1672
2069
|
# Recovery feature.
|
|
1673
2070
|
#
|
|
1674
|
-
# @
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
2071
|
+
# @param [String] old_name
|
|
2072
|
+
# @param [String] new_name
|
|
2073
|
+
# @private
|
|
2074
|
+
def record_queue_name_change(old_name, new_name)
|
|
2075
|
+
@queue_mutex.synchronize do
|
|
2076
|
+
if (orig = @queues[old_name])
|
|
2077
|
+
@queues.delete(old_name)
|
|
1680
2078
|
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
# @api plugin
|
|
1685
|
-
def recover_queues
|
|
1686
|
-
@queue_mutex.synchronize { @queues.values }.each do |q|
|
|
1687
|
-
@logger.debug { "Recovering queue #{q.name}" }
|
|
1688
|
-
q.recover_from_network_failure
|
|
2079
|
+
orig.update_name_to(new_name)
|
|
2080
|
+
@queues[new_name] = orig.dup
|
|
2081
|
+
end
|
|
1689
2082
|
end
|
|
1690
2083
|
end
|
|
1691
2084
|
|
|
1692
|
-
#
|
|
1693
|
-
# Recovery feature.
|
|
2085
|
+
# Used by the Automatic Network Failure Recovery feature.
|
|
1694
2086
|
#
|
|
1695
|
-
# @api
|
|
1696
|
-
def
|
|
2087
|
+
# @api private
|
|
2088
|
+
def maybe_reinitialize_consumer_pool!
|
|
1697
2089
|
unless @consumers.empty?
|
|
1698
2090
|
@work_pool = ConsumerWorkPool.new(@work_pool.size, @work_pool.abort_on_exception)
|
|
1699
2091
|
@work_pool.start
|
|
1700
2092
|
end
|
|
1701
|
-
|
|
1702
|
-
@consumer_mutex.synchronize { @consumers.values }.each do |c|
|
|
1703
|
-
c.recover_from_network_failure
|
|
1704
|
-
end
|
|
1705
|
-
end
|
|
1706
|
-
|
|
1707
|
-
# @private
|
|
1708
|
-
def increment_recoveries_counter
|
|
1709
|
-
@recoveries_counter.increment
|
|
1710
2093
|
end
|
|
1711
2094
|
|
|
1712
2095
|
# @api public
|
|
@@ -1745,6 +2128,9 @@ module Bunny
|
|
|
1745
2128
|
def register_consumer(consumer_tag, consumer)
|
|
1746
2129
|
@consumer_mutex.synchronize do
|
|
1747
2130
|
@consumers[consumer_tag] = consumer
|
|
2131
|
+
if @last_consumer_tag == consumer_tag
|
|
2132
|
+
@last_consumer = consumer
|
|
2133
|
+
end
|
|
1748
2134
|
end
|
|
1749
2135
|
end
|
|
1750
2136
|
|
|
@@ -1752,16 +2138,35 @@ module Bunny
|
|
|
1752
2138
|
def unregister_consumer(consumer_tag)
|
|
1753
2139
|
@consumer_mutex.synchronize do
|
|
1754
2140
|
@consumers.delete(consumer_tag)
|
|
2141
|
+
if @last_consumer_tag == consumer_tag
|
|
2142
|
+
@last_consumer_tag = nil
|
|
2143
|
+
@last_consumer = nil
|
|
2144
|
+
end
|
|
1755
2145
|
end
|
|
1756
2146
|
end
|
|
1757
2147
|
|
|
2148
|
+
# @param [String] queue_name
|
|
2149
|
+
# @param [String] consumer_tag
|
|
2150
|
+
# @param [Boolean] no_ack true means automative acknowledgement mode
|
|
2151
|
+
# @param [Boolean] exclusive
|
|
2152
|
+
# @param [Hash] arguments
|
|
1758
2153
|
# @private
|
|
1759
|
-
def add_consumer(
|
|
2154
|
+
def add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1760
2155
|
@consumer_mutex.synchronize do
|
|
1761
|
-
c = Consumer.new(self,
|
|
2156
|
+
c = Consumer.new(self, queue_name, consumer_tag, no_ack, exclusive, arguments)
|
|
1762
2157
|
c.on_delivery(&block) if block
|
|
1763
2158
|
@consumers[consumer_tag] = c
|
|
2159
|
+
if @last_consumer_tag == consumer_tag
|
|
2160
|
+
@last_consumer = c
|
|
2161
|
+
end
|
|
2162
|
+
c
|
|
1764
2163
|
end
|
|
2164
|
+
record_consumer_with(self, consumer_tag,
|
|
2165
|
+
queue_name,
|
|
2166
|
+
block,
|
|
2167
|
+
!no_ack,
|
|
2168
|
+
exclusive,
|
|
2169
|
+
arguments)
|
|
1765
2170
|
end
|
|
1766
2171
|
|
|
1767
2172
|
# @private
|
|
@@ -1826,6 +2231,10 @@ module Bunny
|
|
|
1826
2231
|
consume_with(consumer)
|
|
1827
2232
|
else
|
|
1828
2233
|
@consumers.delete(method.consumer_tag)
|
|
2234
|
+
if @last_consumer_tag == method.consumer_tag
|
|
2235
|
+
@last_consumer_tag = nil
|
|
2236
|
+
@last_consumer = nil
|
|
2237
|
+
end
|
|
1829
2238
|
consumer.handle_cancellation(method)
|
|
1830
2239
|
end
|
|
1831
2240
|
rescue Exception => e
|
|
@@ -1839,6 +2248,7 @@ module Bunny
|
|
|
1839
2248
|
when AMQ::Protocol::Basic::CancelOk then
|
|
1840
2249
|
@continuations.push(method)
|
|
1841
2250
|
unregister_consumer(method.consumer_tag)
|
|
2251
|
+
delete_recorded_consumer(method.consumer_tag)
|
|
1842
2252
|
when AMQ::Protocol::Tx::SelectOk, AMQ::Protocol::Tx::CommitOk, AMQ::Protocol::Tx::RollbackOk then
|
|
1843
2253
|
@continuations.push(method)
|
|
1844
2254
|
when AMQ::Protocol::Tx::SelectOk then
|
|
@@ -1855,7 +2265,9 @@ module Bunny
|
|
|
1855
2265
|
|
|
1856
2266
|
# basic.ack, basic.reject, basic.nack. MK.
|
|
1857
2267
|
if channel_level_exception_after_operation_that_has_no_response?(method)
|
|
1858
|
-
|
|
2268
|
+
# Runs outside the reader loop so that the callback can perform
|
|
2269
|
+
# blocking operations such as channel.reopen.
|
|
2270
|
+
Thread.new { @on_error.call(self, method) } if @on_error
|
|
1859
2271
|
else
|
|
1860
2272
|
@last_channel_error = instantiate_channel_level_exception(method)
|
|
1861
2273
|
@continuations.push(method)
|
|
@@ -1870,12 +2282,12 @@ module Bunny
|
|
|
1870
2282
|
|
|
1871
2283
|
# @private
|
|
1872
2284
|
def channel_level_exception_after_operation_that_has_no_response?(method)
|
|
1873
|
-
method.
|
|
2285
|
+
method.unknown_delivery_tag? || method.delivery_ack_timeout? || method.message_too_large?
|
|
1874
2286
|
end
|
|
1875
2287
|
|
|
1876
2288
|
# @private
|
|
1877
2289
|
def handle_basic_get_ok(basic_get_ok, properties, content)
|
|
1878
|
-
basic_get_ok.delivery_tag =
|
|
2290
|
+
basic_get_ok.delivery_tag = basic_get_ok.delivery_tag
|
|
1879
2291
|
@basic_get_continuations.push([basic_get_ok, properties, content])
|
|
1880
2292
|
end
|
|
1881
2293
|
|
|
@@ -1886,20 +2298,33 @@ module Bunny
|
|
|
1886
2298
|
|
|
1887
2299
|
# @private
|
|
1888
2300
|
def handle_frameset(basic_deliver, properties, content)
|
|
1889
|
-
|
|
2301
|
+
tag = basic_deliver.consumer_tag
|
|
2302
|
+
if @last_consumer_tag == tag
|
|
2303
|
+
consumer = @last_consumer
|
|
2304
|
+
else
|
|
2305
|
+
consumer = @consumers[tag]
|
|
2306
|
+
@last_consumer_tag = tag
|
|
2307
|
+
@last_consumer = consumer
|
|
2308
|
+
end
|
|
2309
|
+
|
|
1890
2310
|
if consumer
|
|
1891
2311
|
@work_pool.submit do
|
|
1892
|
-
|
|
1893
|
-
consumer.call(DeliveryInfo.new(basic_deliver, consumer, self), MessageProperties.new(properties), content)
|
|
1894
|
-
rescue StandardError => e
|
|
1895
|
-
@uncaught_exception_handler.call(e, consumer) if @uncaught_exception_handler
|
|
1896
|
-
end
|
|
2312
|
+
deliver_to_consumer(consumer, basic_deliver, properties, content)
|
|
1897
2313
|
end
|
|
1898
2314
|
else
|
|
1899
2315
|
@logger.warn "No consumer for tag #{basic_deliver.consumer_tag} on channel #{@id}!"
|
|
1900
2316
|
end
|
|
1901
2317
|
end
|
|
1902
2318
|
|
|
2319
|
+
# @private
|
|
2320
|
+
def deliver_to_consumer(consumer, basic_deliver, properties, content)
|
|
2321
|
+
begin
|
|
2322
|
+
consumer.call(DeliveryInfo.new(basic_deliver, consumer, self), MessageProperties.new(properties), content)
|
|
2323
|
+
rescue StandardError => e
|
|
2324
|
+
@uncaught_exception_handler.call(e, consumer) if @uncaught_exception_handler
|
|
2325
|
+
end
|
|
2326
|
+
end
|
|
2327
|
+
|
|
1903
2328
|
# @private
|
|
1904
2329
|
def handle_basic_return(basic_return, properties, content)
|
|
1905
2330
|
x = find_exchange(basic_return.exchange)
|
|
@@ -1931,6 +2356,22 @@ module Bunny
|
|
|
1931
2356
|
|
|
1932
2357
|
@confirms_continuations.push(true) if @unconfirmed_set.empty?
|
|
1933
2358
|
|
|
2359
|
+
# Signal per-message continuations (only used when tracking without limit)
|
|
2360
|
+
if @confirms_tracking_enabled && !@throttle_publishes
|
|
2361
|
+
to_signal = []
|
|
2362
|
+
@per_message_continuations_mutex.synchronize do
|
|
2363
|
+
@per_message_continuations.each do |tag, cont|
|
|
2364
|
+
to_signal << cont if tag >= confirmed_range_start && tag <= confirmed_range_end
|
|
2365
|
+
end
|
|
2366
|
+
end
|
|
2367
|
+
result = nack ? :nack : :ack
|
|
2368
|
+
to_signal.each { |c| c.push(result) }
|
|
2369
|
+
end
|
|
2370
|
+
|
|
2371
|
+
# Wake publisher(s) waiting for outstanding limit slot
|
|
2372
|
+
# Use broadcast since "multiple" acks can free many slots at once
|
|
2373
|
+
@outstanding_limit_cond&.broadcast if @throttle_publishes
|
|
2374
|
+
|
|
1934
2375
|
if @confirms_callback
|
|
1935
2376
|
confirmed_range.each { |tag| @confirms_callback.call(tag, false, nack) }
|
|
1936
2377
|
end
|
|
@@ -2005,21 +2446,63 @@ module Bunny
|
|
|
2005
2446
|
end
|
|
2006
2447
|
end
|
|
2007
2448
|
|
|
2008
|
-
|
|
2009
|
-
#
|
|
2449
|
+
# Waits for a slot when outstanding limit is reached.
|
|
2450
|
+
# Assumes @unconfirmed_set_mutex is already held.
|
|
2010
2451
|
# @private
|
|
2011
|
-
def
|
|
2012
|
-
|
|
2013
|
-
|
|
2452
|
+
def wait_for_outstanding_slot_locked
|
|
2453
|
+
limit = @outstanding_limit
|
|
2454
|
+
return if @unconfirmed_set.size < limit
|
|
2455
|
+
|
|
2456
|
+
timeout_sec = (@confirm_timeout || @connection.continuation_timeout) / 1000.0
|
|
2457
|
+
deadline = Bunny::Timestamp.monotonic + timeout_sec
|
|
2458
|
+
|
|
2459
|
+
while @unconfirmed_set.size >= limit
|
|
2460
|
+
raise_if_no_longer_open!
|
|
2461
|
+
|
|
2462
|
+
remaining = deadline - Bunny::Timestamp.monotonic
|
|
2463
|
+
raise Timeout::Error, "Timed out waiting for publisher confirms (limit: #{limit})" if remaining <= 0
|
|
2464
|
+
|
|
2465
|
+
@outstanding_limit_cond.wait(remaining)
|
|
2014
2466
|
end
|
|
2015
|
-
|
|
2016
|
-
|
|
2467
|
+
end
|
|
2468
|
+
|
|
2469
|
+
# @private
|
|
2470
|
+
def wait_for_publish_confirm(seq_no, continuation)
|
|
2471
|
+
t = Thread.current
|
|
2472
|
+
@threads_waiting_on_confirms_continuations << t
|
|
2473
|
+
|
|
2474
|
+
begin
|
|
2475
|
+
timeout = @confirm_timeout || @connection.continuation_timeout
|
|
2476
|
+
case continuation.poll(timeout)
|
|
2477
|
+
when :ack, true
|
|
2478
|
+
# confirmed
|
|
2479
|
+
when :nack
|
|
2480
|
+
raise MessageNacked.new("Message #{seq_no} was nacked", seq_no)
|
|
2481
|
+
when :network_error
|
|
2482
|
+
raise NetworkFailure.new("Network failure waiting for confirm", nil)
|
|
2483
|
+
when nil
|
|
2484
|
+
raise Timeout::Error, "Timed out waiting for publisher confirm"
|
|
2485
|
+
end
|
|
2486
|
+
ensure
|
|
2487
|
+
@threads_waiting_on_confirms_continuations.delete(t)
|
|
2488
|
+
@per_message_continuations_mutex.synchronize do
|
|
2489
|
+
@per_message_continuations.delete(seq_no)
|
|
2490
|
+
end
|
|
2017
2491
|
end
|
|
2018
|
-
|
|
2019
|
-
|
|
2492
|
+
end
|
|
2493
|
+
|
|
2494
|
+
|
|
2495
|
+
# @private
|
|
2496
|
+
def release_all_continuations
|
|
2497
|
+
@threads_waiting_on_confirms_continuations.each(&:run)
|
|
2498
|
+
@threads_waiting_on_continuations.each(&:run)
|
|
2499
|
+
@threads_waiting_on_basic_get_continuations.each(&:run)
|
|
2500
|
+
|
|
2501
|
+
if @outstanding_limit_cond
|
|
2502
|
+
@unconfirmed_set_mutex.synchronize { @outstanding_limit_cond.broadcast }
|
|
2020
2503
|
end
|
|
2021
2504
|
|
|
2022
|
-
|
|
2505
|
+
reset_continuations
|
|
2023
2506
|
end
|
|
2024
2507
|
|
|
2025
2508
|
# Starts consumer work pool. Lazily called by #basic_consume to avoid creating new threads
|
|
@@ -2049,39 +2532,167 @@ module Bunny
|
|
|
2049
2532
|
@connection.read_next_frame(options = {})
|
|
2050
2533
|
end
|
|
2051
2534
|
|
|
2535
|
+
# @param [String] name
|
|
2536
|
+
# @private
|
|
2537
|
+
def find_queue(name)
|
|
2538
|
+
@queue_mutex.synchronize { @queues[name] }
|
|
2539
|
+
end
|
|
2540
|
+
|
|
2541
|
+
# @param [String] name
|
|
2542
|
+
# @private
|
|
2543
|
+
def find_exchange(name)
|
|
2544
|
+
@exchange_mutex.synchronize { @exchanges[name] }
|
|
2545
|
+
end
|
|
2546
|
+
|
|
2547
|
+
# @param [Bunny::Queue] queue
|
|
2548
|
+
# @private
|
|
2549
|
+
def register_queue(queue)
|
|
2550
|
+
@queue_mutex.synchronize { @queues[queue.name] = queue }
|
|
2551
|
+
end
|
|
2552
|
+
|
|
2553
|
+
# @param [Bunny::Queue] queue
|
|
2052
2554
|
# @private
|
|
2053
2555
|
def deregister_queue(queue)
|
|
2054
2556
|
@queue_mutex.synchronize { @queues.delete(queue.name) }
|
|
2055
2557
|
end
|
|
2056
2558
|
|
|
2559
|
+
# @param [Bunny::String] name
|
|
2057
2560
|
# @private
|
|
2058
2561
|
def deregister_queue_named(name)
|
|
2059
2562
|
@queue_mutex.synchronize { @queues.delete(name) }
|
|
2060
2563
|
end
|
|
2061
2564
|
|
|
2565
|
+
# @param [Bunny::Queue] queue
|
|
2062
2566
|
# @private
|
|
2063
|
-
def
|
|
2064
|
-
@
|
|
2567
|
+
def record_queue(queue)
|
|
2568
|
+
@connection.record_queue(queue)
|
|
2065
2569
|
end
|
|
2066
2570
|
|
|
2571
|
+
# @param [Bunny::Channel] ch
|
|
2572
|
+
# @param [String] name
|
|
2573
|
+
# @param [Boolean] server_named
|
|
2574
|
+
# @param [Boolean] durable
|
|
2575
|
+
# @param [Boolean] auto_delete
|
|
2576
|
+
# @param [Boolean] exclusive
|
|
2577
|
+
# @param [Hash] arguments
|
|
2578
|
+
def record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
|
|
2579
|
+
@connection.record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
|
|
2580
|
+
end
|
|
2581
|
+
|
|
2582
|
+
# @param [Bunny::Queue, Bunny::RecordedQueue] queue
|
|
2067
2583
|
# @private
|
|
2068
|
-
def
|
|
2069
|
-
@
|
|
2584
|
+
def delete_recoreded_queue(queue)
|
|
2585
|
+
@connection.delete_recorded_queue(queue)
|
|
2070
2586
|
end
|
|
2071
2587
|
|
|
2588
|
+
# @param [String] name
|
|
2072
2589
|
# @private
|
|
2073
|
-
def
|
|
2074
|
-
@
|
|
2590
|
+
def delete_recorded_queue_named(name)
|
|
2591
|
+
@connection.delete_recorded_queue_named(name)
|
|
2075
2592
|
end
|
|
2076
2593
|
|
|
2594
|
+
# @param [Bunny::Exchange] exchange
|
|
2077
2595
|
# @private
|
|
2078
2596
|
def register_exchange(exchange)
|
|
2079
2597
|
@exchange_mutex.synchronize { @exchanges[exchange.name] = exchange }
|
|
2080
2598
|
end
|
|
2081
2599
|
|
|
2600
|
+
# @param [Bunny::Exchange] exchange
|
|
2082
2601
|
# @private
|
|
2083
|
-
def
|
|
2084
|
-
@
|
|
2602
|
+
def deregister_exchange(exchange)
|
|
2603
|
+
@queue_mutex.synchronize { @exchanges.delete(exchange.name) }
|
|
2604
|
+
end
|
|
2605
|
+
|
|
2606
|
+
# @param [String] name
|
|
2607
|
+
# @private
|
|
2608
|
+
def deregister_exchange_named(name)
|
|
2609
|
+
@queue_mutex.synchronize { @exchanges.delete(name) }
|
|
2610
|
+
end
|
|
2611
|
+
|
|
2612
|
+
# @param [Bunny::Exchange] exchange
|
|
2613
|
+
# @private
|
|
2614
|
+
def record_exchange(exchange)
|
|
2615
|
+
@connection.record_exchange(exchange)
|
|
2616
|
+
end
|
|
2617
|
+
|
|
2618
|
+
# @param [Bunny::Channel] ch
|
|
2619
|
+
# @param [String] name
|
|
2620
|
+
# @param [String] type
|
|
2621
|
+
# @param [Boolean] durable
|
|
2622
|
+
# @param [Boolean] auto_delete
|
|
2623
|
+
# @param [Hash] arguments
|
|
2624
|
+
def record_exchange_with(ch, name, type, durable, auto_delete, arguments)
|
|
2625
|
+
@connection.record_exchange_with(ch, name, type, durable, auto_delete, arguments)
|
|
2626
|
+
end
|
|
2627
|
+
|
|
2628
|
+
# @param [Bunny::Exchange] exchange
|
|
2629
|
+
# @private
|
|
2630
|
+
def delete_recorded_exchange(exchange)
|
|
2631
|
+
@connection.delete_recorded_exchange(exchange)
|
|
2632
|
+
end
|
|
2633
|
+
|
|
2634
|
+
# @param [String] name
|
|
2635
|
+
# @private
|
|
2636
|
+
def delete_recorded_exchange_named(name)
|
|
2637
|
+
@connection.delete_recorded_exchange_named(name)
|
|
2638
|
+
end
|
|
2639
|
+
|
|
2640
|
+
# @param [Bunny::Channel] ch
|
|
2641
|
+
# @param [String] exchange_name
|
|
2642
|
+
# @param [String] queue_name
|
|
2643
|
+
# @param [String] routing_key
|
|
2644
|
+
# @param [Hash] arguments
|
|
2645
|
+
# @private
|
|
2646
|
+
def record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2647
|
+
@connection.record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2648
|
+
end
|
|
2649
|
+
|
|
2650
|
+
# @param [Bunny::Channel] ch
|
|
2651
|
+
# @param [String] exchange_name
|
|
2652
|
+
# @param [String] queue_name
|
|
2653
|
+
# @param [String] routing_key
|
|
2654
|
+
# @param [Hash] arguments
|
|
2655
|
+
# @private
|
|
2656
|
+
def delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2657
|
+
@connection.delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2658
|
+
end
|
|
2659
|
+
|
|
2660
|
+
# @param [Bunny::Channel] ch
|
|
2661
|
+
# @param [String] source_name
|
|
2662
|
+
# @param [String] destination_name
|
|
2663
|
+
# @param [String] routing_key
|
|
2664
|
+
# @param [Hash] arguments
|
|
2665
|
+
# @private
|
|
2666
|
+
def record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
|
|
2667
|
+
@connection.record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
|
|
2668
|
+
end
|
|
2669
|
+
|
|
2670
|
+
# @param [Bunny::Channel] ch
|
|
2671
|
+
# @param [String] source_name
|
|
2672
|
+
# @param [String] destination_name
|
|
2673
|
+
# @param [String] routing_key
|
|
2674
|
+
# @param [Hash] arguments
|
|
2675
|
+
# @private
|
|
2676
|
+
def delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
|
|
2677
|
+
@connection.delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
|
|
2678
|
+
end
|
|
2679
|
+
|
|
2680
|
+
# @param [Bunny::Channel] ch
|
|
2681
|
+
# @param [String] consumer_tag
|
|
2682
|
+
# @param [String] queue_name
|
|
2683
|
+
# @param [#call] callable
|
|
2684
|
+
# @param [Boolean] manual_ack
|
|
2685
|
+
# @param [Boolean] exclusive
|
|
2686
|
+
# @param [Hash] arguments
|
|
2687
|
+
# @private
|
|
2688
|
+
def record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
|
|
2689
|
+
@connection.record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
|
|
2690
|
+
end
|
|
2691
|
+
|
|
2692
|
+
# @param [String] consumer_tag
|
|
2693
|
+
# @private
|
|
2694
|
+
def delete_recorded_consumer(consumer_tag)
|
|
2695
|
+
@connection.delete_recorded_consumer(consumer_tag)
|
|
2085
2696
|
end
|
|
2086
2697
|
|
|
2087
2698
|
protected
|
|
@@ -2148,6 +2759,7 @@ module Bunny
|
|
|
2148
2759
|
@continuations = new_continuation
|
|
2149
2760
|
@confirms_continuations = new_continuation
|
|
2150
2761
|
@basic_get_continuations = new_continuation
|
|
2762
|
+
@per_message_continuations_mutex.synchronize { @per_message_continuations.clear }
|
|
2151
2763
|
end
|
|
2152
2764
|
|
|
2153
2765
|
# @private
|
|
@@ -2158,16 +2770,7 @@ module Bunny
|
|
|
2158
2770
|
# @private
|
|
2159
2771
|
def guarding_against_stale_delivery_tags(tag, &block)
|
|
2160
2772
|
case tag
|
|
2161
|
-
|
|
2162
|
-
when Integer then
|
|
2163
|
-
block.call
|
|
2164
|
-
# versioned delivery tags should be checked to avoid
|
|
2165
|
-
# sending out stale (invalid) tags after channel was reopened
|
|
2166
|
-
# during network failure recovery. MK.
|
|
2167
|
-
when VersionedDeliveryTag then
|
|
2168
|
-
if !tag.stale?(@recoveries_counter.get)
|
|
2169
|
-
block.call
|
|
2170
|
-
end
|
|
2773
|
+
when Integer then block.call
|
|
2171
2774
|
end
|
|
2172
2775
|
end
|
|
2173
2776
|
end # Channel
|