bunny 2.23.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -36
  3. data/lib/amq/protocol/extensions.rb +2 -0
  4. data/lib/bunny/authentication/credentials_encoder.rb +2 -0
  5. data/lib/bunny/authentication/external_mechanism_encoder.rb +2 -0
  6. data/lib/bunny/authentication/plain_mechanism_encoder.rb +2 -0
  7. data/lib/bunny/channel.rb +778 -150
  8. data/lib/bunny/channel_id_allocator.rb +2 -0
  9. data/lib/bunny/concurrent/atomic_fixnum.rb +2 -0
  10. data/lib/bunny/concurrent/condition.rb +2 -0
  11. data/lib/bunny/concurrent/continuation_queue.rb +2 -0
  12. data/lib/bunny/concurrent/exception_accumulator.rb +115 -0
  13. data/lib/bunny/concurrent/synchronized_sorted_set.rb +2 -0
  14. data/lib/bunny/consumer.rb +4 -11
  15. data/lib/bunny/consumer_tag_generator.rb +2 -0
  16. data/lib/bunny/consumer_work_pool.rb +2 -0
  17. data/lib/bunny/cruby/socket.rb +36 -2
  18. data/lib/bunny/cruby/ssl_socket.rb +44 -1
  19. data/lib/bunny/delivery_info.rb +23 -15
  20. data/lib/bunny/exceptions.rb +33 -2
  21. data/lib/bunny/exchange.rb +27 -13
  22. data/lib/bunny/framing.rb +2 -0
  23. data/lib/bunny/get_response.rb +20 -14
  24. data/lib/bunny/heartbeat_sender.rb +4 -2
  25. data/lib/bunny/message_properties.rb +2 -0
  26. data/lib/bunny/queue.rb +31 -39
  27. data/lib/bunny/reader_loop.rb +9 -7
  28. data/lib/bunny/return_info.rb +18 -11
  29. data/lib/bunny/session.rb +387 -63
  30. data/lib/bunny/socket.rb +7 -12
  31. data/lib/bunny/ssl_socket.rb +7 -12
  32. data/lib/bunny/test_kit.rb +1 -0
  33. data/lib/bunny/timeout.rb +2 -0
  34. data/lib/bunny/timestamp.rb +3 -1
  35. data/lib/bunny/topology_recovery_filter.rb +71 -0
  36. data/lib/bunny/topology_registry.rb +824 -0
  37. data/lib/bunny/transport.rb +54 -49
  38. data/lib/bunny/version.rb +2 -1
  39. data/lib/bunny.rb +2 -1
  40. metadata +25 -14
  41. data/lib/bunny/concurrent/linked_continuation_queue.rb +0 -61
  42. data/lib/bunny/jruby/socket.rb +0 -57
  43. data/lib/bunny/jruby/ssl_socket.rb +0 -58
  44. data/lib/bunny/versioned_delivery_tag.rb +0 -28
data/lib/bunny/queue.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bunny/get_response"
2
4
 
3
5
  module Bunny
@@ -15,8 +17,10 @@ module Bunny
15
17
  QUORUM = "quorum"
16
18
  CLASSIC = "classic"
17
19
  STREAM = "stream"
20
+ DELAYED = "delayed"
21
+ JMS = "jms"
18
22
 
19
- KNOWN = [CLASSIC, QUORUM, STREAM]
23
+ KNOWN = [CLASSIC, QUORUM, STREAM, DELAYED, JMS]
20
24
 
21
25
  def self.known?(q_type)
22
26
  KNOWN.include?(q_type)
@@ -26,6 +30,13 @@ module Bunny
26
30
  module XArgs
27
31
  MAX_LENGTH = "x-max-length",
28
32
  QUEUE_TYPE = "x-queue-type"
33
+
34
+ DELAYED_RETRY_TYPE = "x-delayed-retry-type"
35
+ DELAYED_RETRY_MIN = "x-delayed-retry-min"
36
+ DELAYED_RETRY_MAX = "x-delayed-retry-max"
37
+
38
+ SELECTOR_FIELDS = "x-selector-fields"
39
+ SELECTOR_FIELD_MAX_BYTES = "x-selector-field-max-bytes"
29
40
  end
30
41
 
31
42
  # @return [Bunny::Channel] Channel this queue uses
@@ -42,7 +53,7 @@ module Bunny
42
53
  # @option opts [Boolean] :durable (false) Should this queue be durable?
43
54
  # @option opts [Boolean] :auto_delete (false) Should this queue be automatically deleted when the last consumer disconnects?
44
55
  # @option opts [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
45
- # @option opts [String] :type (nil) Type of the declared queue (classic, quorum or stream)
56
+ # @option opts [String] :type (nil) Type of the declared queue (classic, quorum, stream, delayed, or jms)
46
57
  # @option opts [Hash] :arguments (nil) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
47
58
  #
48
59
  # @see Bunny::Channel#queue
@@ -78,7 +89,10 @@ module Bunny
78
89
 
79
90
  declare! unless opts[:no_declare]
80
91
 
92
+ # for basic.deliver dispatch and such
81
93
  @channel.register_queue(self)
94
+ # for topology recovery
95
+ @channel.record_queue(self)
82
96
  end
83
97
 
84
98
  # @return [Boolean] true if this queue was declared as durable (will survive broker restart).
@@ -115,6 +129,13 @@ module Bunny
115
129
  @arguments
116
130
  end
117
131
 
132
+ # @param value [String]
133
+ # @private
134
+ def update_name_to(value)
135
+ @name = value
136
+ self
137
+ end
138
+
118
139
  def to_s
119
140
  oid = ("0x%x" % (self.object_id << 1))
120
141
  "<#{self.class.name}:#{oid} @name=\"#{name}\" channel=#{@channel.to_s} @durable=#{@durable} @auto_delete=#{@auto_delete} @exclusive=#{@exclusive} @arguments=#{@arguments}>"
@@ -318,6 +339,7 @@ module Bunny
318
339
  # @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
319
340
  # @api public
320
341
  def delete(opts = {})
342
+ @channel.delete_recorded_queue_named(self.name)
321
343
  @channel.deregister_queue(self)
322
344
  @channel.queue_delete(@name, opts)
323
345
  end
@@ -352,42 +374,14 @@ module Bunny
352
374
  s[:consumer_count]
353
375
  end
354
376
 
355
- #
356
- # Recovery
357
- #
358
-
359
- # @private
360
- def recover_from_network_failure
361
- if self.server_named?
362
- old_name = @name.dup
363
- @name = AMQ::Protocol::EMPTY_STRING
364
-
365
- @channel.deregister_queue_named(old_name)
366
- end
367
-
368
- # TODO: inject and use logger
369
- # puts "Recovering queue #{@name}"
370
- begin
371
- declare! unless @options[:no_declare]
372
-
373
- @channel.register_queue(self)
374
- rescue Exception => e
375
- # TODO: inject and use logger
376
- puts "Caught #{e.inspect} while redeclaring and registering #{@name}!"
377
- end
378
- recover_bindings
379
- end
380
-
381
- # @private
382
- def recover_bindings
383
- @bindings.each do |b|
384
- # TODO: inject and use logger
385
- # puts "Recovering binding #{b.inspect}"
386
- self.bind(b[:exchange], b)
387
- end
377
+ def self.verify_type!(args0 = {})
378
+ # be extra defensive
379
+ args = args0 || {}
380
+ q_type = args["x-queue-type"] || args[:"x-queue-type"]
381
+ throw ArgumentError.new(
382
+ "unsupported queue type #{q_type.inspect}, supported ones: #{Types::KNOWN.join(', ')}") if (q_type and !Types.known?(q_type))
388
383
  end
389
384
 
390
-
391
385
  #
392
386
  # Implementation
393
387
  #
@@ -419,9 +413,7 @@ module Bunny
419
413
  end
420
414
 
421
415
  def verify_type!(args)
422
- q_type = (args || {})["x-queue-type"]
423
- throw ArgumentError.new(
424
- "unsupported queue type #{q_type.inspect}, supported ones: #{Types::KNOWN.join(', ')}") if (q_type and !Types.known?(q_type))
416
+ self.class.verify_type!(args)
425
417
  end
426
418
  end
427
419
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
 
3
5
  module Bunny
@@ -41,9 +43,13 @@ module Bunny
41
43
  OpenSSL::OpenSSLError => e
42
44
  break if terminate? || @session.closing? || @session.closed?
43
45
 
44
- @network_is_down = true
46
+ @mutex.synchronize do
47
+ @stopping = true
48
+ @network_is_down = true
49
+ end
50
+
45
51
  if @session.automatically_recover?
46
- log_exception(e, level: :warn)
52
+ log_exception(e, level: :debug)
47
53
  @session.handle_network_failure(e)
48
54
  else
49
55
  log_exception(e)
@@ -60,10 +66,6 @@ module Bunny
60
66
  @network_is_down = true
61
67
  @session_error_handler.raise(Bunny::NetworkFailure.new("caught an unexpected exception in the network loop: #{e.message}", e))
62
68
  end
63
- rescue Errno::EBADF => _ebadf
64
- break if terminate?
65
- # ignored, happens when we loop after the transport has already been closed
66
- @mutex.synchronize { @stopping = true }
67
69
  end
68
70
  end
69
71
 
@@ -76,7 +78,7 @@ module Bunny
76
78
 
77
79
  if !frame.final? || frame.method_class.has_content?
78
80
  header = @transport.read_next_frame
79
- content = ''
81
+ content = +''
80
82
 
81
83
  if header.body_size > 0
82
84
  loop do
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Wraps AMQ::Protocol::Basic::Return to
3
- # provide access to the delivery properties as immutable hash as
4
- # well as methods.
5
+ # provide access to the return properties as immutable hash as
6
+ # well as methods. Hash representation is created lazily.
5
7
  class ReturnInfo
6
8
 
7
9
  #
@@ -16,29 +18,34 @@ module Bunny
16
18
 
17
19
  def initialize(basic_return)
18
20
  @basic_return = basic_return
19
- @hash = {
20
- :reply_code => basic_return.reply_code,
21
- :reply_text => basic_return.reply_text,
22
- :exchange => basic_return.exchange,
23
- :routing_key => basic_return.routing_key
24
- }
25
21
  end
26
22
 
27
23
  # Iterates over the returned delivery properties
28
24
  # @see Enumerable#each
29
25
  def each(*args, &block)
30
- @hash.each(*args, &block)
26
+ to_hash.each(*args, &block)
31
27
  end
32
28
 
33
29
  # Accesses returned delivery properties by key
34
30
  # @see Hash#[]
35
31
  def [](k)
36
- @hash[k]
32
+ case k
33
+ when :reply_code then @basic_return.reply_code
34
+ when :reply_text then @basic_return.reply_text
35
+ when :exchange then @basic_return.exchange
36
+ when :routing_key then @basic_return.routing_key
37
+ else nil
38
+ end
37
39
  end
38
40
 
39
41
  # @return [Hash] Hash representation of this returned delivery info
40
42
  def to_hash
41
- @hash
43
+ @hash ||= {
44
+ :reply_code => @basic_return.reply_code,
45
+ :reply_text => @basic_return.reply_text,
46
+ :exchange => @basic_return.exchange,
47
+ :routing_key => @basic_return.routing_key
48
+ }
42
49
  end
43
50
 
44
51
  # @private