bunny 2.23.0 → 2.24.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 +29 -35
- data/lib/amq/protocol/extensions.rb +2 -0
- data/lib/bunny/authentication/credentials_encoder.rb +2 -0
- data/lib/bunny/authentication/external_mechanism_encoder.rb +2 -0
- data/lib/bunny/authentication/plain_mechanism_encoder.rb +2 -0
- data/lib/bunny/channel.rb +71 -29
- data/lib/bunny/channel_id_allocator.rb +2 -0
- data/lib/bunny/concurrent/atomic_fixnum.rb +2 -0
- data/lib/bunny/concurrent/condition.rb +2 -0
- data/lib/bunny/concurrent/continuation_queue.rb +2 -0
- data/lib/bunny/concurrent/synchronized_sorted_set.rb +2 -0
- data/lib/bunny/consumer.rb +2 -0
- data/lib/bunny/consumer_tag_generator.rb +2 -0
- data/lib/bunny/consumer_work_pool.rb +2 -0
- data/lib/bunny/cruby/socket.rb +3 -1
- data/lib/bunny/cruby/ssl_socket.rb +3 -1
- data/lib/bunny/delivery_info.rb +2 -0
- data/lib/bunny/exceptions.rb +2 -0
- data/lib/bunny/exchange.rb +2 -0
- data/lib/bunny/framing.rb +2 -0
- data/lib/bunny/get_response.rb +2 -0
- data/lib/bunny/heartbeat_sender.rb +2 -0
- data/lib/bunny/message_properties.rb +2 -0
- data/lib/bunny/queue.rb +11 -3
- data/lib/bunny/reader_loop.rb +3 -1
- data/lib/bunny/return_info.rb +2 -0
- data/lib/bunny/session.rb +11 -27
- data/lib/bunny/socket.rb +7 -12
- data/lib/bunny/ssl_socket.rb +7 -12
- data/lib/bunny/test_kit.rb +1 -0
- data/lib/bunny/timeout.rb +2 -0
- data/lib/bunny/timestamp.rb +2 -0
- data/lib/bunny/transport.rb +19 -41
- data/lib/bunny/version.rb +2 -1
- data/lib/bunny/versioned_delivery_tag.rb +2 -0
- data/lib/bunny.rb +1 -0
- metadata +4 -15
- data/lib/bunny/concurrent/linked_continuation_queue.rb +0 -61
- data/lib/bunny/jruby/socket.rb +0 -57
- data/lib/bunny/jruby/ssl_socket.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20682c9d4288b25e0aec7dcf5ad54276c7494faa45da1101eeedafa4f0f52abf
|
4
|
+
data.tar.gz: e88c87ecce0902f284a2bf54540c322afd3ac4c1fa625fb109d08d325a4faafa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c5668062269ae3be5c160a410432e712b110fc30f9fb6ddcde0c6ce14ddccc5c60e2c298eb21ce4a0512b4564f20833e4556e3d4532fd26918b674b4163ccb7
|
7
|
+
data.tar.gz: e621b5fd31913bf21d48380f0f8e198075f74e7bcec9c97feb17f32ae206b28551b87dd52c83640e72465afce98e12e5e611db940561ea9edbd3ef281f97169e
|
data/README.md
CHANGED
@@ -47,36 +47,33 @@ Specific examples:
|
|
47
47
|
|
48
48
|
Modern Bunny versions support
|
49
49
|
|
50
|
-
* CRuby 2
|
50
|
+
* CRuby 3.2 through 3.4 (inclusive)
|
51
51
|
* [TruffleRuby](https://www.graalvm.org/ruby/)
|
52
52
|
|
53
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**.
|
54
|
+
**includes support for [TLS 1.3](https://www.rabbitmq.com/docs/ssl#tls1.3)**.
|
55
55
|
|
56
56
|
### JRuby
|
57
57
|
|
58
|
-
Bunny
|
59
|
-
JRuby bugs in versions prior to JRuby 9000 that cause high CPU burn. JRuby users should
|
60
|
-
use [March Hare](http://rubymarchhare.info).
|
58
|
+
Bunny no longer supports JRuby.
|
61
59
|
|
62
|
-
|
60
|
+
JRuby users should use [March Hare](http://rubymarchhare.info), which has a similar API
|
61
|
+
and is built on top of the RabbitMQ Java client specifically for JRuby.
|
63
62
|
|
64
63
|
|
65
64
|
## Supported RabbitMQ Versions
|
66
65
|
|
67
|
-
Modern Bunny releases target [currently supported RabbitMQ release series](https://www.rabbitmq.com/
|
66
|
+
Modern Bunny releases target [currently community supported RabbitMQ release series](https://www.rabbitmq.com/release-information).
|
68
67
|
|
68
|
+
The protocol implemented by Bunny was first introduced in RabbitMQ 2.0 and has evolved
|
69
|
+
via extensions and with next to no breaking changes, so all key Bunny operations can be used with a wide range
|
70
|
+
of RabbitMQ versions, accounting for the few potentially breaking changes they
|
71
|
+
may introduce, e.g. the idempotency of `queue.delete` operations.
|
69
72
|
|
70
|
-
## Change Log
|
71
|
-
|
72
|
-
Bunny is a mature library (started in early 2009) with
|
73
|
-
a stable public API.
|
74
|
-
|
75
|
-
Change logs per release series:
|
76
73
|
|
77
|
-
|
78
|
-
* [2.19.x](https://github.com/ruby-amqp/bunny/blob/2.19.x-stable/ChangeLog.md)
|
74
|
+
## Change Log
|
79
75
|
|
76
|
+
[Change log](https://github.com/ruby-amqp/bunny/blob/main/ChangeLog.md).
|
80
77
|
|
81
78
|
|
82
79
|
## Installation & Bundler Dependency
|
@@ -90,7 +87,7 @@ Change logs per release series:
|
|
90
87
|
To use Bunny in a project managed with Bundler:
|
91
88
|
|
92
89
|
``` ruby
|
93
|
-
gem "bunny", ">= 2.
|
90
|
+
gem "bunny", ">= 2.23.0"
|
94
91
|
```
|
95
92
|
|
96
93
|
### With Rubygems
|
@@ -150,7 +147,7 @@ conn.close
|
|
150
147
|
|
151
148
|
### Getting Started
|
152
149
|
|
153
|
-
For a 15 minute tutorial using more practical examples, see [Getting Started with RabbitMQ and Ruby using Bunny](
|
150
|
+
For a 15 minute tutorial using more practical examples, see [Getting Started with RabbitMQ and Ruby using Bunny](https://github.com/ruby-amqp/bunny/blob/main/docs/guides/getting_started.md).
|
154
151
|
|
155
152
|
### Guides
|
156
153
|
|
@@ -168,15 +165,15 @@ Bunny documentation guides are [under `docs/guides` in this repository](https://
|
|
168
165
|
|
169
166
|
Some highly relevant RabbitMQ documentation guides:
|
170
167
|
|
171
|
-
* [Connections](https://www.rabbitmq.com/connections
|
172
|
-
* [Channels](https://www.rabbitmq.com/channels
|
173
|
-
* [Queues](https://www.rabbitmq.com/queues
|
174
|
-
* [Quorum queues](https://www.rabbitmq.com/quorum-queues
|
175
|
-
* [Streams](https://rabbitmq.com/streams
|
176
|
-
* [Publishers](https://www.rabbitmq.com/publishers
|
177
|
-
* [Consumers](https://www.rabbitmq.com/consumers
|
178
|
-
* Data safety: publisher and consumer [Confirmations](https://www.rabbitmq.com/confirms
|
179
|
-
* [Production Checklist](https://www.rabbitmq.com/production-checklist
|
168
|
+
* [Connections](https://www.rabbitmq.com/docs/connections)
|
169
|
+
* [Channels](https://www.rabbitmq.com/docs/channels)
|
170
|
+
* [Queues](https://www.rabbitmq.com/docs/queues)
|
171
|
+
* [Quorum queues](https://www.rabbitmq.com/docs/quorum-queues)
|
172
|
+
* [Streams](https://rabbitmq.com/docs/streams) (Bunny can perform basic operations on streams even though it does not implement the [RabbitMQ Stream protocol](https://github.com/rabbitmq/rabbitmq-server/blob/v4.0.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc))
|
173
|
+
* [Publishers](https://www.rabbitmq.com/docs/publishers)
|
174
|
+
* [Consumers](https://www.rabbitmq.com/docs/consumers)
|
175
|
+
* Data safety: publisher and consumer [Confirmations](https://www.rabbitmq.com/docs/confirms)
|
176
|
+
* [Production Checklist](https://www.rabbitmq.com/docs/production-checklist)
|
180
177
|
|
181
178
|
### API Reference
|
182
179
|
|
@@ -187,17 +184,14 @@ Some highly relevant RabbitMQ documentation guides:
|
|
187
184
|
|
188
185
|
### Mailing List
|
189
186
|
|
190
|
-
|
191
|
-
investigations, and discussions. GitHub issues should be used for specific, well understood, actionable
|
192
|
-
maintainers and contributors can work on.
|
193
|
-
|
194
|
-
We encourage you to also join the [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users)
|
195
|
-
mailing list. Feel free to ask any questions that you may have.
|
187
|
+
Please use [GitHub Discussions](https://github.com/ruby-amqp/bunny/discussions) for questions.
|
196
188
|
|
189
|
+
GitHub issues should be used for specific, well understood, actionable
|
190
|
+
maintainers and contributors can work on.
|
197
191
|
|
198
|
-
|
199
|
-
|
200
|
-
[
|
192
|
+
We encourage you to keep an eye on [RabbitMQ Discussions](https://github.com/rabbitmq/rabbitmq-server/discussions),
|
193
|
+
join the [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users)
|
194
|
+
and the [RabbitMQ Discord server](https://rabbitmq.com/discord).
|
201
195
|
|
202
196
|
|
203
197
|
### Reporting Issues
|
data/lib/bunny/channel.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require "thread"
|
3
5
|
require "monitor"
|
4
6
|
require "set"
|
@@ -13,11 +15,7 @@ require "bunny/delivery_info"
|
|
13
15
|
require "bunny/return_info"
|
14
16
|
require "bunny/message_properties"
|
15
17
|
|
16
|
-
|
17
|
-
require "bunny/concurrent/linked_continuation_queue"
|
18
|
-
else
|
19
|
-
require "bunny/concurrent/continuation_queue"
|
20
|
-
end
|
18
|
+
require "bunny/concurrent/continuation_queue"
|
21
19
|
|
22
20
|
module Bunny
|
23
21
|
# ## Channels in RabbitMQ
|
@@ -163,6 +161,8 @@ module Bunny
|
|
163
161
|
# @return [Integer] active basic.qos prefetch global mode
|
164
162
|
attr_reader :prefetch_global
|
165
163
|
|
164
|
+
attr_reader :cancel_consumers_before_closing
|
165
|
+
|
166
166
|
DEFAULT_CONTENT_TYPE = "application/octet-stream".freeze
|
167
167
|
SHORTSTR_LIMIT = 255
|
168
168
|
|
@@ -218,6 +218,8 @@ module Bunny
|
|
218
218
|
@uncaught_exception_handler = Proc.new do |e, consumer|
|
219
219
|
@logger.error "Uncaught exception from consumer #{consumer.to_s}: #{e.inspect} @ #{e.backtrace[0]}"
|
220
220
|
end
|
221
|
+
|
222
|
+
@cancel_consumers_before_closing = false
|
221
223
|
end
|
222
224
|
|
223
225
|
attr_reader :recoveries_counter
|
@@ -251,6 +253,23 @@ module Bunny
|
|
251
253
|
# see bunny#528
|
252
254
|
raise_if_no_longer_open!
|
253
255
|
|
256
|
+
# This is a best-effort attempt to cancel all consumers before closing the channel.
|
257
|
+
# Retries are extremely unlikely to succeed, and the channel itself is about to be closed,
|
258
|
+
# so we don't bother retrying.
|
259
|
+
if self.cancel_consumers_before_closing?
|
260
|
+
# cancelling a consumer involves using the same mutex, so avoid holding the lock
|
261
|
+
keys = @consumer_mutex.synchronize { @consumers.keys }
|
262
|
+
keys.each do |ctag|
|
263
|
+
begin
|
264
|
+
self.basic_cancel(ctag)
|
265
|
+
rescue Bunny::Exception
|
266
|
+
# ignore
|
267
|
+
rescue Bunny::ClientTimeout
|
268
|
+
# ignore
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
254
273
|
@connection.close_channel(self)
|
255
274
|
@status = :closed
|
256
275
|
@work_pool.shutdown
|
@@ -295,6 +314,23 @@ module Bunny
|
|
295
314
|
|
296
315
|
# @endgroup
|
297
316
|
|
317
|
+
# @group Other settings
|
318
|
+
|
319
|
+
def configure(&block)
|
320
|
+
block.call(self) if block_given?
|
321
|
+
|
322
|
+
self
|
323
|
+
end
|
324
|
+
|
325
|
+
def cancel_consumers_before_closing!
|
326
|
+
@cancel_consumers_before_closing = true
|
327
|
+
end
|
328
|
+
|
329
|
+
def cancel_consumers_before_closing?
|
330
|
+
!!@cancel_consumers_before_closing
|
331
|
+
end
|
332
|
+
|
333
|
+
# @endgroup
|
298
334
|
|
299
335
|
#
|
300
336
|
# Higher-level API, similar to amqp gem
|
@@ -412,7 +448,7 @@ module Bunny
|
|
412
448
|
# @option opts [Boolean] :durable (false) Should this queue be durable?
|
413
449
|
# @option opts [Boolean] :auto-delete (false) Should this queue be automatically deleted when the last consumer disconnects?
|
414
450
|
# @option opts [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
|
415
|
-
# @option opts [Hash] :arguments ({})
|
451
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
416
452
|
#
|
417
453
|
# @return [Bunny::Queue] Queue that was declared or looked up in the cache
|
418
454
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
@@ -431,7 +467,7 @@ module Bunny
|
|
431
467
|
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
432
468
|
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
433
469
|
#
|
434
|
-
# @option opts [Hash] :arguments ({})
|
470
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
435
471
|
#
|
436
472
|
# @return [Bunny::Queue] Queue that was declared
|
437
473
|
# @see #durable_queue
|
@@ -452,7 +488,7 @@ module Bunny
|
|
452
488
|
# @param [String] name Stream name. Empty (server-generated) names are not supported by this method.
|
453
489
|
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
454
490
|
#
|
455
|
-
# @option opts [Hash] :arguments ({})
|
491
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
456
492
|
#
|
457
493
|
#
|
458
494
|
# @return [Bunny::Queue] Queue that was declared
|
@@ -472,7 +508,7 @@ module Bunny
|
|
472
508
|
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
473
509
|
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
474
510
|
#
|
475
|
-
# @option opts [Hash] :arguments ({})
|
511
|
+
# @option opts [Hash] :arguments ({}) Optional arguments (x-arguments)
|
476
512
|
#
|
477
513
|
# @return [Bunny::Queue] Queue that was declared
|
478
514
|
# @see #queue
|
@@ -500,7 +536,10 @@ module Bunny
|
|
500
536
|
# @see #queue
|
501
537
|
# @api public
|
502
538
|
def temporary_queue(opts = {})
|
503
|
-
|
539
|
+
temporary_queue_opts = {
|
540
|
+
:exclusive => true
|
541
|
+
}
|
542
|
+
queue("", opts.merge(temporary_queue_opts))
|
504
543
|
end
|
505
544
|
|
506
545
|
# @endgroup
|
@@ -1027,15 +1066,24 @@ module Bunny
|
|
1027
1066
|
# it was on is auto-deleted and this consumer was the last one, the queue will be deleted.
|
1028
1067
|
#
|
1029
1068
|
# @param [String] consumer_tag Consumer tag (unique identifier) to cancel
|
1069
|
+
# @param [Hash] arguments ({}) Optional arguments
|
1070
|
+
#
|
1071
|
+
# @option opts [Boolean] :no_wait (false) if set to true, this method won't receive a response and will
|
1072
|
+
# immediately return nil
|
1030
1073
|
#
|
1031
|
-
# @return [AMQ::Protocol::Basic::CancelOk] RabbitMQ response
|
1074
|
+
# @return [AMQ::Protocol::Basic::CancelOk] RabbitMQ response or nil, if the no_wait option is used
|
1032
1075
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
1033
1076
|
# @api public
|
1034
|
-
def basic_cancel(consumer_tag)
|
1035
|
-
|
1077
|
+
def basic_cancel(consumer_tag, opts = {})
|
1078
|
+
no_wait = opts.fetch(:no_wait, false)
|
1079
|
+
@connection.send_frame(AMQ::Protocol::Basic::Cancel.encode(@id, consumer_tag, no_wait))
|
1036
1080
|
|
1037
|
-
|
1038
|
-
@last_basic_cancel_ok =
|
1081
|
+
if no_wait
|
1082
|
+
@last_basic_cancel_ok = nil
|
1083
|
+
else
|
1084
|
+
with_continuation_timeout do
|
1085
|
+
@last_basic_cancel_ok = wait_on_continuations
|
1086
|
+
end
|
1039
1087
|
end
|
1040
1088
|
|
1041
1089
|
# reduces thread usage for channels that don't have any
|
@@ -1070,13 +1118,15 @@ module Bunny
|
|
1070
1118
|
# connection is closed
|
1071
1119
|
# @option opts [Boolean] passive (false) If true, queue will be checked for existence. If it does not
|
1072
1120
|
# exist, {Bunny::NotFound} will be raised.
|
1073
|
-
#
|
1121
|
+
# @option opts [Hash] :arguments ({}) Optional queue arguments (x-arguments)
|
1074
1122
|
# @return [AMQ::Protocol::Queue::DeclareOk] RabbitMQ response
|
1075
1123
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
1076
1124
|
# @api public
|
1077
1125
|
def queue_declare(name, opts = {})
|
1078
1126
|
raise_if_no_longer_open!
|
1079
1127
|
|
1128
|
+
Bunny::Queue.verify_type!(opts[:arguments]) if opts[:arguments]
|
1129
|
+
|
1080
1130
|
# strip trailing new line and carriage returns
|
1081
1131
|
# just like RabbitMQ does
|
1082
1132
|
safe_name = name.gsub(/[\r\n]/, "")
|
@@ -1256,7 +1306,7 @@ module Bunny
|
|
1256
1306
|
opts.fetch(:durable, false),
|
1257
1307
|
opts.fetch(:auto_delete, false),
|
1258
1308
|
opts.fetch(:internal, false),
|
1259
|
-
false,
|
1309
|
+
opts.fetch(:no_wait, false),
|
1260
1310
|
opts[:arguments]))
|
1261
1311
|
with_continuation_timeout do
|
1262
1312
|
@last_exchange_declare_ok = wait_on_continuations
|
@@ -2100,18 +2150,10 @@ module Bunny
|
|
2100
2150
|
@basic_get_continuations = new_continuation
|
2101
2151
|
end
|
2102
2152
|
|
2103
|
-
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
Concurrent::LinkedContinuationQueue.new
|
2108
|
-
end
|
2109
|
-
else
|
2110
|
-
# @private
|
2111
|
-
def new_continuation
|
2112
|
-
Concurrent::ContinuationQueue.new
|
2113
|
-
end
|
2114
|
-
end # if defined?
|
2153
|
+
# @private
|
2154
|
+
def new_continuation
|
2155
|
+
Concurrent::ContinuationQueue.new
|
2156
|
+
end
|
2115
2157
|
|
2116
2158
|
# @private
|
2117
2159
|
def guarding_against_stale_delivery_tags(tag, &block)
|
data/lib/bunny/consumer.rb
CHANGED
data/lib/bunny/cruby/socket.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "socket"
|
2
4
|
|
3
5
|
module Bunny
|
@@ -52,7 +54,7 @@ module Bunny
|
|
52
54
|
def read_fully(count, timeout = nil)
|
53
55
|
return nil if @__bunny_socket_eof_flag__
|
54
56
|
|
55
|
-
value = ''
|
57
|
+
value = +''
|
56
58
|
begin
|
57
59
|
loop do
|
58
60
|
value << read_nonblock(count - value.bytesize)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "socket"
|
2
4
|
|
3
5
|
module Bunny
|
@@ -39,7 +41,7 @@ module Bunny
|
|
39
41
|
def read_fully(count, timeout = nil)
|
40
42
|
return nil if @__bunny_socket_eof_flag__
|
41
43
|
|
42
|
-
value = ''
|
44
|
+
value = +''
|
43
45
|
begin
|
44
46
|
loop do
|
45
47
|
value << read_nonblock(count - value.bytesize)
|
data/lib/bunny/delivery_info.rb
CHANGED
data/lib/bunny/exceptions.rb
CHANGED
data/lib/bunny/exchange.rb
CHANGED
data/lib/bunny/framing.rb
CHANGED
data/lib/bunny/get_response.rb
CHANGED
data/lib/bunny/queue.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "bunny/get_response"
|
2
4
|
|
3
5
|
module Bunny
|
@@ -352,6 +354,14 @@ module Bunny
|
|
352
354
|
s[:consumer_count]
|
353
355
|
end
|
354
356
|
|
357
|
+
def self.verify_type!(args0 = {})
|
358
|
+
# be extra defensive
|
359
|
+
args = args0 || {}
|
360
|
+
q_type = args["x-queue-type"] || args[:"x-queue-type"]
|
361
|
+
throw ArgumentError.new(
|
362
|
+
"unsupported queue type #{q_type.inspect}, supported ones: #{Types::KNOWN.join(', ')}") if (q_type and !Types.known?(q_type))
|
363
|
+
end
|
364
|
+
|
355
365
|
#
|
356
366
|
# Recovery
|
357
367
|
#
|
@@ -419,9 +429,7 @@ module Bunny
|
|
419
429
|
end
|
420
430
|
|
421
431
|
def verify_type!(args)
|
422
|
-
|
423
|
-
throw ArgumentError.new(
|
424
|
-
"unsupported queue type #{q_type.inspect}, supported ones: #{Types::KNOWN.join(', ')}") if (q_type and !Types.known?(q_type))
|
432
|
+
self.class.verify_type!(args)
|
425
433
|
end
|
426
434
|
end
|
427
435
|
end
|
data/lib/bunny/reader_loop.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "thread"
|
2
4
|
|
3
5
|
module Bunny
|
@@ -76,7 +78,7 @@ module Bunny
|
|
76
78
|
|
77
79
|
if !frame.final? || frame.method_class.has_content?
|
78
80
|
header = @transport.read_next_frame
|
79
|
-
content = ''
|
81
|
+
content = +''
|
80
82
|
|
81
83
|
if header.body_size > 0
|
82
84
|
loop do
|
data/lib/bunny/return_info.rb
CHANGED
data/lib/bunny/session.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "socket"
|
2
4
|
require "thread"
|
3
5
|
require "monitor"
|
@@ -10,11 +12,7 @@ require "bunny/authentication/credentials_encoder"
|
|
10
12
|
require "bunny/authentication/plain_mechanism_encoder"
|
11
13
|
require "bunny/authentication/external_mechanism_encoder"
|
12
14
|
|
13
|
-
|
14
|
-
require "bunny/concurrent/linked_continuation_queue"
|
15
|
-
else
|
16
|
-
require "bunny/concurrent/continuation_queue"
|
17
|
-
end
|
15
|
+
require "bunny/concurrent/continuation_queue"
|
18
16
|
|
19
17
|
require "amq/protocol/client"
|
20
18
|
require "amq/settings"
|
@@ -516,6 +514,8 @@ module Bunny
|
|
516
514
|
begin
|
517
515
|
ch.queue(name, :passive => true)
|
518
516
|
true
|
517
|
+
rescue Bunny::ResourceLocked => _
|
518
|
+
true
|
519
519
|
rescue Bunny::NotFound => _
|
520
520
|
false
|
521
521
|
ensure
|
@@ -1076,16 +1076,7 @@ module Bunny
|
|
1076
1076
|
# this is the easiest way to wait until the loop
|
1077
1077
|
# is guaranteed to have terminated
|
1078
1078
|
@reader_loop.terminate_with(ShutdownSignal)
|
1079
|
-
|
1080
|
-
# on JRuby because sun.nio.ch.KQueueArrayWrapper#kevent0 is
|
1081
|
-
# a native method that cannot be (easily) interrupted.
|
1082
|
-
# So we use this ugly hack or else our test suite takes forever
|
1083
|
-
# to run on JRuby (a new connection is opened/closed per example). MK.
|
1084
|
-
if defined?(JRUBY_VERSION)
|
1085
|
-
sleep 0.075
|
1086
|
-
else
|
1087
|
-
@reader_loop.join
|
1088
|
-
end
|
1079
|
+
@reader_loop.join
|
1089
1080
|
else
|
1090
1081
|
# single threaded mode, nothing to do. MK.
|
1091
1082
|
end
|
@@ -1159,7 +1150,7 @@ module Bunny
|
|
1159
1150
|
channel.synchronize do
|
1160
1151
|
# see rabbitmq/rabbitmq-server#156
|
1161
1152
|
if open?
|
1162
|
-
data = frames.reduce("") { |acc, frame| acc << frame.encode }
|
1153
|
+
data = frames.reduce(+"") { |acc, frame| acc << frame.encode }
|
1163
1154
|
@transport.write(data)
|
1164
1155
|
signal_activity!
|
1165
1156
|
else
|
@@ -1270,7 +1261,7 @@ module Bunny
|
|
1270
1261
|
negotiate_value(@client_heartbeat, connection_tune.heartbeat)
|
1271
1262
|
end
|
1272
1263
|
@logger.debug { "Heartbeat interval negotiation: client = #{@client_heartbeat}, server = #{connection_tune.heartbeat}, result = #{@heartbeat}" }
|
1273
|
-
@logger.
|
1264
|
+
@logger.debug "Heartbeat interval used (in seconds): #{@heartbeat}"
|
1274
1265
|
|
1275
1266
|
# We set the read_write_timeout to twice the heartbeat value,
|
1276
1267
|
# and then some padding for edge cases.
|
@@ -1409,16 +1400,9 @@ module Bunny
|
|
1409
1400
|
Authentication::CredentialsEncoder.for_session(self)
|
1410
1401
|
end
|
1411
1402
|
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
@continuations = Concurrent::LinkedContinuationQueue.new
|
1416
|
-
end
|
1417
|
-
else
|
1418
|
-
# @private
|
1419
|
-
def reset_continuations
|
1420
|
-
@continuations = Concurrent::ContinuationQueue.new
|
1421
|
-
end
|
1403
|
+
# @private
|
1404
|
+
def reset_continuations
|
1405
|
+
@continuations = Concurrent::ContinuationQueue.new
|
1422
1406
|
end
|
1423
1407
|
|
1424
1408
|
# @private
|
data/lib/bunny/socket.rb
CHANGED
@@ -1,14 +1,9 @@
|
|
1
|
-
#
|
2
|
-
if defined?(JRUBY_VERSION)
|
3
|
-
require "bunny/jruby/socket"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
SocketImpl = JRuby::Socket
|
7
|
-
end
|
8
|
-
else
|
9
|
-
require "bunny/cruby/socket"
|
3
|
+
require "bunny/cruby/socket"
|
10
4
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
module Bunny
|
6
|
+
# An alias for the standard MRI Socket,
|
7
|
+
# exists from the days of JRuby support.
|
8
|
+
SocketImpl = Socket
|
9
|
+
end
|
data/lib/bunny/ssl_socket.rb
CHANGED
@@ -1,14 +1,9 @@
|
|
1
|
-
#
|
2
|
-
if defined?(JRUBY_VERSION)
|
3
|
-
require "bunny/jruby/ssl_socket"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
SSLSocketImpl = JRuby::SSLSocket
|
7
|
-
end
|
8
|
-
else
|
9
|
-
require "bunny/cruby/ssl_socket"
|
3
|
+
require "bunny/cruby/ssl_socket"
|
10
4
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
module Bunny
|
6
|
+
# An alias for the standard SSLSocket,
|
7
|
+
# exists from the days of JRuby support.
|
8
|
+
SSLSocketImpl = SSLSocket
|
9
|
+
end
|
data/lib/bunny/test_kit.rb
CHANGED
data/lib/bunny/timeout.rb
CHANGED
data/lib/bunny/timestamp.rb
CHANGED
data/lib/bunny/transport.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "socket"
|
2
4
|
require "thread"
|
3
5
|
require "monitor"
|
@@ -151,51 +153,26 @@ module Bunny
|
|
151
153
|
block.call(@tls_context) if @tls_context
|
152
154
|
end
|
153
155
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
156
|
+
# Writes data to the socket. If read/write timeout was specified the operation will return after that
|
157
|
+
# amount of time has elapsed waiting for the socket.
|
158
|
+
def write(data)
|
159
|
+
return write_without_timeout(data) unless @write_timeout
|
158
160
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
end
|
165
|
-
rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e
|
166
|
-
@logger.error "Got an exception when sending data: #{e.message} (#{e.class.name})"
|
167
|
-
close
|
168
|
-
@status = :not_connected
|
169
|
-
|
170
|
-
if @session.automatically_recover?
|
171
|
-
@session.handle_network_failure(e)
|
172
|
-
else
|
173
|
-
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
161
|
+
begin
|
162
|
+
if open?
|
163
|
+
@writes_mutex.synchronize do
|
164
|
+
@socket.write_nonblock_fully(data, @write_timeout)
|
174
165
|
end
|
175
166
|
end
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
def write(data)
|
181
|
-
return write_without_timeout(data) unless @write_timeout
|
167
|
+
rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e
|
168
|
+
@logger.error "Got an exception when sending data: #{e.message} (#{e.class.name})"
|
169
|
+
close
|
170
|
+
@status = :not_connected
|
182
171
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
end
|
188
|
-
end
|
189
|
-
rescue SystemCallError, Timeout::Error, Bunny::ConnectionError, IOError => e
|
190
|
-
@logger.error "Got an exception when sending data: #{e.message} (#{e.class.name})"
|
191
|
-
close
|
192
|
-
@status = :not_connected
|
193
|
-
|
194
|
-
if @session.automatically_recover?
|
195
|
-
@session.handle_network_failure(e)
|
196
|
-
else
|
197
|
-
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
198
|
-
end
|
172
|
+
if @session.automatically_recover?
|
173
|
+
@session.handle_network_failure(e)
|
174
|
+
else
|
175
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
199
176
|
end
|
200
177
|
end
|
201
178
|
end
|
@@ -320,6 +297,7 @@ module Bunny
|
|
320
297
|
end
|
321
298
|
|
322
299
|
def initialize_socket
|
300
|
+
@logger.debug("Usong connection timeout of #{@connect_timeout} when connecting to #{@host}:#{@port}")
|
323
301
|
begin
|
324
302
|
@socket = Bunny::SocketImpl.open(@host, @port,
|
325
303
|
:keepalive => @opts[:keepalive],
|
data/lib/bunny/version.rb
CHANGED
data/lib/bunny.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Duncan
|
@@ -9,10 +9,9 @@ authors:
|
|
9
9
|
- Jakub Stastny aka botanicus
|
10
10
|
- Michael S. Klishin
|
11
11
|
- Stefan Kaes
|
12
|
-
autorequire:
|
13
12
|
bindir: bin
|
14
13
|
cert_chain: []
|
15
|
-
date:
|
14
|
+
date: 2025-03-23 00:00:00.000000000 Z
|
16
15
|
dependencies:
|
17
16
|
- !ruby/object:Gem::Dependency
|
18
17
|
name: amq-protocol
|
@@ -21,9 +20,6 @@ dependencies:
|
|
21
20
|
- - "~>"
|
22
21
|
- !ruby/object:Gem::Version
|
23
22
|
version: '2.3'
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 2.3.1
|
27
23
|
type: :runtime
|
28
24
|
prerelease: false
|
29
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -31,9 +27,6 @@ dependencies:
|
|
31
27
|
- - "~>"
|
32
28
|
- !ruby/object:Gem::Version
|
33
29
|
version: '2.3'
|
34
|
-
- - ">="
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: 2.3.1
|
37
30
|
- !ruby/object:Gem::Dependency
|
38
31
|
name: sorted_set
|
39
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -74,7 +67,6 @@ files:
|
|
74
67
|
- lib/bunny/concurrent/atomic_fixnum.rb
|
75
68
|
- lib/bunny/concurrent/condition.rb
|
76
69
|
- lib/bunny/concurrent/continuation_queue.rb
|
77
|
-
- lib/bunny/concurrent/linked_continuation_queue.rb
|
78
70
|
- lib/bunny/concurrent/synchronized_sorted_set.rb
|
79
71
|
- lib/bunny/consumer.rb
|
80
72
|
- lib/bunny/consumer_tag_generator.rb
|
@@ -87,8 +79,6 @@ files:
|
|
87
79
|
- lib/bunny/framing.rb
|
88
80
|
- lib/bunny/get_response.rb
|
89
81
|
- lib/bunny/heartbeat_sender.rb
|
90
|
-
- lib/bunny/jruby/socket.rb
|
91
|
-
- lib/bunny/jruby/ssl_socket.rb
|
92
82
|
- lib/bunny/message_properties.rb
|
93
83
|
- lib/bunny/queue.rb
|
94
84
|
- lib/bunny/reader_loop.rb
|
@@ -107,7 +97,7 @@ licenses:
|
|
107
97
|
- MIT
|
108
98
|
metadata:
|
109
99
|
changelog_uri: https://github.com/ruby-amqp/bunny/blob/main/ChangeLog.md
|
110
|
-
|
100
|
+
source_code_uri: https://github.com/ruby-amqp/bunny/
|
111
101
|
rdoc_options: []
|
112
102
|
require_paths:
|
113
103
|
- lib
|
@@ -122,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
112
|
- !ruby/object:Gem::Version
|
123
113
|
version: '0'
|
124
114
|
requirements: []
|
125
|
-
rubygems_version: 3.
|
126
|
-
signing_key:
|
115
|
+
rubygems_version: 3.6.2
|
127
116
|
specification_version: 4
|
128
117
|
summary: Popular easy to use Ruby client for RabbitMQ
|
129
118
|
test_files: []
|
@@ -1,61 +0,0 @@
|
|
1
|
-
if !defined?(JRUBY_VERSION)
|
2
|
-
raise "Bunny::Concurrent::LinkedContinuationQueue can only be used on JRuby!"
|
3
|
-
end
|
4
|
-
|
5
|
-
require "java"
|
6
|
-
|
7
|
-
java_import java.util.concurrent.LinkedBlockingQueue
|
8
|
-
java_import java.util.concurrent.TimeUnit
|
9
|
-
|
10
|
-
module Bunny
|
11
|
-
module Concurrent
|
12
|
-
# Continuation queue implementation for JRuby.
|
13
|
-
#
|
14
|
-
# On JRuby, we'd rather use reliable and heavily battle tested j.u.c.
|
15
|
-
# primitives with well described semantics than informally specified, clumsy
|
16
|
-
# and limited Ruby standard library parts.
|
17
|
-
#
|
18
|
-
# This is an implementation of the continuation queue on top of the linked blocking
|
19
|
-
# queue in j.u.c.
|
20
|
-
#
|
21
|
-
# Compared to the Ruby standard library Queue, there is one limitation: you cannot
|
22
|
-
# push a nil on the queue, it will fail with a null pointer exception.
|
23
|
-
# @private
|
24
|
-
class LinkedContinuationQueue
|
25
|
-
def initialize(*args, &block)
|
26
|
-
@q = LinkedBlockingQueue.new
|
27
|
-
end
|
28
|
-
|
29
|
-
def push(el, timeout_in_ms = nil)
|
30
|
-
if timeout_in_ms
|
31
|
-
@q.offer(el, timeout_in_ms, TimeUnit::MILLISECONDS)
|
32
|
-
else
|
33
|
-
@q.offer(el)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
alias << push
|
37
|
-
|
38
|
-
def pop
|
39
|
-
@q.take
|
40
|
-
end
|
41
|
-
|
42
|
-
def poll(timeout_in_ms = nil)
|
43
|
-
if timeout_in_ms
|
44
|
-
v = @q.poll(timeout_in_ms, TimeUnit::MILLISECONDS)
|
45
|
-
raise ::Timeout::Error.new("operation did not finish in #{timeout_in_ms} ms") if v.nil?
|
46
|
-
v
|
47
|
-
else
|
48
|
-
@q.poll
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def clear
|
53
|
-
@q.clear
|
54
|
-
end
|
55
|
-
|
56
|
-
def method_missing(selector, *args, &block)
|
57
|
-
@q.__send__(selector, *args, &block)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/bunny/jruby/socket.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require "bunny/cruby/socket"
|
2
|
-
|
3
|
-
module Bunny
|
4
|
-
module JRuby
|
5
|
-
# TCP socket extension that uses Socket#readpartial to avoid excessive CPU
|
6
|
-
# burn after some time. See issue #165.
|
7
|
-
# @private
|
8
|
-
module Socket
|
9
|
-
include Bunny::Socket
|
10
|
-
|
11
|
-
def self.open(host, port, options = {})
|
12
|
-
socket = ::Socket.tcp(host, port, nil, nil,
|
13
|
-
connect_timeout: options[:connect_timeout])
|
14
|
-
if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
|
15
|
-
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
16
|
-
end
|
17
|
-
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
|
18
|
-
socket.extend self
|
19
|
-
socket.options = { :host => host, :port => port }.merge(options)
|
20
|
-
socket
|
21
|
-
rescue Errno::ETIMEDOUT
|
22
|
-
raise ClientTimeout
|
23
|
-
end
|
24
|
-
|
25
|
-
# Reads given number of bytes with an optional timeout
|
26
|
-
#
|
27
|
-
# @param [Integer] count How many bytes to read
|
28
|
-
# @param [Integer] timeout Timeout
|
29
|
-
#
|
30
|
-
# @return [String] Data read from the socket
|
31
|
-
# @api public
|
32
|
-
def read_fully(count, timeout = nil)
|
33
|
-
value = ''
|
34
|
-
|
35
|
-
begin
|
36
|
-
loop do
|
37
|
-
value << read_nonblock(count - value.bytesize)
|
38
|
-
break if value.bytesize >= count
|
39
|
-
end
|
40
|
-
rescue EOFError
|
41
|
-
# JRuby specific fix via https://github.com/jruby/jruby/issues/1694#issuecomment-54873532
|
42
|
-
IO.select([self], nil, nil, timeout)
|
43
|
-
retry
|
44
|
-
rescue *READ_RETRY_EXCEPTION_CLASSES
|
45
|
-
if IO.select([self], nil, nil, timeout)
|
46
|
-
retry
|
47
|
-
else
|
48
|
-
raise Timeout::Error, "IO timeout when reading #{count} bytes"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
value
|
53
|
-
end # read_fully
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module Bunny
|
2
|
-
module JRuby
|
3
|
-
begin
|
4
|
-
require "bunny/cruby/ssl_socket"
|
5
|
-
require "openssl"
|
6
|
-
|
7
|
-
# TLS-enabled TCP socket that implements convenience
|
8
|
-
# methods found in Bunny::Socket.
|
9
|
-
class SSLSocket < Bunny::SSLSocket
|
10
|
-
|
11
|
-
def initialize(*args)
|
12
|
-
super
|
13
|
-
@__bunny_socket_eof_flag__ = false
|
14
|
-
end
|
15
|
-
|
16
|
-
# Reads given number of bytes with an optional timeout
|
17
|
-
#
|
18
|
-
# @param [Integer] count How many bytes to read
|
19
|
-
# @param [Integer] timeout Timeout
|
20
|
-
#
|
21
|
-
# @return [String] Data read from the socket
|
22
|
-
# @api public
|
23
|
-
def read_fully(count, timeout = nil)
|
24
|
-
return nil if @__bunny_socket_eof_flag__
|
25
|
-
|
26
|
-
value = ''
|
27
|
-
begin
|
28
|
-
loop do
|
29
|
-
value << read_nonblock(count - value.bytesize)
|
30
|
-
break if value.bytesize >= count
|
31
|
-
end
|
32
|
-
rescue EOFError => e
|
33
|
-
@__bunny_socket_eof_flag__ = true
|
34
|
-
rescue OpenSSL::SSL::SSLError => e
|
35
|
-
if e.message == "read would block"
|
36
|
-
if IO.select([self], nil, nil, timeout)
|
37
|
-
retry
|
38
|
-
else
|
39
|
-
raise Timeout::Error, "IO timeout when reading #{count} bytes"
|
40
|
-
end
|
41
|
-
else
|
42
|
-
raise e
|
43
|
-
end
|
44
|
-
rescue *READ_RETRY_EXCEPTION_CLASSES => e
|
45
|
-
if IO.select([self], nil, nil, timeout)
|
46
|
-
retry
|
47
|
-
else
|
48
|
-
raise Timeout::Error, "IO timeout when reading #{count} bytes"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
rescue LoadError => le
|
55
|
-
puts "Could not load OpenSSL"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|