bunny 2.19.0 → 2.22.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 +31 -32
- data/lib/bunny/channel.rb +88 -12
- data/lib/bunny/consumer.rb +2 -2
- data/lib/bunny/consumer_work_pool.rb +1 -1
- data/lib/bunny/delivery_info.rb +1 -1
- data/lib/bunny/queue.rb +36 -2
- data/lib/bunny/session.rb +39 -16
- data/lib/bunny/transport.rb +37 -1
- data/lib/bunny/version.rb +1 -1
- data/lib/bunny.rb +45 -4
- metadata +6 -146
- data/spec/config/enabled_plugins +0 -1
- data/spec/config/rabbitmq.conf +0 -13
- data/spec/higher_level_api/integration/basic_ack_spec.rb +0 -230
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +0 -142
- data/spec/higher_level_api/integration/basic_consume_spec.rb +0 -357
- data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +0 -54
- data/spec/higher_level_api/integration/basic_get_spec.rb +0 -80
- data/spec/higher_level_api/integration/basic_nack_spec.rb +0 -82
- data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -74
- data/spec/higher_level_api/integration/basic_qos_spec.rb +0 -57
- data/spec/higher_level_api/integration/basic_reject_spec.rb +0 -152
- data/spec/higher_level_api/integration/basic_return_spec.rb +0 -33
- data/spec/higher_level_api/integration/channel_close_spec.rb +0 -66
- data/spec/higher_level_api/integration/channel_open_spec.rb +0 -57
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +0 -483
- data/spec/higher_level_api/integration/connection_spec.rb +0 -589
- data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -83
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +0 -128
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +0 -75
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +0 -31
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +0 -237
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +0 -105
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +0 -40
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
- data/spec/higher_level_api/integration/heartbeat_spec.rb +0 -49
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +0 -95
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +0 -24
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +0 -191
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +0 -87
- data/spec/higher_level_api/integration/queue_bind_spec.rb +0 -109
- data/spec/higher_level_api/integration/queue_declare_spec.rb +0 -285
- data/spec/higher_level_api/integration/queue_delete_spec.rb +0 -41
- data/spec/higher_level_api/integration/queue_purge_spec.rb +0 -30
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +0 -54
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +0 -60
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +0 -36
- data/spec/higher_level_api/integration/tls_connection_spec.rb +0 -255
- data/spec/higher_level_api/integration/toxiproxy_spec.rb +0 -76
- data/spec/higher_level_api/integration/tx_commit_spec.rb +0 -21
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +0 -21
- data/spec/higher_level_api/integration/with_channel_spec.rb +0 -25
- data/spec/issues/issue100_spec.rb +0 -42
- data/spec/issues/issue141_spec.rb +0 -43
- data/spec/issues/issue202_spec.rb +0 -15
- data/spec/issues/issue224_spec.rb +0 -40
- data/spec/issues/issue465_spec.rb +0 -32
- data/spec/issues/issue549_spec.rb +0 -30
- data/spec/issues/issue609_spec.rb +0 -84
- data/spec/issues/issue78_spec.rb +0 -72
- data/spec/issues/issue83_spec.rb +0 -30
- data/spec/issues/issue97_attachment.json +0 -1
- data/spec/issues/issue97_spec.rb +0 -175
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +0 -83
- data/spec/lower_level_api/integration/basic_consume_spec.rb +0 -99
- data/spec/spec_helper.rb +0 -47
- data/spec/stress/channel_close_stress_spec.rb +0 -64
- data/spec/stress/channel_open_stress_spec.rb +0 -84
- data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -28
- data/spec/stress/concurrent_consumers_stress_spec.rb +0 -71
- data/spec/stress/concurrent_publishers_stress_spec.rb +0 -54
- data/spec/stress/connection_open_close_spec.rb +0 -52
- data/spec/stress/merry_go_round_spec.rb +0 -105
- data/spec/toxiproxy_helper.rb +0 -28
- data/spec/unit/bunny_spec.rb +0 -15
- data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
- data/spec/unit/concurrent/condition_spec.rb +0 -82
- data/spec/unit/concurrent/linked_continuation_queue_spec.rb +0 -35
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
- data/spec/unit/exchange_recovery_spec.rb +0 -39
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2edd88411f92dbdbb1d06b334006e446d5b3e3fb165f3baae3745bd066cf9651
|
4
|
+
data.tar.gz: 437032f606bb6f77fee02e65706e615f8a52c0e05467bbe257f1796fcedd624c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 698398dc76ca4e3dd11e3c5dc6b078998f23895bd3d975b01e1329c08c8ff0835cb9691d0108f0f6e13aaa769b870b258ff5e1de1958321be4804ca99b30a0be
|
7
|
+
data.tar.gz: 2a1fdcc61d683a991d07f601a986c5bc04d40cdd7155a1833dc7dba46be014c23d36612c505531b2f2adfe08ed057d6a493cbf5df368318205ffaf88659a88fb
|
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](
|
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.
|
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
|
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
|
-
* [
|
73
|
-
* [2.
|
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
|
[](http://badge.fury.io/rb/bunny)
|
83
87
|
|
84
|
-
###
|
88
|
+
### Bundler Dependency
|
85
89
|
|
86
|
-
To
|
90
|
+
To use Bunny in a project managed with Bundler:
|
87
91
|
|
88
|
-
```
|
89
|
-
gem
|
92
|
+
``` ruby
|
93
|
+
gem "bunny", ">= 2.19.0"
|
90
94
|
```
|
91
95
|
|
92
|
-
###
|
96
|
+
### With Rubygems
|
93
97
|
|
94
|
-
To
|
98
|
+
To install Bunny with RubyGems:
|
95
99
|
|
96
|
-
```
|
97
|
-
gem
|
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](
|
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
|
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](
|
156
|
-
* [Exchanges and Publishers](
|
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](
|
159
|
-
* [Error Handling and Recovery](
|
160
|
-
* [TLS/SSL Support](
|
161
|
-
* [Bindings](
|
162
|
-
* [Using RabbitMQ Extensions with Bunny](
|
163
|
-
* [Durability and Related Matters](
|
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
|
[](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
|
@@ -374,7 +378,7 @@ module Bunny
|
|
374
378
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
375
379
|
# @api public
|
376
380
|
def default_exchange
|
377
|
-
Exchange.default(self)
|
381
|
+
@default_exchange ||= Exchange.default(self)
|
378
382
|
end
|
379
383
|
|
380
384
|
# Declares a headers exchange or looks it up in the cache of previously
|
@@ -392,7 +396,7 @@ module Bunny
|
|
392
396
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
393
397
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
|
394
398
|
def exchange(name, opts = {})
|
395
|
-
Exchange.new(self, opts.fetch(:type, :direct), name, opts)
|
399
|
+
find_exchange(name) || Exchange.new(self, opts.fetch(:type, :direct), name, opts)
|
396
400
|
end
|
397
401
|
|
398
402
|
# @endgroup
|
@@ -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 [
|
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
|
-
@
|
1533
|
-
|
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}
|
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
|
data/lib/bunny/consumer.rb
CHANGED
@@ -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}
|
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}
|
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
|
@@ -70,7 +70,7 @@ module Bunny
|
|
70
70
|
return if !(wait_for_workers && @shutdown_timeout && was_running)
|
71
71
|
|
72
72
|
@shutdown_mutex.synchronize do
|
73
|
-
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout)
|
73
|
+
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout) if busy?
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
data/lib/bunny/delivery_info.rb
CHANGED
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 [
|
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
|
-
@
|
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
@@ -71,6 +71,7 @@ module Bunny
|
|
71
71
|
# Default reconnection interval for TCP connection failures
|
72
72
|
DEFAULT_NETWORK_RECOVERY_INTERVAL = 5.0
|
73
73
|
|
74
|
+
DEFAULT_RECOVERABLE_EXCEPTIONS = [StandardError, TCPConnectionFailedForAllHosts, TCPConnectionFailed, AMQ::Protocol::EmptyResponseError, SystemCallError, Timeout::Error, Bunny::ConnectionLevelException, Bunny::ConnectionClosedError]
|
74
75
|
|
75
76
|
#
|
76
77
|
# API
|
@@ -91,6 +92,7 @@ module Bunny
|
|
91
92
|
attr_reader :network_recovery_interval
|
92
93
|
attr_reader :connection_name
|
93
94
|
attr_accessor :socket_configurator
|
95
|
+
attr_accessor :recoverable_exceptions
|
94
96
|
|
95
97
|
# @param [String, Hash] connection_string_or_opts Connection string or a hash of connection options
|
96
98
|
# @param [Hash] optz Extra options not related to connection
|
@@ -109,7 +111,7 @@ module Bunny
|
|
109
111
|
# @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
|
110
112
|
# @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
113
|
# @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
|
112
|
-
# @option connection_string_or_opts [Symbol] :
|
114
|
+
# @option connection_string_or_opts [Symbol] :tls_protocol (negotiated) What TLS version should be used (:TLSv1, :TLSv1_1, or :TLSv1_2)
|
113
115
|
# @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
116
|
# @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
117
|
# @option connection_string_or_opts [Integer] :connection_timeout (30) Timeout in seconds for connecting to the server.
|
@@ -126,6 +128,7 @@ module Bunny
|
|
126
128
|
# @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.
|
127
129
|
# @option connection_string_or_opts [Proc] :recovery_attempt_started (nil) Will be called before every connection recovery attempt
|
128
130
|
# @option connection_string_or_opts [Proc] :recovery_completed (nil) Will be called after successful connection recovery
|
131
|
+
# @option connection_string_or_opts [Proc] :recovery_attempts_exhausted (nil) Will be called when the connection recovery failed after the specified amount of recovery attempts
|
129
132
|
# @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)?
|
130
133
|
# @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.
|
131
134
|
#
|
@@ -223,9 +226,12 @@ module Bunny
|
|
223
226
|
|
224
227
|
@recovery_attempt_started = opts[:recovery_attempt_started]
|
225
228
|
@recovery_completed = opts[:recovery_completed]
|
229
|
+
@recovery_attempts_exhausted = opts[:recovery_attempts_exhausted]
|
226
230
|
|
227
231
|
@session_error_handler = opts.fetch(:session_error_handler, Thread.current)
|
228
232
|
|
233
|
+
@recoverable_exceptions = DEFAULT_RECOVERABLE_EXCEPTIONS.dup
|
234
|
+
|
229
235
|
self.reset_continuations
|
230
236
|
self.initialize_transport
|
231
237
|
|
@@ -549,6 +555,12 @@ module Bunny
|
|
549
555
|
@recovery_completed = block
|
550
556
|
end
|
551
557
|
|
558
|
+
# Defines a callable (e.g. a block) that will be called
|
559
|
+
# when the connection recovery failed after the specified
|
560
|
+
# numbers of recovery attempts.
|
561
|
+
def after_recovery_attempts_exhausted(&block)
|
562
|
+
@recovery_attempts_exhausted = block
|
563
|
+
end
|
552
564
|
|
553
565
|
#
|
554
566
|
# Implementation
|
@@ -671,8 +683,12 @@ module Bunny
|
|
671
683
|
# avoid doing that while holding a mutex lock. MK.
|
672
684
|
ch.handle_method(method)
|
673
685
|
ensure
|
674
|
-
|
675
|
-
|
686
|
+
if ch.nil?
|
687
|
+
@logger.warn "Received a server-sent channel.close but the channel was not found locally. Ignoring the frame."
|
688
|
+
else
|
689
|
+
# synchronises on @channel_mutex under the hood
|
690
|
+
self.unregister_channel(ch)
|
691
|
+
end
|
676
692
|
end
|
677
693
|
when AMQ::Protocol::Basic::GetEmpty then
|
678
694
|
ch = find_channel(ch_number)
|
@@ -743,9 +759,7 @@ module Bunny
|
|
743
759
|
|
744
760
|
# @private
|
745
761
|
def recoverable_network_failure?(exception)
|
746
|
-
|
747
|
-
# So just recover unconditionally. MK.
|
748
|
-
true
|
762
|
+
@recoverable_exceptions.any? {|x| exception.kind_of? x}
|
749
763
|
end
|
750
764
|
|
751
765
|
# @private
|
@@ -790,19 +804,23 @@ module Bunny
|
|
790
804
|
rescue HostListDepleted
|
791
805
|
reset_address_index
|
792
806
|
retry
|
793
|
-
rescue
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
807
|
+
rescue => e
|
808
|
+
if recoverable_network_failure?(e)
|
809
|
+
@logger.warn "TCP connection failed"
|
810
|
+
if should_retry_recovery?
|
811
|
+
@logger.warn "Reconnecting in #{@network_recovery_interval} seconds"
|
812
|
+
decrement_recovery_attemp_counter!
|
798
813
|
announce_network_failure_recovery
|
799
814
|
retry
|
815
|
+
else
|
816
|
+
@logger.error "Ran out of recovery attempts (limit set to #{@max_recovery_attempts}), giving up"
|
817
|
+
@transport.close
|
818
|
+
self.close(false)
|
819
|
+
@manually_closed = false
|
820
|
+
notify_of_recovery_attempts_exhausted
|
800
821
|
end
|
801
822
|
else
|
802
|
-
|
803
|
-
@transport.close
|
804
|
-
self.close(false)
|
805
|
-
@manually_closed = false
|
823
|
+
raise e
|
806
824
|
end
|
807
825
|
end
|
808
826
|
|
@@ -850,6 +868,11 @@ module Bunny
|
|
850
868
|
@recovery_completed.call if @recovery_completed
|
851
869
|
end
|
852
870
|
|
871
|
+
# @private
|
872
|
+
def notify_of_recovery_attempts_exhausted
|
873
|
+
@recovery_attempts_exhausted.call if @recovery_attempts_exhausted
|
874
|
+
end
|
875
|
+
|
853
876
|
# @private
|
854
877
|
def instantiate_connection_level_exception(frame)
|
855
878
|
case frame
|
@@ -1352,7 +1375,7 @@ module Bunny
|
|
1352
1375
|
host_from_address(address),
|
1353
1376
|
port_from_address(address),
|
1354
1377
|
@opts.merge(:session_error_handler => @session_error_handler)
|
1355
|
-
|
1378
|
+
)
|
1356
1379
|
|
1357
1380
|
# Reset the cached progname for the logger only when no logger was provided
|
1358
1381
|
@default_logger.progname = self.to_s
|
data/lib/bunny/transport.rb
CHANGED
@@ -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
|
-
|
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