bunny 2.24.0 → 3.0.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 +12 -4
- data/lib/bunny/channel.rb +709 -123
- 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 +376 -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 +28 -6
- 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?
|
|
@@ -423,7 +474,7 @@ module Bunny
|
|
|
423
474
|
# @param [String] name Exchange name
|
|
424
475
|
# @param [Hash] opts Exchange parameters
|
|
425
476
|
#
|
|
426
|
-
# @option opts [String,Symbol] :type (:direct) Exchange type, e.g. :fanout or "x-consistent-hash"
|
|
477
|
+
# @option opts [String,Symbol] :type (:direct) Exchange type, e.g. :fanout or "x-consistent-hash" or "x-modulus-hash"
|
|
427
478
|
# @option opts [Boolean] :durable (false) Should the exchange be durable?
|
|
428
479
|
# @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
|
|
429
480
|
# @option opts [Hash] :arguments ({}) Optional exchange arguments
|
|
@@ -459,6 +510,7 @@ module Bunny
|
|
|
459
510
|
|
|
460
511
|
q = find_queue(name) || Bunny::Queue.new(self, name, opts)
|
|
461
512
|
|
|
513
|
+
record_queue(q)
|
|
462
514
|
register_queue(q)
|
|
463
515
|
end
|
|
464
516
|
|
|
@@ -502,6 +554,67 @@ module Bunny
|
|
|
502
554
|
durable_queue(name, Bunny::Queue::Types::STREAM, opts)
|
|
503
555
|
end
|
|
504
556
|
|
|
557
|
+
# Declares a Tanzu RabbitMQ delayed queue (a durable, replicated queue type).
|
|
558
|
+
# This queue type must be durable, non-exclusive, and non-auto-delete.
|
|
559
|
+
#
|
|
560
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
|
561
|
+
# @param [Hash] opts Queue properties
|
|
562
|
+
#
|
|
563
|
+
# @option opts [String] :delayed_retry_type ("all") Retry strategy: "all", "failed", or "returned"
|
|
564
|
+
# @option opts [Integer] :delayed_retry_min (nil) Minimum retry delay in milliseconds
|
|
565
|
+
# @option opts [Integer] :delayed_retry_max (nil) Maximum retry delay in milliseconds
|
|
566
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
|
567
|
+
#
|
|
568
|
+
# @return [Bunny::Queue] Queue that was declared
|
|
569
|
+
# @see #durable_queue
|
|
570
|
+
# @see #queue
|
|
571
|
+
# @api public
|
|
572
|
+
def delayed_queue(name, opts = {})
|
|
573
|
+
throw ArgumentError.new("delayed queue name must not be nil") if name.nil?
|
|
574
|
+
throw ArgumentError.new("delayed queue name must not be empty") if name.empty?
|
|
575
|
+
|
|
576
|
+
args = opts[:arguments] || {}
|
|
577
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_TYPE] = opts[:delayed_retry_type] if opts[:delayed_retry_type]
|
|
578
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_MIN] = opts[:delayed_retry_min] if opts[:delayed_retry_min]
|
|
579
|
+
args[Bunny::Queue::XArgs::DELAYED_RETRY_MAX] = opts[:delayed_retry_max] if opts[:delayed_retry_max]
|
|
580
|
+
|
|
581
|
+
final_opts = opts.merge(:arguments => args)
|
|
582
|
+
final_opts.delete(:delayed_retry_type)
|
|
583
|
+
final_opts.delete(:delayed_retry_min)
|
|
584
|
+
final_opts.delete(:delayed_retry_max)
|
|
585
|
+
|
|
586
|
+
durable_queue(name, Bunny::Queue::Types::DELAYED, final_opts)
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# Declares a Tanzu RabbitMQ JMS queue (a durable, replicated queue type).
|
|
590
|
+
# This queue type must be durable, non-exclusive, and non-auto-delete.
|
|
591
|
+
#
|
|
592
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
|
593
|
+
# @param [Hash] opts Queue properties
|
|
594
|
+
#
|
|
595
|
+
# @option opts [Array<String>] :selector_fields (nil) Fields available for JMS selector expressions (e.g. ["priority", "region"], or ["*"] for all)
|
|
596
|
+
# @option opts [Integer] :selector_field_max_bytes (nil) Maximum byte size per selector field
|
|
597
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
|
598
|
+
#
|
|
599
|
+
# @return [Bunny::Queue] Queue that was declared
|
|
600
|
+
# @see #durable_queue
|
|
601
|
+
# @see #queue
|
|
602
|
+
# @api public
|
|
603
|
+
def jms_queue(name, opts = {})
|
|
604
|
+
throw ArgumentError.new("JMS queue name must not be nil") if name.nil?
|
|
605
|
+
throw ArgumentError.new("JMS queue name must not be empty") if name.empty?
|
|
606
|
+
|
|
607
|
+
args = opts[:arguments] || {}
|
|
608
|
+
args[Bunny::Queue::XArgs::SELECTOR_FIELDS] = opts[:selector_fields] if opts[:selector_fields]
|
|
609
|
+
args[Bunny::Queue::XArgs::SELECTOR_FIELD_MAX_BYTES] = opts[:selector_field_max_bytes] if opts[:selector_field_max_bytes]
|
|
610
|
+
|
|
611
|
+
final_opts = opts.merge(:arguments => args)
|
|
612
|
+
final_opts.delete(:selector_fields)
|
|
613
|
+
final_opts.delete(:selector_field_max_bytes)
|
|
614
|
+
|
|
615
|
+
durable_queue(name, Bunny::Queue::Types::JMS, final_opts)
|
|
616
|
+
end
|
|
617
|
+
|
|
505
618
|
# Declares a new server-named queue that is automatically deleted when the
|
|
506
619
|
# connection is closed.
|
|
507
620
|
#
|
|
@@ -526,6 +639,7 @@ module Bunny
|
|
|
526
639
|
})
|
|
527
640
|
q = find_queue(name) || Bunny::Queue.new(self, name, final_opts)
|
|
528
641
|
|
|
642
|
+
record_queue(q)
|
|
529
643
|
register_queue(q)
|
|
530
644
|
end
|
|
531
645
|
|
|
@@ -660,10 +774,25 @@ module Bunny
|
|
|
660
774
|
opts[:content_type] ||= DEFAULT_CONTENT_TYPE
|
|
661
775
|
opts[:priority] ||= 0
|
|
662
776
|
|
|
777
|
+
seq_no = nil
|
|
778
|
+
continuation = nil
|
|
779
|
+
|
|
663
780
|
if @next_publish_seq_no > 0
|
|
664
781
|
@unconfirmed_set_mutex.synchronize do
|
|
665
|
-
|
|
782
|
+
# With outstanding_limit: wait for slot if at the limit
|
|
783
|
+
wait_for_outstanding_slot_locked if @throttle_publishes
|
|
784
|
+
|
|
785
|
+
seq_no = @next_publish_seq_no
|
|
786
|
+
@unconfirmed_set.add(seq_no)
|
|
666
787
|
@next_publish_seq_no += 1
|
|
788
|
+
|
|
789
|
+
# Only create per-message continuation when blocking individually (no limit)
|
|
790
|
+
if @confirms_tracking_enabled && !@throttle_publishes
|
|
791
|
+
continuation = new_continuation
|
|
792
|
+
@per_message_continuations_mutex.synchronize do
|
|
793
|
+
@per_message_continuations[seq_no] = continuation
|
|
794
|
+
end
|
|
795
|
+
end
|
|
667
796
|
end
|
|
668
797
|
end
|
|
669
798
|
|
|
@@ -674,9 +803,90 @@ module Bunny
|
|
|
674
803
|
routing_key,
|
|
675
804
|
opts[:mandatory],
|
|
676
805
|
false,
|
|
677
|
-
@
|
|
806
|
+
@frame_max)
|
|
678
807
|
@connection.send_frameset(frames, self)
|
|
679
808
|
|
|
809
|
+
wait_for_publish_confirm(seq_no, continuation) if continuation
|
|
810
|
+
|
|
811
|
+
self
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
# Publishes multiple messages in a batch with a single mutex acquisition.
|
|
815
|
+
# More efficient than calling basic_publish repeatedly when using publisher
|
|
816
|
+
# confirms with tracking. Recommended batch sizes: 500-3000.
|
|
817
|
+
#
|
|
818
|
+
# @param [Array<String>] payloads Array of message payloads to publish
|
|
819
|
+
# @param [String, Bunny::Exchange] exchange Exchange name or object
|
|
820
|
+
# @param [String] routing_key Routing key
|
|
821
|
+
# @param [Hash] opts Publishing options (applied to all messages)
|
|
822
|
+
# @return [self]
|
|
823
|
+
#
|
|
824
|
+
# @example Batch publishing with confirms
|
|
825
|
+
# ch.confirm_select(tracking: true)
|
|
826
|
+
# messages = 100.times.map { |i| "message #{i}" }
|
|
827
|
+
# ch.basic_publish_batch(messages, "", queue.name)
|
|
828
|
+
#
|
|
829
|
+
# @api public
|
|
830
|
+
def basic_publish_batch(payloads, exchange, routing_key, opts = {})
|
|
831
|
+
raise_if_no_longer_open!
|
|
832
|
+
raise ArgumentError, "payloads must be an Array" unless payloads.is_a?(Array)
|
|
833
|
+
raise ArgumentError, "routing key cannot be longer than #{SHORTSTR_LIMIT} characters" if routing_key && routing_key.size > SHORTSTR_LIMIT
|
|
834
|
+
return self if payloads.empty?
|
|
835
|
+
|
|
836
|
+
exchange_name = if exchange.respond_to?(:name)
|
|
837
|
+
exchange.name
|
|
838
|
+
else
|
|
839
|
+
exchange
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
mode = opts.fetch(:persistent, true) ? 2 : 1
|
|
843
|
+
opts = opts.dup
|
|
844
|
+
opts[:delivery_mode] ||= mode
|
|
845
|
+
opts[:content_type] ||= DEFAULT_CONTENT_TYPE
|
|
846
|
+
opts[:priority] ||= 0
|
|
847
|
+
|
|
848
|
+
batch_size = payloads.size
|
|
849
|
+
|
|
850
|
+
if @next_publish_seq_no > 0
|
|
851
|
+
@unconfirmed_set_mutex.synchronize do
|
|
852
|
+
# With throttling: wait until we have room for the batch
|
|
853
|
+
if @throttle_publishes
|
|
854
|
+
limit = @outstanding_limit
|
|
855
|
+
target = [limit - batch_size, 0].max
|
|
856
|
+
timeout_sec = (@confirm_timeout || @connection.continuation_timeout) / 1000.0
|
|
857
|
+
deadline = nil
|
|
858
|
+
|
|
859
|
+
while @unconfirmed_set.size > target
|
|
860
|
+
raise_if_no_longer_open!
|
|
861
|
+
deadline ||= Bunny::Timestamp.monotonic + timeout_sec
|
|
862
|
+
remaining = deadline - Bunny::Timestamp.monotonic
|
|
863
|
+
raise Timeout::Error, "Timed out waiting for publisher confirms (batch: #{batch_size}, limit: #{limit})" if remaining <= 0
|
|
864
|
+
@outstanding_limit_cond.wait(remaining)
|
|
865
|
+
end
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
# Register all sequence numbers at once
|
|
869
|
+
start_seq = @next_publish_seq_no
|
|
870
|
+
batch_size.times { |i| @unconfirmed_set.add(start_seq + i) }
|
|
871
|
+
@next_publish_seq_no = start_seq + batch_size
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
# Encode all messages into a single buffer and write once
|
|
876
|
+
data = +""
|
|
877
|
+
payloads.each do |payload|
|
|
878
|
+
frames = AMQ::Protocol::Basic::Publish.encode(@id,
|
|
879
|
+
payload,
|
|
880
|
+
opts,
|
|
881
|
+
exchange_name,
|
|
882
|
+
routing_key,
|
|
883
|
+
opts[:mandatory],
|
|
884
|
+
false,
|
|
885
|
+
@frame_max)
|
|
886
|
+
frames.each { |frame| data << frame.encode }
|
|
887
|
+
end
|
|
888
|
+
@connection.send_raw_without_timeout(data, self)
|
|
889
|
+
|
|
680
890
|
self
|
|
681
891
|
end
|
|
682
892
|
|
|
@@ -753,19 +963,19 @@ module Bunny
|
|
|
753
963
|
# @see Bunny::Channel#prefetch
|
|
754
964
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
755
965
|
# @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: #{
|
|
966
|
+
def basic_qos(prefetch_count, global = false)
|
|
967
|
+
raise ArgumentError.new("prefetch count must be a positive integer, given: #{prefetch_count}") if prefetch_count < 0
|
|
968
|
+
raise ArgumentError.new("prefetch count must be no greater than #{MAX_PREFETCH_COUNT}, given: #{prefetch_count}") if prefetch_count > MAX_PREFETCH_COUNT
|
|
759
969
|
raise_if_no_longer_open!
|
|
760
970
|
|
|
761
|
-
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0,
|
|
971
|
+
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, prefetch_count, global))
|
|
762
972
|
|
|
763
973
|
with_continuation_timeout do
|
|
764
974
|
@last_basic_qos_ok = wait_on_continuations
|
|
765
975
|
end
|
|
766
976
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
767
977
|
|
|
768
|
-
@prefetch_count =
|
|
978
|
+
@prefetch_count = prefetch_count
|
|
769
979
|
@prefetch_global = global
|
|
770
980
|
|
|
771
981
|
@last_basic_qos_ok
|
|
@@ -828,12 +1038,10 @@ module Bunny
|
|
|
828
1038
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
829
1039
|
# @api public
|
|
830
1040
|
def basic_reject(delivery_tag, requeue = false)
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
|
1041
|
+
raise_if_no_longer_open!
|
|
1042
|
+
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
|
834
1043
|
|
|
835
|
-
|
|
836
|
-
end
|
|
1044
|
+
nil
|
|
837
1045
|
end
|
|
838
1046
|
|
|
839
1047
|
# Acknowledges a delivery (message).
|
|
@@ -952,7 +1160,7 @@ module Bunny
|
|
|
952
1160
|
# Registers a consumer for queue. Delivered messages will be handled with the block
|
|
953
1161
|
# provided to this method.
|
|
954
1162
|
#
|
|
955
|
-
# @param [String
|
|
1163
|
+
# @param [String] queue Queue to consume from
|
|
956
1164
|
# @param [String] consumer_tag Consumer tag (unique identifier), generated by Bunny by default
|
|
957
1165
|
# @param [Boolean] no_ack (false) If true, delivered messages will be automatically acknowledged.
|
|
958
1166
|
# If false, manual acknowledgements will be necessary.
|
|
@@ -975,7 +1183,7 @@ module Bunny
|
|
|
975
1183
|
# helps avoid race condition between basic.consume-ok and basic.deliver if there are messages
|
|
976
1184
|
# in the queue already. MK.
|
|
977
1185
|
if consumer_tag && consumer_tag.strip != AMQ::Protocol::EMPTY_STRING
|
|
978
|
-
add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1186
|
+
add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments || {}, &block)
|
|
979
1187
|
end
|
|
980
1188
|
|
|
981
1189
|
@connection.send_frame(AMQ::Protocol::Basic::Consume.encode(@id,
|
|
@@ -995,6 +1203,8 @@ module Bunny
|
|
|
995
1203
|
# if basic.consume-ok never arrives, unregister the proactively
|
|
996
1204
|
# registered consumer. MK.
|
|
997
1205
|
unregister_consumer(@last_basic_consume_ok.consumer_tag)
|
|
1206
|
+
# #add_consumer records a consumer, make sure to undo it here. MK.
|
|
1207
|
+
delete_recorded_consumer(@last_basic_consume_ok.consumer_tag)
|
|
998
1208
|
|
|
999
1209
|
raise e
|
|
1000
1210
|
end
|
|
@@ -1004,7 +1214,7 @@ module Bunny
|
|
|
1004
1214
|
raise_if_channel_close!(@last_basic_consume_ok)
|
|
1005
1215
|
|
|
1006
1216
|
# covers server-generated consumer tags
|
|
1007
|
-
add_consumer(queue_name, @last_basic_consume_ok.consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1217
|
+
add_consumer(queue_name, @last_basic_consume_ok.consumer_tag, no_ack, exclusive, arguments || {}, &block)
|
|
1008
1218
|
|
|
1009
1219
|
@last_basic_consume_ok
|
|
1010
1220
|
end
|
|
@@ -1055,6 +1265,12 @@ module Bunny
|
|
|
1055
1265
|
|
|
1056
1266
|
# covers server-generated consumer tags
|
|
1057
1267
|
register_consumer(@last_basic_consume_ok.consumer_tag, consumer)
|
|
1268
|
+
record_consumer_with(self, @last_basic_consume_ok.consumer_tag,
|
|
1269
|
+
consumer.queue_name,
|
|
1270
|
+
consumer,
|
|
1271
|
+
consumer.manual_acknowledgement?,
|
|
1272
|
+
consumer.exclusive,
|
|
1273
|
+
consumer.arguments)
|
|
1058
1274
|
|
|
1059
1275
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1060
1276
|
|
|
@@ -1066,12 +1282,12 @@ module Bunny
|
|
|
1066
1282
|
# it was on is auto-deleted and this consumer was the last one, the queue will be deleted.
|
|
1067
1283
|
#
|
|
1068
1284
|
# @param [String] consumer_tag Consumer tag (unique identifier) to cancel
|
|
1069
|
-
# @param [Hash]
|
|
1285
|
+
# @param [Hash] opts ({}) Optional arguments
|
|
1070
1286
|
#
|
|
1071
1287
|
# @option opts [Boolean] :no_wait (false) if set to true, this method won't receive a response and will
|
|
1072
1288
|
# immediately return nil
|
|
1073
1289
|
#
|
|
1074
|
-
# @return [AMQ::Protocol::Basic::CancelOk] RabbitMQ response or nil, if the no_wait option is used
|
|
1290
|
+
# @return [AMQ::Protocol::Basic::CancelOk, nil] RabbitMQ response or nil, if the no_wait option is used
|
|
1075
1291
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
1076
1292
|
# @api public
|
|
1077
1293
|
def basic_cancel(consumer_tag, opts = {})
|
|
@@ -1089,6 +1305,7 @@ module Bunny
|
|
|
1089
1305
|
# reduces thread usage for channels that don't have any
|
|
1090
1306
|
# consumers
|
|
1091
1307
|
@work_pool.shutdown(true) unless self.any_consumers?
|
|
1308
|
+
self.delete_recorded_consumer(consumer_tag)
|
|
1092
1309
|
|
|
1093
1310
|
@last_basic_cancel_ok
|
|
1094
1311
|
end
|
|
@@ -1123,6 +1340,26 @@ module Bunny
|
|
|
1123
1340
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
|
1124
1341
|
# @api public
|
|
1125
1342
|
def queue_declare(name, opts = {})
|
|
1343
|
+
# strip trailing new line and carriage returns
|
|
1344
|
+
# just like RabbitMQ does
|
|
1345
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
|
1346
|
+
is_server_named = (safe_name == AMQ::Protocol::EMPTY_STRING)
|
|
1347
|
+
passive = opts.fetch(:passive, false)
|
|
1348
|
+
durable = opts.fetch(:durable, false)
|
|
1349
|
+
exclusive = opts.fetch(:exclusive, false)
|
|
1350
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1351
|
+
args = opts[:arguments]
|
|
1352
|
+
|
|
1353
|
+
result = self.queue_declare_without_recording_topology(name, opts)
|
|
1354
|
+
self.record_queue_with(self, result.queue, is_server_named, durable, exclusive, auto_delete, args) unless passive
|
|
1355
|
+
|
|
1356
|
+
result
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1360
|
+
# as we iterate over them during topology recovery.
|
|
1361
|
+
# @private
|
|
1362
|
+
def queue_declare_without_recording_topology(name, opts = {})
|
|
1126
1363
|
raise_if_no_longer_open!
|
|
1127
1364
|
|
|
1128
1365
|
Bunny::Queue.verify_type!(opts[:arguments]) if opts[:arguments]
|
|
@@ -1130,16 +1367,24 @@ module Bunny
|
|
|
1130
1367
|
# strip trailing new line and carriage returns
|
|
1131
1368
|
# just like RabbitMQ does
|
|
1132
1369
|
safe_name = name.gsub(/[\r\n]/, "")
|
|
1370
|
+
is_server_named = (safe_name == AMQ::Protocol::EMPTY_STRING)
|
|
1133
1371
|
@pending_queue_declare_name = safe_name
|
|
1372
|
+
|
|
1373
|
+
passive = opts.fetch(:passive, false)
|
|
1374
|
+
durable = opts.fetch(:durable, false)
|
|
1375
|
+
exclusive = opts.fetch(:exclusive, false)
|
|
1376
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1377
|
+
args = opts[:arguments]
|
|
1378
|
+
|
|
1134
1379
|
@connection.send_frame(
|
|
1135
1380
|
AMQ::Protocol::Queue::Declare.encode(@id,
|
|
1136
1381
|
@pending_queue_declare_name,
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1382
|
+
passive,
|
|
1383
|
+
durable,
|
|
1384
|
+
exclusive,
|
|
1385
|
+
auto_delete,
|
|
1141
1386
|
false,
|
|
1142
|
-
|
|
1387
|
+
args))
|
|
1143
1388
|
|
|
1144
1389
|
begin
|
|
1145
1390
|
with_continuation_timeout do
|
|
@@ -1177,6 +1422,8 @@ module Bunny
|
|
|
1177
1422
|
@last_queue_delete_ok = wait_on_continuations
|
|
1178
1423
|
end
|
|
1179
1424
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1425
|
+
self.delete_recorded_queue_named(name)
|
|
1426
|
+
self.deregister_queue_named(name)
|
|
1180
1427
|
|
|
1181
1428
|
@last_queue_delete_ok
|
|
1182
1429
|
end
|
|
@@ -1222,18 +1469,43 @@ module Bunny
|
|
|
1222
1469
|
else
|
|
1223
1470
|
exchange
|
|
1224
1471
|
end
|
|
1472
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1473
|
+
args = opts[:arguments]
|
|
1474
|
+
|
|
1475
|
+
result = self.queue_bind_without_recording_topology(name, exchange, opts)
|
|
1476
|
+
self.record_queue_binding_with(self, exchange_name, name, rk, args)
|
|
1225
1477
|
|
|
1478
|
+
result
|
|
1479
|
+
end
|
|
1480
|
+
|
|
1481
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1482
|
+
# as we iterate over them during topology recovery.
|
|
1483
|
+
# @private
|
|
1484
|
+
def queue_bind_without_recording_topology(name, exchange, opts = {})
|
|
1485
|
+
raise_if_no_longer_open!
|
|
1486
|
+
|
|
1487
|
+
exchange_name = if exchange.respond_to?(:name)
|
|
1488
|
+
exchange.name
|
|
1489
|
+
else
|
|
1490
|
+
exchange
|
|
1491
|
+
end
|
|
1492
|
+
|
|
1493
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1494
|
+
args = opts[:arguments]
|
|
1226
1495
|
@connection.send_frame(AMQ::Protocol::Queue::Bind.encode(@id,
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1496
|
+
name,
|
|
1497
|
+
exchange_name,
|
|
1498
|
+
rk,
|
|
1499
|
+
false,
|
|
1500
|
+
args))
|
|
1501
|
+
|
|
1232
1502
|
with_continuation_timeout do
|
|
1233
1503
|
@last_queue_bind_ok = wait_on_continuations
|
|
1234
1504
|
end
|
|
1235
1505
|
|
|
1236
1506
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1507
|
+
|
|
1508
|
+
|
|
1237
1509
|
@last_queue_bind_ok
|
|
1238
1510
|
end
|
|
1239
1511
|
|
|
@@ -1259,16 +1531,20 @@ module Bunny
|
|
|
1259
1531
|
exchange
|
|
1260
1532
|
end
|
|
1261
1533
|
|
|
1534
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1535
|
+
args = opts[:arguments]
|
|
1262
1536
|
@connection.send_frame(AMQ::Protocol::Queue::Unbind.encode(@id,
|
|
1263
1537
|
name,
|
|
1264
1538
|
exchange_name,
|
|
1265
|
-
|
|
1266
|
-
|
|
1539
|
+
rk,
|
|
1540
|
+
args))
|
|
1267
1541
|
with_continuation_timeout do
|
|
1268
1542
|
@last_queue_unbind_ok = wait_on_continuations
|
|
1269
1543
|
end
|
|
1270
1544
|
|
|
1271
1545
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1546
|
+
self.delete_recorded_queue_binding(self, exchange_name, name, rk, args)
|
|
1547
|
+
|
|
1272
1548
|
@last_queue_unbind_ok
|
|
1273
1549
|
end
|
|
1274
1550
|
|
|
@@ -1294,25 +1570,65 @@ module Bunny
|
|
|
1294
1570
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
|
1295
1571
|
# @api public
|
|
1296
1572
|
def exchange_declare(name, type, opts = {})
|
|
1573
|
+
result = self.exchange_declare_without_recording_topology(name, type, opts)
|
|
1574
|
+
|
|
1575
|
+
# strip trailing new line and carriage returns
|
|
1576
|
+
# just like RabbitMQ does
|
|
1577
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
|
1578
|
+
passive = opts.fetch(:passive, false)
|
|
1579
|
+
durable = opts.fetch(:durable, false)
|
|
1580
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1581
|
+
args = opts[:arguments]
|
|
1582
|
+
self.record_exchange_with(self,
|
|
1583
|
+
safe_name,
|
|
1584
|
+
type.to_s,
|
|
1585
|
+
durable,
|
|
1586
|
+
auto_delete,
|
|
1587
|
+
args) unless passive
|
|
1588
|
+
|
|
1589
|
+
result
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1593
|
+
# as we iterate over them during topology recovery.
|
|
1594
|
+
#
|
|
1595
|
+
# @param [String] name The name of the exchange. Note that LF and CR characters
|
|
1596
|
+
# will be stripped from the value.
|
|
1597
|
+
# @param [String,Symbol] type Exchange type, e.g. :fanout or :topic
|
|
1598
|
+
# @param [Hash] opts Exchange properties
|
|
1599
|
+
#
|
|
1600
|
+
# @option opts [Boolean] durable (false) Should information about this exchange be persisted to disk so that it
|
|
1601
|
+
# can survive broker restarts? Typically set to true for long-lived exchanges.
|
|
1602
|
+
# @option opts [Boolean] auto_delete (false) Should this exchange be deleted when it is no longer used?
|
|
1603
|
+
# @option opts [Boolean] passive (false) If true, exchange will be checked for existence. If it does not
|
|
1604
|
+
# exist, {Bunny::NotFound} will be raised.
|
|
1605
|
+
# @private
|
|
1606
|
+
def exchange_declare_without_recording_topology(name, type, opts = {})
|
|
1297
1607
|
raise_if_no_longer_open!
|
|
1298
1608
|
|
|
1299
1609
|
# strip trailing new line and carriage returns
|
|
1300
1610
|
# just like RabbitMQ does
|
|
1301
1611
|
safe_name = name.gsub(/[\r\n]/, "")
|
|
1612
|
+
passive = opts.fetch(:passive, false)
|
|
1613
|
+
durable = opts.fetch(:durable, false)
|
|
1614
|
+
auto_delete = opts.fetch(:auto_delete, false)
|
|
1615
|
+
args = opts[:arguments]
|
|
1616
|
+
|
|
1302
1617
|
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@id,
|
|
1303
1618
|
safe_name,
|
|
1304
1619
|
type.to_s,
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1620
|
+
passive,
|
|
1621
|
+
durable,
|
|
1622
|
+
auto_delete,
|
|
1308
1623
|
opts.fetch(:internal, false),
|
|
1309
1624
|
opts.fetch(:no_wait, false),
|
|
1310
|
-
|
|
1625
|
+
args))
|
|
1311
1626
|
with_continuation_timeout do
|
|
1312
1627
|
@last_exchange_declare_ok = wait_on_continuations
|
|
1313
1628
|
end
|
|
1314
1629
|
|
|
1315
1630
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1631
|
+
|
|
1316
1632
|
@last_exchange_declare_ok
|
|
1317
1633
|
end
|
|
1318
1634
|
|
|
@@ -1338,6 +1654,9 @@ module Bunny
|
|
|
1338
1654
|
end
|
|
1339
1655
|
|
|
1340
1656
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1657
|
+
self.delete_recorded_exchange_named(name)
|
|
1658
|
+
self.deregister_exchange_named(name)
|
|
1659
|
+
|
|
1341
1660
|
@last_exchange_delete_ok
|
|
1342
1661
|
end
|
|
1343
1662
|
|
|
@@ -1357,6 +1676,29 @@ module Bunny
|
|
|
1357
1676
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
|
1358
1677
|
# @api public
|
|
1359
1678
|
def exchange_bind(source, destination, opts = {})
|
|
1679
|
+
result = self.exchange_bind_without_recording_topology(source, destination, opts)
|
|
1680
|
+
|
|
1681
|
+
source_name = if source.respond_to?(:name)
|
|
1682
|
+
source.name
|
|
1683
|
+
else
|
|
1684
|
+
source
|
|
1685
|
+
end
|
|
1686
|
+
destination_name = if destination.respond_to?(:name)
|
|
1687
|
+
destination.name
|
|
1688
|
+
else
|
|
1689
|
+
destination
|
|
1690
|
+
end
|
|
1691
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1692
|
+
args = opts[:arguments]
|
|
1693
|
+
self.record_exchange_binding_with(self, source_name, destination_name, rk, args)
|
|
1694
|
+
|
|
1695
|
+
result
|
|
1696
|
+
end
|
|
1697
|
+
|
|
1698
|
+
# We need this bypassing topology version to avoid modifying the collections
|
|
1699
|
+
# as we iterate over them during topology recovery.
|
|
1700
|
+
# @private
|
|
1701
|
+
def exchange_bind_without_recording_topology(source, destination, opts = {})
|
|
1360
1702
|
raise_if_no_longer_open!
|
|
1361
1703
|
|
|
1362
1704
|
source_name = if source.respond_to?(:name)
|
|
@@ -1371,17 +1713,21 @@ module Bunny
|
|
|
1371
1713
|
destination
|
|
1372
1714
|
end
|
|
1373
1715
|
|
|
1716
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1717
|
+
args = opts[:arguments]
|
|
1374
1718
|
@connection.send_frame(AMQ::Protocol::Exchange::Bind.encode(@id,
|
|
1375
1719
|
destination_name,
|
|
1376
1720
|
source_name,
|
|
1377
|
-
|
|
1721
|
+
rk,
|
|
1378
1722
|
false,
|
|
1379
|
-
|
|
1723
|
+
args))
|
|
1380
1724
|
with_continuation_timeout do
|
|
1381
1725
|
@last_exchange_bind_ok = wait_on_continuations
|
|
1382
1726
|
end
|
|
1383
1727
|
|
|
1384
1728
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1729
|
+
self.record_exchange_binding_with(self, source_name, destination_name, rk, args)
|
|
1730
|
+
|
|
1385
1731
|
@last_exchange_bind_ok
|
|
1386
1732
|
end
|
|
1387
1733
|
|
|
@@ -1415,17 +1761,21 @@ module Bunny
|
|
|
1415
1761
|
destination
|
|
1416
1762
|
end
|
|
1417
1763
|
|
|
1764
|
+
rk = (opts[:routing_key] || opts[:key])
|
|
1765
|
+
args = opts[:arguments]
|
|
1418
1766
|
@connection.send_frame(AMQ::Protocol::Exchange::Unbind.encode(@id,
|
|
1419
1767
|
destination_name,
|
|
1420
1768
|
source_name,
|
|
1421
|
-
|
|
1769
|
+
rk,
|
|
1422
1770
|
false,
|
|
1423
|
-
|
|
1771
|
+
args))
|
|
1424
1772
|
with_continuation_timeout do
|
|
1425
1773
|
@last_exchange_unbind_ok = wait_on_continuations
|
|
1426
1774
|
end
|
|
1427
1775
|
|
|
1428
1776
|
raise_if_continuation_resulted_in_a_channel_error!
|
|
1777
|
+
self.delete_recorded_exchange_binding(self, source_name, destination_name, rk, args)
|
|
1778
|
+
|
|
1429
1779
|
@last_exchange_unbind_ok
|
|
1430
1780
|
end
|
|
1431
1781
|
|
|
@@ -1528,14 +1878,25 @@ module Bunny
|
|
|
1528
1878
|
alias using_publisher_confirms? using_publisher_confirmations?
|
|
1529
1879
|
|
|
1530
1880
|
# Enables publisher confirms for the channel.
|
|
1881
|
+
#
|
|
1882
|
+
# @param [Proc] callback Optional callback invoked for each confirm. Receives (delivery_tag, multiple, nack).
|
|
1883
|
+
# @param [Boolean] tracking When true, basic_publish blocks until the broker confirms receipt.
|
|
1884
|
+
# Raises Bunny::MessageNacked if the message is nacked.
|
|
1885
|
+
# @param [Integer] outstanding_limit Max unconfirmed messages before basic_publish blocks.
|
|
1886
|
+
# Defaults to 1000 when tracking: true (optimal for throughput). Pass explicit value to override.
|
|
1887
|
+
# @param [Integer] confirm_timeout Timeout in ms for confirms. Defaults to connection's continuation_timeout.
|
|
1888
|
+
#
|
|
1531
1889
|
# @return [AMQ::Protocol::Confirm::SelectOk] RabbitMQ response
|
|
1532
1890
|
# @see #wait_for_confirms
|
|
1533
1891
|
# @see #unconfirmed_set
|
|
1534
1892
|
# @see #nacked_set
|
|
1535
1893
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
|
1536
1894
|
# @api public
|
|
1537
|
-
def confirm_select(callback = nil)
|
|
1895
|
+
def confirm_select(callback = nil, tracking: false, outstanding_limit: nil, confirm_timeout: nil)
|
|
1538
1896
|
raise_if_no_longer_open!
|
|
1897
|
+
raise ArgumentError, "outstanding_limit requires tracking: true" if outstanding_limit && !tracking
|
|
1898
|
+
raise ArgumentError, "outstanding_limit must be positive" if outstanding_limit && outstanding_limit < 1
|
|
1899
|
+
raise ArgumentError, "confirm_timeout must be positive" if confirm_timeout && confirm_timeout < 1
|
|
1539
1900
|
|
|
1540
1901
|
if @next_publish_seq_no == 0
|
|
1541
1902
|
@confirms_continuations = new_continuation
|
|
@@ -1546,6 +1907,17 @@ module Bunny
|
|
|
1546
1907
|
end
|
|
1547
1908
|
|
|
1548
1909
|
@confirms_callback = callback
|
|
1910
|
+
@confirms_tracking_enabled = tracking
|
|
1911
|
+
# Default to optimal limit when tracking enabled (avoids per-message mutex)
|
|
1912
|
+
@outstanding_limit = outstanding_limit || (tracking ? DEFAULT_OUTSTANDING_CONFIRMS_LIMIT : nil)
|
|
1913
|
+
@confirm_timeout = confirm_timeout
|
|
1914
|
+
|
|
1915
|
+
# Cache combined check for fast path in basic_publish
|
|
1916
|
+
@throttle_publishes = tracking && @outstanding_limit
|
|
1917
|
+
|
|
1918
|
+
if @outstanding_limit && !@outstanding_limit_cond
|
|
1919
|
+
@outstanding_limit_cond = @unconfirmed_set_mutex.new_cond
|
|
1920
|
+
end
|
|
1549
1921
|
|
|
1550
1922
|
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
|
1551
1923
|
with_continuation_timeout do
|
|
@@ -1585,9 +1957,9 @@ module Bunny
|
|
|
1585
1957
|
#
|
|
1586
1958
|
# @return [String] Unique string.
|
|
1587
1959
|
# @api plugin
|
|
1588
|
-
def generate_consumer_tag(
|
|
1960
|
+
def generate_consumer_tag(prefix = "bunny")
|
|
1589
1961
|
t = Bunny::Timestamp.now
|
|
1590
|
-
"#{
|
|
1962
|
+
"#{prefix}-#{t.to_i * 1000}-#{Kernel.rand(999_999_999_999)}"
|
|
1591
1963
|
end
|
|
1592
1964
|
|
|
1593
1965
|
# @endgroup
|
|
@@ -1630,11 +2002,8 @@ module Bunny
|
|
|
1630
2002
|
recover_prefetch_setting
|
|
1631
2003
|
recover_confirm_mode
|
|
1632
2004
|
recover_tx_mode
|
|
1633
|
-
|
|
1634
|
-
#
|
|
1635
|
-
recover_queues
|
|
1636
|
-
recover_consumers
|
|
1637
|
-
increment_recoveries_counter
|
|
2005
|
+
|
|
2006
|
+
# Topology is now recovered by [Bunny::Session] via the data in [Bunny::TopologyRegistry].
|
|
1638
2007
|
end
|
|
1639
2008
|
|
|
1640
2009
|
# Recovers basic.qos setting. Used by the Automatic Network Failure
|
|
@@ -1651,13 +2020,26 @@ module Bunny
|
|
|
1651
2020
|
#
|
|
1652
2021
|
# @api plugin
|
|
1653
2022
|
def recover_confirm_mode
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2023
|
+
return unless using_publisher_confirmations?
|
|
2024
|
+
|
|
2025
|
+
@unconfirmed_set_mutex.synchronize do
|
|
2026
|
+
@unconfirmed_set.clear
|
|
2027
|
+
@delivery_tag_offset = @next_publish_seq_no - 1
|
|
2028
|
+
|
|
2029
|
+
if @confirms_tracking_enabled
|
|
2030
|
+
@per_message_continuations_mutex.synchronize do
|
|
2031
|
+
@per_message_continuations.each_value { |c| c.push(:network_error) }
|
|
2032
|
+
@per_message_continuations.clear
|
|
2033
|
+
end
|
|
1658
2034
|
end
|
|
1659
|
-
|
|
2035
|
+
|
|
2036
|
+
@outstanding_limit_cond&.broadcast
|
|
1660
2037
|
end
|
|
2038
|
+
|
|
2039
|
+
confirm_select(@confirms_callback,
|
|
2040
|
+
tracking: @confirms_tracking_enabled,
|
|
2041
|
+
outstanding_limit: @outstanding_limit,
|
|
2042
|
+
confirm_timeout: @confirm_timeout)
|
|
1661
2043
|
end
|
|
1662
2044
|
|
|
1663
2045
|
# Recovers transaction mode. Used by the Automatic Network Failure
|
|
@@ -1668,45 +2050,31 @@ module Bunny
|
|
|
1668
2050
|
tx_select if @tx_mode
|
|
1669
2051
|
end
|
|
1670
2052
|
|
|
1671
|
-
#
|
|
2053
|
+
# Used by the Automatic Network Failure
|
|
1672
2054
|
# Recovery feature.
|
|
1673
2055
|
#
|
|
1674
|
-
# @
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
2056
|
+
# @param [String] old_name
|
|
2057
|
+
# @param [String] new_name
|
|
2058
|
+
# @private
|
|
2059
|
+
def record_queue_name_change(old_name, new_name)
|
|
2060
|
+
@queue_mutex.synchronize do
|
|
2061
|
+
if (orig = @queues[old_name])
|
|
2062
|
+
@queues.delete(old_name)
|
|
1680
2063
|
|
|
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
|
|
2064
|
+
orig.update_name_to(new_name)
|
|
2065
|
+
@queues[new_name] = orig.dup
|
|
2066
|
+
end
|
|
1689
2067
|
end
|
|
1690
2068
|
end
|
|
1691
2069
|
|
|
1692
|
-
#
|
|
1693
|
-
# Recovery feature.
|
|
2070
|
+
# Used by the Automatic Network Failure Recovery feature.
|
|
1694
2071
|
#
|
|
1695
|
-
# @api
|
|
1696
|
-
def
|
|
2072
|
+
# @api private
|
|
2073
|
+
def maybe_reinitialize_consumer_pool!
|
|
1697
2074
|
unless @consumers.empty?
|
|
1698
2075
|
@work_pool = ConsumerWorkPool.new(@work_pool.size, @work_pool.abort_on_exception)
|
|
1699
2076
|
@work_pool.start
|
|
1700
2077
|
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
2078
|
end
|
|
1711
2079
|
|
|
1712
2080
|
# @api public
|
|
@@ -1745,6 +2113,9 @@ module Bunny
|
|
|
1745
2113
|
def register_consumer(consumer_tag, consumer)
|
|
1746
2114
|
@consumer_mutex.synchronize do
|
|
1747
2115
|
@consumers[consumer_tag] = consumer
|
|
2116
|
+
if @last_consumer_tag == consumer_tag
|
|
2117
|
+
@last_consumer = consumer
|
|
2118
|
+
end
|
|
1748
2119
|
end
|
|
1749
2120
|
end
|
|
1750
2121
|
|
|
@@ -1752,16 +2123,35 @@ module Bunny
|
|
|
1752
2123
|
def unregister_consumer(consumer_tag)
|
|
1753
2124
|
@consumer_mutex.synchronize do
|
|
1754
2125
|
@consumers.delete(consumer_tag)
|
|
2126
|
+
if @last_consumer_tag == consumer_tag
|
|
2127
|
+
@last_consumer_tag = nil
|
|
2128
|
+
@last_consumer = nil
|
|
2129
|
+
end
|
|
1755
2130
|
end
|
|
1756
2131
|
end
|
|
1757
2132
|
|
|
2133
|
+
# @param [String] queue_name
|
|
2134
|
+
# @param [String] consumer_tag
|
|
2135
|
+
# @param [Boolean] no_ack true means automative acknowledgement mode
|
|
2136
|
+
# @param [Boolean] exclusive
|
|
2137
|
+
# @param [Hash] arguments
|
|
1758
2138
|
# @private
|
|
1759
|
-
def add_consumer(
|
|
2139
|
+
def add_consumer(queue_name, consumer_tag, no_ack, exclusive, arguments, &block)
|
|
1760
2140
|
@consumer_mutex.synchronize do
|
|
1761
|
-
c = Consumer.new(self,
|
|
2141
|
+
c = Consumer.new(self, queue_name, consumer_tag, no_ack, exclusive, arguments)
|
|
1762
2142
|
c.on_delivery(&block) if block
|
|
1763
2143
|
@consumers[consumer_tag] = c
|
|
2144
|
+
if @last_consumer_tag == consumer_tag
|
|
2145
|
+
@last_consumer = c
|
|
2146
|
+
end
|
|
2147
|
+
c
|
|
1764
2148
|
end
|
|
2149
|
+
record_consumer_with(self, consumer_tag,
|
|
2150
|
+
queue_name,
|
|
2151
|
+
block,
|
|
2152
|
+
!no_ack,
|
|
2153
|
+
exclusive,
|
|
2154
|
+
arguments)
|
|
1765
2155
|
end
|
|
1766
2156
|
|
|
1767
2157
|
# @private
|
|
@@ -1826,6 +2216,10 @@ module Bunny
|
|
|
1826
2216
|
consume_with(consumer)
|
|
1827
2217
|
else
|
|
1828
2218
|
@consumers.delete(method.consumer_tag)
|
|
2219
|
+
if @last_consumer_tag == method.consumer_tag
|
|
2220
|
+
@last_consumer_tag = nil
|
|
2221
|
+
@last_consumer = nil
|
|
2222
|
+
end
|
|
1829
2223
|
consumer.handle_cancellation(method)
|
|
1830
2224
|
end
|
|
1831
2225
|
rescue Exception => e
|
|
@@ -1839,6 +2233,7 @@ module Bunny
|
|
|
1839
2233
|
when AMQ::Protocol::Basic::CancelOk then
|
|
1840
2234
|
@continuations.push(method)
|
|
1841
2235
|
unregister_consumer(method.consumer_tag)
|
|
2236
|
+
delete_recorded_consumer(method.consumer_tag)
|
|
1842
2237
|
when AMQ::Protocol::Tx::SelectOk, AMQ::Protocol::Tx::CommitOk, AMQ::Protocol::Tx::RollbackOk then
|
|
1843
2238
|
@continuations.push(method)
|
|
1844
2239
|
when AMQ::Protocol::Tx::SelectOk then
|
|
@@ -1870,12 +2265,12 @@ module Bunny
|
|
|
1870
2265
|
|
|
1871
2266
|
# @private
|
|
1872
2267
|
def channel_level_exception_after_operation_that_has_no_response?(method)
|
|
1873
|
-
method.
|
|
2268
|
+
method.unknown_delivery_tag? || method.delivery_ack_timeout? || method.message_too_large?
|
|
1874
2269
|
end
|
|
1875
2270
|
|
|
1876
2271
|
# @private
|
|
1877
2272
|
def handle_basic_get_ok(basic_get_ok, properties, content)
|
|
1878
|
-
basic_get_ok.delivery_tag =
|
|
2273
|
+
basic_get_ok.delivery_tag = basic_get_ok.delivery_tag
|
|
1879
2274
|
@basic_get_continuations.push([basic_get_ok, properties, content])
|
|
1880
2275
|
end
|
|
1881
2276
|
|
|
@@ -1886,20 +2281,33 @@ module Bunny
|
|
|
1886
2281
|
|
|
1887
2282
|
# @private
|
|
1888
2283
|
def handle_frameset(basic_deliver, properties, content)
|
|
1889
|
-
|
|
2284
|
+
tag = basic_deliver.consumer_tag
|
|
2285
|
+
if @last_consumer_tag == tag
|
|
2286
|
+
consumer = @last_consumer
|
|
2287
|
+
else
|
|
2288
|
+
consumer = @consumers[tag]
|
|
2289
|
+
@last_consumer_tag = tag
|
|
2290
|
+
@last_consumer = consumer
|
|
2291
|
+
end
|
|
2292
|
+
|
|
1890
2293
|
if consumer
|
|
1891
2294
|
@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
|
|
2295
|
+
deliver_to_consumer(consumer, basic_deliver, properties, content)
|
|
1897
2296
|
end
|
|
1898
2297
|
else
|
|
1899
2298
|
@logger.warn "No consumer for tag #{basic_deliver.consumer_tag} on channel #{@id}!"
|
|
1900
2299
|
end
|
|
1901
2300
|
end
|
|
1902
2301
|
|
|
2302
|
+
# @private
|
|
2303
|
+
def deliver_to_consumer(consumer, basic_deliver, properties, content)
|
|
2304
|
+
begin
|
|
2305
|
+
consumer.call(DeliveryInfo.new(basic_deliver, consumer, self), MessageProperties.new(properties), content)
|
|
2306
|
+
rescue StandardError => e
|
|
2307
|
+
@uncaught_exception_handler.call(e, consumer) if @uncaught_exception_handler
|
|
2308
|
+
end
|
|
2309
|
+
end
|
|
2310
|
+
|
|
1903
2311
|
# @private
|
|
1904
2312
|
def handle_basic_return(basic_return, properties, content)
|
|
1905
2313
|
x = find_exchange(basic_return.exchange)
|
|
@@ -1931,6 +2339,22 @@ module Bunny
|
|
|
1931
2339
|
|
|
1932
2340
|
@confirms_continuations.push(true) if @unconfirmed_set.empty?
|
|
1933
2341
|
|
|
2342
|
+
# Signal per-message continuations (only used when tracking without limit)
|
|
2343
|
+
if @confirms_tracking_enabled && !@throttle_publishes
|
|
2344
|
+
to_signal = []
|
|
2345
|
+
@per_message_continuations_mutex.synchronize do
|
|
2346
|
+
@per_message_continuations.each do |tag, cont|
|
|
2347
|
+
to_signal << cont if tag >= confirmed_range_start && tag <= confirmed_range_end
|
|
2348
|
+
end
|
|
2349
|
+
end
|
|
2350
|
+
result = nack ? :nack : :ack
|
|
2351
|
+
to_signal.each { |c| c.push(result) }
|
|
2352
|
+
end
|
|
2353
|
+
|
|
2354
|
+
# Wake publisher(s) waiting for outstanding limit slot
|
|
2355
|
+
# Use broadcast since "multiple" acks can free many slots at once
|
|
2356
|
+
@outstanding_limit_cond&.broadcast if @throttle_publishes
|
|
2357
|
+
|
|
1934
2358
|
if @confirms_callback
|
|
1935
2359
|
confirmed_range.each { |tag| @confirms_callback.call(tag, false, nack) }
|
|
1936
2360
|
end
|
|
@@ -2005,21 +2429,63 @@ module Bunny
|
|
|
2005
2429
|
end
|
|
2006
2430
|
end
|
|
2007
2431
|
|
|
2008
|
-
|
|
2009
|
-
#
|
|
2432
|
+
# Waits for a slot when outstanding limit is reached.
|
|
2433
|
+
# Assumes @unconfirmed_set_mutex is already held.
|
|
2010
2434
|
# @private
|
|
2011
|
-
def
|
|
2012
|
-
|
|
2013
|
-
|
|
2435
|
+
def wait_for_outstanding_slot_locked
|
|
2436
|
+
limit = @outstanding_limit
|
|
2437
|
+
return if @unconfirmed_set.size < limit
|
|
2438
|
+
|
|
2439
|
+
timeout_sec = (@confirm_timeout || @connection.continuation_timeout) / 1000.0
|
|
2440
|
+
deadline = Bunny::Timestamp.monotonic + timeout_sec
|
|
2441
|
+
|
|
2442
|
+
while @unconfirmed_set.size >= limit
|
|
2443
|
+
raise_if_no_longer_open!
|
|
2444
|
+
|
|
2445
|
+
remaining = deadline - Bunny::Timestamp.monotonic
|
|
2446
|
+
raise Timeout::Error, "Timed out waiting for publisher confirms (limit: #{limit})" if remaining <= 0
|
|
2447
|
+
|
|
2448
|
+
@outstanding_limit_cond.wait(remaining)
|
|
2014
2449
|
end
|
|
2015
|
-
|
|
2016
|
-
|
|
2450
|
+
end
|
|
2451
|
+
|
|
2452
|
+
# @private
|
|
2453
|
+
def wait_for_publish_confirm(seq_no, continuation)
|
|
2454
|
+
t = Thread.current
|
|
2455
|
+
@threads_waiting_on_confirms_continuations << t
|
|
2456
|
+
|
|
2457
|
+
begin
|
|
2458
|
+
timeout = @confirm_timeout || @connection.continuation_timeout
|
|
2459
|
+
case continuation.poll(timeout)
|
|
2460
|
+
when :ack, true
|
|
2461
|
+
# confirmed
|
|
2462
|
+
when :nack
|
|
2463
|
+
raise MessageNacked.new("Message #{seq_no} was nacked", seq_no)
|
|
2464
|
+
when :network_error
|
|
2465
|
+
raise NetworkFailure.new("Network failure waiting for confirm", nil)
|
|
2466
|
+
when nil
|
|
2467
|
+
raise Timeout::Error, "Timed out waiting for publisher confirm"
|
|
2468
|
+
end
|
|
2469
|
+
ensure
|
|
2470
|
+
@threads_waiting_on_confirms_continuations.delete(t)
|
|
2471
|
+
@per_message_continuations_mutex.synchronize do
|
|
2472
|
+
@per_message_continuations.delete(seq_no)
|
|
2473
|
+
end
|
|
2017
2474
|
end
|
|
2018
|
-
|
|
2019
|
-
|
|
2475
|
+
end
|
|
2476
|
+
|
|
2477
|
+
|
|
2478
|
+
# @private
|
|
2479
|
+
def release_all_continuations
|
|
2480
|
+
@threads_waiting_on_confirms_continuations.each(&:run)
|
|
2481
|
+
@threads_waiting_on_continuations.each(&:run)
|
|
2482
|
+
@threads_waiting_on_basic_get_continuations.each(&:run)
|
|
2483
|
+
|
|
2484
|
+
if @outstanding_limit_cond
|
|
2485
|
+
@unconfirmed_set_mutex.synchronize { @outstanding_limit_cond.broadcast }
|
|
2020
2486
|
end
|
|
2021
2487
|
|
|
2022
|
-
|
|
2488
|
+
reset_continuations
|
|
2023
2489
|
end
|
|
2024
2490
|
|
|
2025
2491
|
# Starts consumer work pool. Lazily called by #basic_consume to avoid creating new threads
|
|
@@ -2049,39 +2515,167 @@ module Bunny
|
|
|
2049
2515
|
@connection.read_next_frame(options = {})
|
|
2050
2516
|
end
|
|
2051
2517
|
|
|
2518
|
+
# @param [String] name
|
|
2519
|
+
# @private
|
|
2520
|
+
def find_queue(name)
|
|
2521
|
+
@queue_mutex.synchronize { @queues[name] }
|
|
2522
|
+
end
|
|
2523
|
+
|
|
2524
|
+
# @param [String] name
|
|
2525
|
+
# @private
|
|
2526
|
+
def find_exchange(name)
|
|
2527
|
+
@exchange_mutex.synchronize { @exchanges[name] }
|
|
2528
|
+
end
|
|
2529
|
+
|
|
2530
|
+
# @param [Bunny::Queue] queue
|
|
2531
|
+
# @private
|
|
2532
|
+
def register_queue(queue)
|
|
2533
|
+
@queue_mutex.synchronize { @queues[queue.name] = queue }
|
|
2534
|
+
end
|
|
2535
|
+
|
|
2536
|
+
# @param [Bunny::Queue] queue
|
|
2052
2537
|
# @private
|
|
2053
2538
|
def deregister_queue(queue)
|
|
2054
2539
|
@queue_mutex.synchronize { @queues.delete(queue.name) }
|
|
2055
2540
|
end
|
|
2056
2541
|
|
|
2542
|
+
# @param [Bunny::String] name
|
|
2057
2543
|
# @private
|
|
2058
2544
|
def deregister_queue_named(name)
|
|
2059
2545
|
@queue_mutex.synchronize { @queues.delete(name) }
|
|
2060
2546
|
end
|
|
2061
2547
|
|
|
2548
|
+
# @param [Bunny::Queue] queue
|
|
2062
2549
|
# @private
|
|
2063
|
-
def
|
|
2064
|
-
@
|
|
2550
|
+
def record_queue(queue)
|
|
2551
|
+
@connection.record_queue(queue)
|
|
2065
2552
|
end
|
|
2066
2553
|
|
|
2554
|
+
# @param [Bunny::Channel] ch
|
|
2555
|
+
# @param [String] name
|
|
2556
|
+
# @param [Boolean] server_named
|
|
2557
|
+
# @param [Boolean] durable
|
|
2558
|
+
# @param [Boolean] auto_delete
|
|
2559
|
+
# @param [Boolean] exclusive
|
|
2560
|
+
# @param [Hash] arguments
|
|
2561
|
+
def record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
|
|
2562
|
+
@connection.record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
|
|
2563
|
+
end
|
|
2564
|
+
|
|
2565
|
+
# @param [Bunny::Queue, Bunny::RecordedQueue] queue
|
|
2067
2566
|
# @private
|
|
2068
|
-
def
|
|
2069
|
-
@
|
|
2567
|
+
def delete_recoreded_queue(queue)
|
|
2568
|
+
@connection.delete_recorded_queue(queue)
|
|
2070
2569
|
end
|
|
2071
2570
|
|
|
2571
|
+
# @param [String] name
|
|
2072
2572
|
# @private
|
|
2073
|
-
def
|
|
2074
|
-
@
|
|
2573
|
+
def delete_recorded_queue_named(name)
|
|
2574
|
+
@connection.delete_recorded_queue_named(name)
|
|
2075
2575
|
end
|
|
2076
2576
|
|
|
2577
|
+
# @param [Bunny::Exchange] exchange
|
|
2077
2578
|
# @private
|
|
2078
2579
|
def register_exchange(exchange)
|
|
2079
2580
|
@exchange_mutex.synchronize { @exchanges[exchange.name] = exchange }
|
|
2080
2581
|
end
|
|
2081
2582
|
|
|
2583
|
+
# @param [Bunny::Exchange] exchange
|
|
2082
2584
|
# @private
|
|
2083
|
-
def
|
|
2084
|
-
@
|
|
2585
|
+
def deregister_exchange(exchange)
|
|
2586
|
+
@queue_mutex.synchronize { @exchanges.delete(exchange.name) }
|
|
2587
|
+
end
|
|
2588
|
+
|
|
2589
|
+
# @param [String] name
|
|
2590
|
+
# @private
|
|
2591
|
+
def deregister_exchange_named(name)
|
|
2592
|
+
@queue_mutex.synchronize { @exchanges.delete(name) }
|
|
2593
|
+
end
|
|
2594
|
+
|
|
2595
|
+
# @param [Bunny::Exchange] exchange
|
|
2596
|
+
# @private
|
|
2597
|
+
def record_exchange(exchange)
|
|
2598
|
+
@connection.record_exchange(exchange)
|
|
2599
|
+
end
|
|
2600
|
+
|
|
2601
|
+
# @param [Bunny::Channel] ch
|
|
2602
|
+
# @param [String] name
|
|
2603
|
+
# @param [String] type
|
|
2604
|
+
# @param [Boolean] durable
|
|
2605
|
+
# @param [Boolean] auto_delete
|
|
2606
|
+
# @param [Hash] arguments
|
|
2607
|
+
def record_exchange_with(ch, name, type, durable, auto_delete, arguments)
|
|
2608
|
+
@connection.record_exchange_with(ch, name, type, durable, auto_delete, arguments)
|
|
2609
|
+
end
|
|
2610
|
+
|
|
2611
|
+
# @param [Bunny::Exchange] exchange
|
|
2612
|
+
# @private
|
|
2613
|
+
def delete_recorded_exchange(exchange)
|
|
2614
|
+
@connection.delete_recorded_exchange(exchange)
|
|
2615
|
+
end
|
|
2616
|
+
|
|
2617
|
+
# @param [String] name
|
|
2618
|
+
# @private
|
|
2619
|
+
def delete_recorded_exchange_named(name)
|
|
2620
|
+
@connection.delete_recorded_exchange_named(name)
|
|
2621
|
+
end
|
|
2622
|
+
|
|
2623
|
+
# @param [Bunny::Channel] ch
|
|
2624
|
+
# @param [String] exchange_name
|
|
2625
|
+
# @param [String] queue_name
|
|
2626
|
+
# @param [String] routing_key
|
|
2627
|
+
# @param [Hash] arguments
|
|
2628
|
+
# @private
|
|
2629
|
+
def record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2630
|
+
@connection.record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2631
|
+
end
|
|
2632
|
+
|
|
2633
|
+
# @param [Bunny::Channel] ch
|
|
2634
|
+
# @param [String] exchange_name
|
|
2635
|
+
# @param [String] queue_name
|
|
2636
|
+
# @param [String] routing_key
|
|
2637
|
+
# @param [Hash] arguments
|
|
2638
|
+
# @private
|
|
2639
|
+
def delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2640
|
+
@connection.delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
|
|
2641
|
+
end
|
|
2642
|
+
|
|
2643
|
+
# @param [Bunny::Channel] ch
|
|
2644
|
+
# @param [String] source_name
|
|
2645
|
+
# @param [String] destination_name
|
|
2646
|
+
# @param [String] routing_key
|
|
2647
|
+
# @param [Hash] arguments
|
|
2648
|
+
# @private
|
|
2649
|
+
def record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
|
|
2650
|
+
@connection.record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
|
|
2651
|
+
end
|
|
2652
|
+
|
|
2653
|
+
# @param [Bunny::Channel] ch
|
|
2654
|
+
# @param [String] source_name
|
|
2655
|
+
# @param [String] destination_name
|
|
2656
|
+
# @param [String] routing_key
|
|
2657
|
+
# @param [Hash] arguments
|
|
2658
|
+
# @private
|
|
2659
|
+
def delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
|
|
2660
|
+
@connection.delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
|
|
2661
|
+
end
|
|
2662
|
+
|
|
2663
|
+
# @param [Bunny::Channel] ch
|
|
2664
|
+
# @param [String] consumer_tag
|
|
2665
|
+
# @param [String] queue_name
|
|
2666
|
+
# @param [#call] callable
|
|
2667
|
+
# @param [Boolean] manual_ack
|
|
2668
|
+
# @param [Boolean] exclusive
|
|
2669
|
+
# @param [Hash] arguments
|
|
2670
|
+
# @private
|
|
2671
|
+
def record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
|
|
2672
|
+
@connection.record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
|
|
2673
|
+
end
|
|
2674
|
+
|
|
2675
|
+
# @param [String] consumer_tag
|
|
2676
|
+
# @private
|
|
2677
|
+
def delete_recorded_consumer(consumer_tag)
|
|
2678
|
+
@connection.delete_recorded_consumer(consumer_tag)
|
|
2085
2679
|
end
|
|
2086
2680
|
|
|
2087
2681
|
protected
|
|
@@ -2148,6 +2742,7 @@ module Bunny
|
|
|
2148
2742
|
@continuations = new_continuation
|
|
2149
2743
|
@confirms_continuations = new_continuation
|
|
2150
2744
|
@basic_get_continuations = new_continuation
|
|
2745
|
+
@per_message_continuations_mutex.synchronize { @per_message_continuations.clear }
|
|
2151
2746
|
end
|
|
2152
2747
|
|
|
2153
2748
|
# @private
|
|
@@ -2158,16 +2753,7 @@ module Bunny
|
|
|
2158
2753
|
# @private
|
|
2159
2754
|
def guarding_against_stale_delivery_tags(tag, &block)
|
|
2160
2755
|
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
|
|
2756
|
+
when Integer then block.call
|
|
2171
2757
|
end
|
|
2172
2758
|
end
|
|
2173
2759
|
end # Channel
|