bunny 2.19.0 → 2.20.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -32
  3. data/lib/bunny/channel.rb +86 -10
  4. data/lib/bunny/consumer.rb +2 -2
  5. data/lib/bunny/delivery_info.rb +1 -1
  6. data/lib/bunny/queue.rb +36 -2
  7. data/lib/bunny/session.rb +7 -3
  8. data/lib/bunny/transport.rb +37 -1
  9. data/lib/bunny/version.rb +1 -1
  10. data/lib/bunny.rb +45 -4
  11. metadata +5 -145
  12. data/spec/config/enabled_plugins +0 -1
  13. data/spec/config/rabbitmq.conf +0 -13
  14. data/spec/higher_level_api/integration/basic_ack_spec.rb +0 -230
  15. data/spec/higher_level_api/integration/basic_cancel_spec.rb +0 -142
  16. data/spec/higher_level_api/integration/basic_consume_spec.rb +0 -357
  17. data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +0 -54
  18. data/spec/higher_level_api/integration/basic_get_spec.rb +0 -80
  19. data/spec/higher_level_api/integration/basic_nack_spec.rb +0 -82
  20. data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -74
  21. data/spec/higher_level_api/integration/basic_qos_spec.rb +0 -57
  22. data/spec/higher_level_api/integration/basic_reject_spec.rb +0 -152
  23. data/spec/higher_level_api/integration/basic_return_spec.rb +0 -33
  24. data/spec/higher_level_api/integration/channel_close_spec.rb +0 -66
  25. data/spec/higher_level_api/integration/channel_open_spec.rb +0 -57
  26. data/spec/higher_level_api/integration/connection_recovery_spec.rb +0 -483
  27. data/spec/higher_level_api/integration/connection_spec.rb +0 -589
  28. data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -83
  29. data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +0 -128
  30. data/spec/higher_level_api/integration/dead_lettering_spec.rb +0 -75
  31. data/spec/higher_level_api/integration/exchange_bind_spec.rb +0 -31
  32. data/spec/higher_level_api/integration/exchange_declare_spec.rb +0 -237
  33. data/spec/higher_level_api/integration/exchange_delete_spec.rb +0 -105
  34. data/spec/higher_level_api/integration/exchange_unbind_spec.rb +0 -40
  35. data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
  36. data/spec/higher_level_api/integration/heartbeat_spec.rb +0 -49
  37. data/spec/higher_level_api/integration/message_properties_access_spec.rb +0 -95
  38. data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +0 -24
  39. data/spec/higher_level_api/integration/publisher_confirms_spec.rb +0 -191
  40. data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +0 -87
  41. data/spec/higher_level_api/integration/queue_bind_spec.rb +0 -109
  42. data/spec/higher_level_api/integration/queue_declare_spec.rb +0 -285
  43. data/spec/higher_level_api/integration/queue_delete_spec.rb +0 -41
  44. data/spec/higher_level_api/integration/queue_purge_spec.rb +0 -30
  45. data/spec/higher_level_api/integration/queue_unbind_spec.rb +0 -54
  46. data/spec/higher_level_api/integration/read_only_consumer_spec.rb +0 -60
  47. data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +0 -36
  48. data/spec/higher_level_api/integration/tls_connection_spec.rb +0 -255
  49. data/spec/higher_level_api/integration/toxiproxy_spec.rb +0 -76
  50. data/spec/higher_level_api/integration/tx_commit_spec.rb +0 -21
  51. data/spec/higher_level_api/integration/tx_rollback_spec.rb +0 -21
  52. data/spec/higher_level_api/integration/with_channel_spec.rb +0 -25
  53. data/spec/issues/issue100_spec.rb +0 -42
  54. data/spec/issues/issue141_spec.rb +0 -43
  55. data/spec/issues/issue202_spec.rb +0 -15
  56. data/spec/issues/issue224_spec.rb +0 -40
  57. data/spec/issues/issue465_spec.rb +0 -32
  58. data/spec/issues/issue549_spec.rb +0 -30
  59. data/spec/issues/issue609_spec.rb +0 -84
  60. data/spec/issues/issue78_spec.rb +0 -72
  61. data/spec/issues/issue83_spec.rb +0 -30
  62. data/spec/issues/issue97_attachment.json +0 -1
  63. data/spec/issues/issue97_spec.rb +0 -175
  64. data/spec/lower_level_api/integration/basic_cancel_spec.rb +0 -83
  65. data/spec/lower_level_api/integration/basic_consume_spec.rb +0 -99
  66. data/spec/spec_helper.rb +0 -47
  67. data/spec/stress/channel_close_stress_spec.rb +0 -64
  68. data/spec/stress/channel_open_stress_spec.rb +0 -84
  69. data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -28
  70. data/spec/stress/concurrent_consumers_stress_spec.rb +0 -71
  71. data/spec/stress/concurrent_publishers_stress_spec.rb +0 -54
  72. data/spec/stress/connection_open_close_spec.rb +0 -52
  73. data/spec/stress/merry_go_round_spec.rb +0 -105
  74. data/spec/toxiproxy_helper.rb +0 -28
  75. data/spec/unit/bunny_spec.rb +0 -15
  76. data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
  77. data/spec/unit/concurrent/condition_spec.rb +0 -82
  78. data/spec/unit/concurrent/linked_continuation_queue_spec.rb +0 -35
  79. data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
  80. data/spec/unit/exchange_recovery_spec.rb +0 -39
  81. data/spec/unit/version_delivery_tag_spec.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6de535f1d386dbf46fd89a733c1c44915280af55c3cc3cc56467abe0ead9c24
4
- data.tar.gz: 6048aea84078fb8995718ed774d9a3956dc91645b24c09382cd54283b444aabe
3
+ metadata.gz: '0638b435d0f724c5b9566797df9ba50e94144f0bb82f60b01e5d794bce868512'
4
+ data.tar.gz: c278e7122a90653738ff68b845509873ed0e7ca7b5759e0a33a7157725bcf650
5
5
  SHA512:
6
- metadata.gz: b3575710f81dabf6c116c92c4ac1807a29f0c0bcd1bd5fb35ae1fd9dd468df193efac49d0ad5e77ef04ecc53e97b9b4e13e70f4207972ba0c2335c28afcd6c9b
7
- data.tar.gz: 8b90dd4da7dab28b529e78cf1282656ca1904432b1017ee5574545c1972315f975d175c718481372604b61796e9ae56b293a342dcba800fa0929e4b80cd7a3c4
6
+ metadata.gz: 44e1c56c0500d2e375a22e6349401e25d9e1c8f9e553b91df0ed4ac07ee80167cd50e28f6191e549961a31c7795e07a740949b72c971178b2f35060a221cc312
7
+ data.tar.gz: c0cbd8f1d0d6b6973f6ba6e3cc6140dbaa6843fe18cb00372e5b3a01bbdad5f1c265867b8314937ed711671266fb14fb281bbf739b2510a91fad4404b6ba4042
data/README.md CHANGED
@@ -7,7 +7,7 @@ have any heavyweight dependencies.
7
7
 
8
8
  ## I Know What RabbitMQ and Bunny are, How Do I Get Started?
9
9
 
10
- [Right here](http://rubybunny.info/articles/getting_started.html)!
10
+ [Right here](https://www.rabbitmq.com/getstarted.html)!
11
11
 
12
12
 
13
13
  ## What is Bunny Good For?
@@ -47,7 +47,13 @@ Specific examples:
47
47
 
48
48
  Modern Bunny versions support
49
49
 
50
- * CRuby 2.5 through 3.0 (inclusive)
50
+ * CRuby 2.6 through 3.1 (inclusive)
51
+ * [TruffleRuby](https://www.graalvm.org/ruby/)
52
+
53
+ For environments that use TLS, Bunny expects Ruby installations to use a recent enough OpenSSL version that
54
+ **includes support for TLS 1.3**.
55
+
56
+ ### JRuby
51
57
 
52
58
  Bunny works sufficiently well on JRuby but there are known
53
59
  JRuby bugs in versions prior to JRuby 9000 that cause high CPU burn. JRuby users should
@@ -58,8 +64,7 @@ Bunny `1.7.x` was the last version to support CRuby 1.9.3 and 1.8.7
58
64
 
59
65
  ## Supported RabbitMQ Versions
60
66
 
61
- Bunny `1.5.0` and later versions only support RabbitMQ `3.3+`.
62
- Bunny `1.4.x` and earlier supports RabbitMQ 2.x and 3.x.
67
+ Modern Bunny releases target [currently supported RabbitMQ release series](https://www.rabbitmq.com/versions.html).
63
68
 
64
69
 
65
70
  ## Change Log
@@ -69,9 +74,8 @@ a stable public API.
69
74
 
70
75
  Change logs per release series:
71
76
 
72
- * [master](https://github.com/ruby-amqp/bunny/blob/master/ChangeLog.md)
73
- * [2.18.x](https://github.com/ruby-amqp/bunny/blob/2.18.x-stable/ChangeLog.md)
74
- * [2.17.x](https://github.com/ruby-amqp/bunny/blob/2.17.x-stable/ChangeLog.md)
77
+ * [main](https://github.com/ruby-amqp/bunny/blob/main/ChangeLog.md) (most notable changes for all release series)
78
+ * [2.19.x](https://github.com/ruby-amqp/bunny/blob/2.19.x-stable/ChangeLog.md)
75
79
 
76
80
 
77
81
 
@@ -81,20 +85,20 @@ Change logs per release series:
81
85
 
82
86
  [![Gem Version](https://badge.fury.io/rb/bunny.svg)](http://badge.fury.io/rb/bunny)
83
87
 
84
- ### With Rubygems
88
+ ### Bundler Dependency
85
89
 
86
- To install Bunny with RubyGems:
90
+ To use Bunny in a project managed with Bundler:
87
91
 
88
- ```
89
- gem install bunny
92
+ ``` ruby
93
+ gem "bunny", ">= 2.19.0"
90
94
  ```
91
95
 
92
- ### Bundler Dependency
96
+ ### With Rubygems
93
97
 
94
- To use Bunny in a project managed with Bundler:
98
+ To install Bunny with RubyGems:
95
99
 
96
- ``` ruby
97
- gem "bunny", ">= 2.18.0"
100
+ ```
101
+ gem install bunny
98
102
  ```
99
103
 
100
104
 
@@ -103,7 +107,7 @@ gem "bunny", ">= 2.18.0"
103
107
  Below is a small snippet that demonstrates how to publish
104
108
  and synchronously consume ("pull API") messages with Bunny.
105
109
 
106
- For a 15 minute tutorial using more practical examples, see [Getting Started with RabbitMQ and Ruby using Bunny](http://rubybunny.info/articles/getting_started.html).
110
+ For a 15 minute tutorial using more practical examples, see [Getting Started with RabbitMQ and Ruby using Bunny](https://www.rabbitmq.com/tutorials/tutorial-one-ruby.html).
107
111
 
108
112
  ``` ruby
109
113
  require "bunny"
@@ -150,23 +154,25 @@ For a 15 minute tutorial using more practical examples, see [Getting Started wit
150
154
 
151
155
  ### Guides
152
156
 
153
- Bunny documentation guides are available at [rubybunny.info](http://rubybunny.info):
157
+ Bunny documentation guides are [under `docs/guides` in this repository](https://github.com/ruby-amqp/bunny/tree/main/docs/guides):
154
158
 
155
- * [Queues and Consumers](http://rubybunny.info/articles/queues.html)
156
- * [Exchanges and Publishers](http://rubybunny.info/articles/exchanges.html)
159
+ * [Queues and Consumers](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/queues.md)
160
+ * [Exchanges and Publishers](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/exchanges.md)
157
161
  * [AMQP 0.9.1 Model Explained](http://www.rabbitmq.com/tutorials/amqp-concepts.html)
158
- * [Connecting to RabbitMQ](http://rubybunny.info/articles/connecting.html)
159
- * [Error Handling and Recovery](http://rubybunny.info/articles/error_handling.html)
160
- * [TLS/SSL Support](http://rubybunny.info/articles/tls.html)
161
- * [Bindings](http://rubybunny.info/articles/bindings.html)
162
- * [Using RabbitMQ Extensions with Bunny](http://rubybunny.info/articles/extensions.html)
163
- * [Durability and Related Matters](http://rubybunny.info/articles/durability.html)
162
+ * [Connecting to RabbitMQ](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/connecting.md)
163
+ * [Error Handling and Recovery](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/error_handling.md)
164
+ * [TLS/SSL Support](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/tls.md)
165
+ * [Bindings](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/bindings.md)
166
+ * [Using RabbitMQ Extensions with Bunny](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/extensions.md)
167
+ * [Durability and Related Matters](https://github.com/ruby-amqp/bunny/tree/main/docs/guides/durability.md)
164
168
 
165
169
  Some highly relevant RabbitMQ documentation guides:
166
170
 
167
171
  * [Connections](https://www.rabbitmq.com/connections.html)
168
172
  * [Channels](https://www.rabbitmq.com/channels.html)
169
173
  * [Queues](https://www.rabbitmq.com/queues.html)
174
+ * [Quorum queues](https://www.rabbitmq.com/quorum-queues.html)
175
+ * [Streams](https://rabbitmq.com/streams.html) (Bunny can perform basic operations on streams even though it does not implement the [RabbitMQ Stream protocol](https://github.com/rabbitmq/rabbitmq-server/blob/v3.10.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc))
170
176
  * [Publishers](https://www.rabbitmq.com/publishers.html)
171
177
  * [Consumers](https://www.rabbitmq.com/consumers.html)
172
178
  * Data safety: publisher and consumer [Confirmations](https://www.rabbitmq.com/confirms.html)
@@ -194,13 +200,6 @@ mailing list. Feel free to ask any questions that you may have.
194
200
  [![Build Status](https://travis-ci.org/ruby-amqp/bunny.svg)](https://travis-ci.org/ruby-amqp/bunny/)
195
201
 
196
202
 
197
- ### News & Announcements on Twitter
198
-
199
- To subscribe for announcements of releases, important changes and so on, please follow [@rubyamqp](https://twitter.com/#!/rubyamqp) on Twitter.
200
-
201
- More detailed announcements can be found in the [RabbitMQ Ruby clients blog](http://blog.rubyrabbitmq.info).
202
-
203
-
204
203
  ### Reporting Issues
205
204
 
206
205
  If you find a bug you understand well, poor default, incorrect or unclear piece of documentation,
data/lib/bunny/channel.rb CHANGED
@@ -143,6 +143,10 @@ module Bunny
143
143
  attr_reader :work_pool
144
144
  # @return [Integer] Next publisher confirmations sequence index
145
145
  attr_reader :next_publish_seq_no
146
+ # @return [Integer] Offset for the confirmations sequence index.
147
+ # This will be set to the current sequence index during automatic network failure recovery
148
+ # to keep the sequence monotonic for the user and abstract the reset from the protocol
149
+ attr_reader :delivery_tag_offset
146
150
  # @return [Hash<String, Bunny::Queue>] Queue instances declared on this channel
147
151
  attr_reader :queues
148
152
  # @return [Hash<String, Bunny::Exchange>] Exchange instances declared on this channel
@@ -408,7 +412,7 @@ module Bunny
408
412
  # @option opts [Boolean] :durable (false) Should this queue be durable?
409
413
  # @option opts [Boolean] :auto-delete (false) Should this queue be automatically deleted when the last consumer disconnects?
410
414
  # @option opts [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
411
- # @option opts [Boolean] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
415
+ # @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
412
416
  #
413
417
  # @return [Bunny::Queue] Queue that was declared or looked up in the cache
414
418
  # @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
@@ -422,6 +426,73 @@ module Bunny
422
426
  register_queue(q)
423
427
  end
424
428
 
429
+ # Declares a new client-named quorum queue.
430
+ #
431
+ # @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
432
+ # @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
433
+ #
434
+ # @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
435
+ #
436
+ # @return [Bunny::Queue] Queue that was declared
437
+ # @see #durable_queue
438
+ # @see #queue
439
+ # @api public
440
+ def quorum_queue(name, opts = {})
441
+ throw ArgumentError.new("quorum queue name must not be nil") if name.nil?
442
+ throw ArgumentError.new("quorum queue name must not be empty (server-named QQs do not make sense)") if name.empty?
443
+
444
+ durable_queue(name, Bunny::Queue::Types::QUORUM, opts)
445
+ end
446
+
447
+ # Declares a new client-named stream (that Bunny can use as if it was a queue).
448
+ # Note that Bunny would still use AMQP 0-9-1 to perform operations on this "queue".
449
+ # To use stream-specific operations and to gain from stream protocol efficiency and partitioning,
450
+ # use a Ruby client for the RabbitMQ stream protocol.
451
+ #
452
+ # @param [String] name Stream name. Empty (server-generated) names are not supported by this method.
453
+ # @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
454
+ #
455
+ # @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
456
+ #
457
+ #
458
+ # @return [Bunny::Queue] Queue that was declared
459
+ # @see #durable_queue
460
+ # @see #queue
461
+ # @api public
462
+ def stream(name, opts = {})
463
+ throw ArgumentError.new("stream name must not be nil") if name.nil?
464
+ throw ArgumentError.new("stream name must not be empty (server-named QQs do not make sense)") if name.empty?
465
+
466
+ durable_queue(name, Bunny::Queue::Types::STREAM, opts)
467
+ end
468
+
469
+ # Declares a new server-named queue that is automatically deleted when the
470
+ # connection is closed.
471
+ #
472
+ # @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
473
+ # @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
474
+ #
475
+ # @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
476
+ #
477
+ # @return [Bunny::Queue] Queue that was declared
478
+ # @see #queue
479
+ # @api public
480
+ def durable_queue(name, type = "classic", opts = {})
481
+ throw ArgumentError.new("queue name must not be nil") if name.nil?
482
+ throw ArgumentError.new("queue name must not be empty (server-named durable queues do not make sense)") if name.empty?
483
+
484
+ final_opts = opts.merge({
485
+ :type => type,
486
+ :durable => true,
487
+ # exclusive or auto-delete QQs do not make much sense
488
+ :exclusive => false,
489
+ :auto_delete => false
490
+ })
491
+ q = find_queue(name) || Bunny::Queue.new(self, name, final_opts)
492
+
493
+ register_queue(q)
494
+ end
495
+
425
496
  # Declares a new server-named queue that is automatically deleted when the
426
497
  # connection is closed.
427
498
  #
@@ -1525,12 +1596,15 @@ module Bunny
1525
1596
 
1526
1597
  # Recovers publisher confirms mode. Used by the Automatic Network Failure
1527
1598
  # Recovery feature.
1599
+ # Set the offset to the previous publish sequence index as the protocol will reset the index to after recovery.
1528
1600
  #
1529
1601
  # @api plugin
1530
1602
  def recover_confirm_mode
1531
1603
  if using_publisher_confirmations?
1532
- @unconfirmed_set.clear
1533
- @delivery_tag_offset = @next_publish_seq_no - 1
1604
+ @unconfirmed_set_mutex.synchronize do
1605
+ @unconfirmed_set.clear
1606
+ @delivery_tag_offset = @next_publish_seq_no - 1
1607
+ end
1534
1608
  confirm_select(@confirms_callback)
1535
1609
  end
1536
1610
  end
@@ -1599,7 +1673,7 @@ module Bunny
1599
1673
 
1600
1674
  # @return [String] Brief human-readable representation of the channel
1601
1675
  def to_s
1602
- "#<#{self.class.name}:#{object_id} @id=#{self.number} @connection=#{@connection.to_s}> @open=#{open?}"
1676
+ "#<#{self.class.name}:#{object_id} @id=#{self.number} @connection=#{@connection.to_s} @open=#{open?}>"
1603
1677
  end
1604
1678
 
1605
1679
  def inspect
@@ -1663,7 +1737,7 @@ module Bunny
1663
1737
  if !pending_server_named_queue_declaration?
1664
1738
  # this response is for an outdated/overwritten
1665
1739
  # queue.declare, drop it
1666
- @logger.warn "Received a queue.declare-ok response for a mismatching queue (#{method.queue} instead of #{@pending_queue_declare_name}) on channel #{@id} possibly due to a timeout, ignoring it"
1740
+ @logger.warn "Received a queue.declare-ok response for a mismatching queue (#{method.queue} instead of #{@pending_queue_declare_name}) on channel #{@id}, possibly due to concurrent channel use or a timeout, ignoring it"
1667
1741
  end
1668
1742
  end
1669
1743
  when AMQ::Protocol::Queue::DeleteOk then
@@ -1786,14 +1860,16 @@ module Bunny
1786
1860
  end
1787
1861
  end
1788
1862
 
1863
+ # Handle delivery tag offset calculations to keep the the delivery tag monotonic after a reset
1864
+ # due to automatic network failure recovery. @unconfirmed_set contains indices already offsetted.
1789
1865
  # @private
1790
1866
  def handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
1791
- delivery_tag = delivery_tag_before_offset + @delivery_tag_offset
1792
- confirmed_range_start = multiple ? @delivery_tag_offset + @unconfirmed_set.min : delivery_tag
1793
- confirmed_range_end = delivery_tag
1794
- confirmed_range = (confirmed_range_start..confirmed_range_end)
1795
-
1796
1867
  @unconfirmed_set_mutex.synchronize do
1868
+ delivery_tag = delivery_tag_before_offset + @delivery_tag_offset
1869
+ confirmed_range_start = multiple ? @unconfirmed_set.min : delivery_tag
1870
+ confirmed_range_end = delivery_tag
1871
+ confirmed_range = (confirmed_range_start..confirmed_range_end)
1872
+
1797
1873
  if nack
1798
1874
  @nacked_set.merge(@unconfirmed_set & confirmed_range)
1799
1875
  end
@@ -86,12 +86,12 @@ module Bunny
86
86
 
87
87
  # @return [String] More detailed human-readable string representation of this consumer
88
88
  def inspect
89
- "#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}> @consumer_tag=#{@consumer_tag} @exclusive=#{@exclusive} @no_ack=#{@no_ack}>"
89
+ "#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name} @consumer_tag=#{@consumer_tag} @exclusive=#{@exclusive} @no_ack=#{@no_ack}>"
90
90
  end
91
91
 
92
92
  # @return [String] Brief human-readable string representation of this consumer
93
93
  def to_s
94
- "#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}> @consumer_tag=#{@consumer_tag}>"
94
+ "#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name} @consumer_tag=#{@consumer_tag}>"
95
95
  end
96
96
 
97
97
  # @return [Boolean] true if this consumer uses automatic acknowledgement mode
@@ -37,7 +37,7 @@ module Bunny
37
37
  @channel = channel
38
38
  end
39
39
 
40
- # Iterates over the delivery properties
40
+ # Iterates over delivery properties
41
41
  # @see Enumerable#each
42
42
  def each(*args, &block)
43
43
  @hash.each(*args, &block)
data/lib/bunny/queue.rb CHANGED
@@ -11,6 +11,23 @@ module Bunny
11
11
  # API
12
12
  #
13
13
 
14
+ module Types
15
+ QUORUM = "quorum"
16
+ CLASSIC = "classic"
17
+ STREAM = "stream"
18
+
19
+ KNOWN = [CLASSIC, QUORUM, STREAM]
20
+
21
+ def self.known?(q_type)
22
+ KNOWN.include?(q_type)
23
+ end
24
+ end
25
+
26
+ module XArgs
27
+ MAX_LENGTH = "x-max-length",
28
+ QUEUE_TYPE = "x-queue-type"
29
+ end
30
+
14
31
  # @return [Bunny::Channel] Channel this queue uses
15
32
  attr_reader :channel
16
33
  # @return [String] Queue name
@@ -25,7 +42,8 @@ module Bunny
25
42
  # @option opts [Boolean] :durable (false) Should this queue be durable?
26
43
  # @option opts [Boolean] :auto_delete (false) Should this queue be automatically deleted when the last consumer disconnects?
27
44
  # @option opts [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
28
- # @option opts [Boolean] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
45
+ # @option opts [String] :type (nil) Type of the declared queue (classic, quorum or stream)
46
+ # @option opts [Hash] :arguments (nil) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
29
47
  #
30
48
  # @see Bunny::Channel#queue
31
49
  # @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
@@ -42,7 +60,17 @@ module Bunny
42
60
  @exclusive = @options[:exclusive]
43
61
  @server_named = @name.empty?
44
62
  @auto_delete = @options[:auto_delete]
45
- @arguments = @options[:arguments]
63
+ @type = @options[:type]
64
+
65
+ @arguments = if @type and !@type.empty? then
66
+ (@options[:arguments] || {}).merge({XArgs::QUEUE_TYPE => @type})
67
+ else
68
+ @options[:arguments]
69
+ end
70
+ verify_type!(@arguments)
71
+ # reassigns updated and verified arguments because Bunny::Channel#declare_queue
72
+ # accepts a map of options
73
+ @options[:arguments] = @arguments
46
74
 
47
75
  @bindings = Array.new
48
76
 
@@ -389,5 +417,11 @@ module Bunny
389
417
  h
390
418
  end
391
419
  end
420
+
421
+ 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))
425
+ end
392
426
  end
393
427
  end
data/lib/bunny/session.rb CHANGED
@@ -109,7 +109,7 @@ module Bunny
109
109
  # @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
110
110
  # @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
111
111
  # @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
112
- # @option connection_string_or_opts [Symbol] :tls_version (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
112
+ # @option connection_string_or_opts [Symbol] :tls_protocol (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
113
113
  # @option connection_string_or_opts [Integer] :channel_max (2047) Maximum number of channels allowed on this connection, minus 1 to account for the special channel 0.
114
114
  # @option connection_string_or_opts [Integer] :continuation_timeout (15000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
115
115
  # @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
@@ -671,8 +671,12 @@ module Bunny
671
671
  # avoid doing that while holding a mutex lock. MK.
672
672
  ch.handle_method(method)
673
673
  ensure
674
- # synchronises on @channel_mutex under the hood
675
- self.unregister_channel(ch)
674
+ if ch.nil?
675
+ @logger.warn "Received a server-sent channel.close but the channel was not found locally. Ignoring the frame."
676
+ else
677
+ # synchronises on @channel_mutex under the hood
678
+ self.unregister_channel(ch)
679
+ end
676
680
  end
677
681
  when AMQ::Protocol::Basic::GetEmpty then
678
682
  ch = find_channel(ch_number)
@@ -25,6 +25,30 @@ module Bunny
25
25
  DEFAULT_READ_TIMEOUT = 30.0
26
26
  DEFAULT_WRITE_TIMEOUT = 30.0
27
27
 
28
+ # mimics METHODS_MAP in ssl.rb but also lists TLS 1.3
29
+ # and string constants
30
+ TLS_VERSION_ALIASES = {
31
+ TLSv1: OpenSSL::SSL::TLS1_VERSION,
32
+ TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,
33
+ TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,
34
+ "1.0": OpenSSL::SSL::TLS1_VERSION,
35
+ "1.1": OpenSSL::SSL::TLS1_1_VERSION,
36
+ "1.2": OpenSSL::SSL::TLS1_2_VERSION,
37
+ OpenSSL::SSL::TLS1_VERSION => OpenSSL::SSL::TLS1_VERSION,
38
+ OpenSSL::SSL::TLS1_1_VERSION => OpenSSL::SSL::TLS1_1_VERSION,
39
+ OpenSSL::SSL::TLS1_2_VERSION => OpenSSL::SSL::TLS1_2_VERSION
40
+ }
41
+
42
+ # older OpenSSL versions won't support for TLS 1.3 and won't
43
+ # have this constant defined.
44
+ if defined?(OpenSSL::SSL::TLS1_3_VERSION)
45
+ TLS_VERSION_ALIASES["1.3"] = OpenSSL::SSL::TLS1_3_VERSION
46
+ TLS_VERSION_ALIASES[:TLSv1_3] = OpenSSL::SSL::TLS1_3_VERSION
47
+ TLS_VERSION_ALIASES[OpenSSL::SSL::TLS1_3_VERSION] = OpenSSL::SSL::TLS1_3_VERSION
48
+ end
49
+
50
+ TLS_VERSION_ALIASES.freeze
51
+
28
52
  attr_reader :session, :host, :port, :socket, :connect_timeout, :read_timeout, :write_timeout, :disconnect_timeout
29
53
  attr_reader :tls_context, :verify_peer, :tls_ca_certificates, :tls_certificate_path, :tls_key_path
30
54
 
@@ -491,7 +515,11 @@ but prone to man-in-the-middle attacks. Please set verify_peer: true in producti
491
515
  end
492
516
 
493
517
  ssl_version = opts[:tls_protocol] || opts[:ssl_version] || :TLSv1_2
494
- ctx.ssl_version = ssl_version if ssl_version
518
+ if ssl_version
519
+ v = tls_version_constant(ssl_version)
520
+ ctx.min_version = v
521
+ ctx.max_version = v
522
+ end
495
523
 
496
524
  ctx
497
525
  end
@@ -519,6 +547,14 @@ but prone to man-in-the-middle attacks. Please set verify_peer: true in producti
519
547
  end
520
548
  end
521
549
 
550
+
551
+ def tls_version_constant(value)
552
+ # OpenSSL::SSL::TLS1_3_VERSION and similar constants
553
+ # are just integers, so use the value itself as fallback since
554
+ # there is no class to case switch on
555
+ TLS_VERSION_ALIASES[value] || value
556
+ end
557
+
522
558
  def timeout_from(options)
523
559
  options[:connect_timeout] || options[:connection_timeout] || options[:timeout] || DEFAULT_CONNECTION_TIMEOUT
524
560
  end
data/lib/bunny/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Bunny
4
4
  # @return [String] Version of the library
5
- VERSION = "2.19.0"
5
+ VERSION = "2.20.3"
6
6
  end
data/lib/bunny.rb CHANGED
@@ -53,17 +53,58 @@ module Bunny
53
53
  # Instantiates a new connection. The actual network
54
54
  # connection is started with {Bunny::Session#start}
55
55
  #
56
+ # @param [String, Hash] connection_string_or_opts Connection string or a hash of connection options
57
+ # @param [Hash] optz Extra options not related to connection
58
+ #
59
+ # @option connection_string_or_opts [String] :host ("127.0.0.1") Hostname or IP address to connect to
60
+ # @option connection_string_or_opts [Array<String>] :hosts (["127.0.0.1"]) list of hostname or IP addresses to select hostname from when connecting
61
+ # @option connection_string_or_opts [Array<String>] :addresses (["127.0.0.1:5672"]) list of addresses to select hostname and port from when connecting
62
+ # @option connection_string_or_opts [Integer] :port (5672) Port RabbitMQ listens on
63
+ # @option connection_string_or_opts [String] :username ("guest") Username
64
+ # @option connection_string_or_opts [String] :password ("guest") Password
65
+ # @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
66
+ # @option connection_string_or_opts [Integer, Symbol] :heartbeat (:server) Heartbeat timeout to offer to the server. :server means use the value suggested by RabbitMQ. 0 means heartbeats and socket read timeouts will be disabled (not recommended).
67
+ # @option connection_string_or_opts [Integer] :network_recovery_interval (4) Recovery interval periodic network recovery will use. This includes initial pause after network failure.
68
+ # @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
69
+ # @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
70
+ # @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
71
+ # @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
72
+ # @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
73
+ # @option connection_string_or_opts [Symbol] :tls_protocol (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
74
+ # @option connection_string_or_opts [Integer] :channel_max (2047) Maximum number of channels allowed on this connection, minus 1 to account for the special channel 0.
75
+ # @option connection_string_or_opts [Integer] :continuation_timeout (15000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
76
+ # @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
77
+ # @option connection_string_or_opts [Integer] :read_timeout (30) TCP socket read timeout in seconds. If heartbeats are disabled this will be ignored.
78
+ # @option connection_string_or_opts [Integer] :write_timeout (30) TCP socket write timeout in seconds.
79
+ # @option connection_string_or_opts [Proc] :hosts_shuffle_strategy a callable that reorders a list of host strings, defaults to Array#shuffle
80
+ # @option connection_string_or_opts [Proc] :recovery_completed a callable that will be called when a network recovery is performed
81
+ # @option connection_string_or_opts [Logger] :logger The logger. If missing, one is created using :log_file and :log_level.
82
+ # @option connection_string_or_opts [IO, String] :log_file The file or path to use when creating a logger. Defaults to STDOUT.
83
+ # @option connection_string_or_opts [IO, String] :logfile DEPRECATED: use :log_file instead. The file or path to use when creating a logger. Defaults to STDOUT.
84
+ # @option connection_string_or_opts [Integer] :log_level The log level to use when creating a logger. Defaults to LOGGER::WARN
85
+ # @option connection_string_or_opts [Boolean] :automatically_recover (true) Should automatically recover from network failures?
86
+ # @option connection_string_or_opts [Integer] :recovery_attempts (nil) Max number of recovery attempts, nil means forever
87
+ # @option connection_string_or_opts [Integer] :reset_recovery_attempts_after_reconnection (true) Should recovery attempt counter be reset after successful reconnection? When set to false, the attempt counter will last through the entire lifetime of the connection object.
88
+ # @option connection_string_or_opts [Proc] :recovery_attempt_started (nil) Will be called before every connection recovery attempt
89
+ # @option connection_string_or_opts [Proc] :recovery_completed (nil) Will be called after successful connection recovery
90
+ # @option connection_string_or_opts [Boolean] :recover_from_connection_close (true) Should this connection recover after receiving a server-sent connection.close (e.g. connection was force closed)?
91
+ # @option connection_string_or_opts [Object] :session_error_handler (Thread.current) Object which responds to #raise that will act as a session error handler. Defaults to Thread.current, which will raise asynchronous exceptions in the thread that created the session.
92
+ #
93
+ # @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
94
+ # @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
95
+ # @option optz [String] :connection_name (nil) Client-provided connection name, if any. Note that the value returned does not uniquely identify a connection and cannot be used as a connection identifier in HTTP API requests.
96
+ #
56
97
  # @return [Bunny::Session]
57
98
  # @see Bunny::Session#start
58
99
  # @see http://rubybunny.info/articles/getting_started.html
59
100
  # @see http://rubybunny.info/articles/connecting.html
60
101
  # @api public
61
- def self.new(connection_string_or_opts = ENV['RABBITMQ_URL'], opts = {})
62
- if connection_string_or_opts.respond_to?(:keys) && opts.empty?
63
- opts = connection_string_or_opts
102
+ def self.new(connection_string_or_opts = ENV['RABBITMQ_URL'], optz = {})
103
+ if connection_string_or_opts.respond_to?(:keys) && optz.empty?
104
+ optz = connection_string_or_opts
64
105
  end
65
106
 
66
- conn = Session.new(connection_string_or_opts, opts)
107
+ conn = Session.new(connection_string_or_opts, optz)
67
108
  @default_connection ||= conn
68
109
 
69
110
  conn