bunny 2.19.0 → 2.22.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/bunny.svg)](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
|
[![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
|
@@ -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