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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -35
  3. data/lib/amq/protocol/extensions.rb +2 -0
  4. data/lib/bunny/authentication/credentials_encoder.rb +2 -0
  5. data/lib/bunny/authentication/external_mechanism_encoder.rb +2 -0
  6. data/lib/bunny/authentication/plain_mechanism_encoder.rb +2 -0
  7. data/lib/bunny/channel.rb +71 -29
  8. data/lib/bunny/channel_id_allocator.rb +2 -0
  9. data/lib/bunny/concurrent/atomic_fixnum.rb +2 -0
  10. data/lib/bunny/concurrent/condition.rb +2 -0
  11. data/lib/bunny/concurrent/continuation_queue.rb +2 -0
  12. data/lib/bunny/concurrent/synchronized_sorted_set.rb +2 -0
  13. data/lib/bunny/consumer.rb +2 -0
  14. data/lib/bunny/consumer_tag_generator.rb +2 -0
  15. data/lib/bunny/consumer_work_pool.rb +2 -0
  16. data/lib/bunny/cruby/socket.rb +3 -1
  17. data/lib/bunny/cruby/ssl_socket.rb +3 -1
  18. data/lib/bunny/delivery_info.rb +2 -0
  19. data/lib/bunny/exceptions.rb +2 -0
  20. data/lib/bunny/exchange.rb +2 -0
  21. data/lib/bunny/framing.rb +2 -0
  22. data/lib/bunny/get_response.rb +2 -0
  23. data/lib/bunny/heartbeat_sender.rb +2 -0
  24. data/lib/bunny/message_properties.rb +2 -0
  25. data/lib/bunny/queue.rb +11 -3
  26. data/lib/bunny/reader_loop.rb +3 -1
  27. data/lib/bunny/return_info.rb +2 -0
  28. data/lib/bunny/session.rb +11 -27
  29. data/lib/bunny/socket.rb +7 -12
  30. data/lib/bunny/ssl_socket.rb +7 -12
  31. data/lib/bunny/test_kit.rb +1 -0
  32. data/lib/bunny/timeout.rb +2 -0
  33. data/lib/bunny/timestamp.rb +2 -0
  34. data/lib/bunny/transport.rb +19 -41
  35. data/lib/bunny/version.rb +2 -1
  36. data/lib/bunny/versioned_delivery_tag.rb +2 -0
  37. data/lib/bunny.rb +1 -0
  38. metadata +4 -15
  39. data/lib/bunny/concurrent/linked_continuation_queue.rb +0 -61
  40. data/lib/bunny/jruby/socket.rb +0 -57
  41. data/lib/bunny/jruby/ssl_socket.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b33407ce8bf5340f646d7f35f884b991da2c54b1e46e7c8bd31f65e75822cc22
4
- data.tar.gz: 8b4242b14294c62a4310f6f4921eabb54414d930756495ab1c9130559475593f
3
+ metadata.gz: 20682c9d4288b25e0aec7dcf5ad54276c7494faa45da1101eeedafa4f0f52abf
4
+ data.tar.gz: e88c87ecce0902f284a2bf54540c322afd3ac4c1fa625fb109d08d325a4faafa
5
5
  SHA512:
6
- metadata.gz: 7ecfba958caee454e1105cd500a1d2f632340b8358469420802b8fbf029abdedc742bdae39ff9d2ad1b04cc4a7d7fd6bc26b1ff11fc282118c6c05fb688ff661
7
- data.tar.gz: 7b101718ac037ad85702432cdf865310e94c5a269348ceee714bc6e5630312415f87283360dbbe88577fa1b661ecc5e5f8086d59bbdd50098cfe5e528c757ea1
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.6 through 3.1 (inclusive)
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 works sufficiently well on JRuby but there are known
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
- Bunny `1.7.x` was the last version to support CRuby 1.9.3 and 1.8.7
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/versions.html).
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
- * [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)
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.19.0"
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](http://rubybunny.info/articles/getting_started.html).
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.html)
172
- * [Channels](https://www.rabbitmq.com/channels.html)
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))
176
- * [Publishers](https://www.rabbitmq.com/publishers.html)
177
- * [Consumers](https://www.rabbitmq.com/consumers.html)
178
- * Data safety: publisher and consumer [Confirmations](https://www.rabbitmq.com/confirms.html)
179
- * [Production Checklist](https://www.rabbitmq.com/production-checklist.html)
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
- [Bunny has a mailing list](http://groups.google.com/group/ruby-amqp). Please use it for all questions,
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
- ## Continuous Integration
199
-
200
- [![Build Status](https://travis-ci.org/ruby-amqp/bunny.svg)](https://travis-ci.org/ruby-amqp/bunny/)
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @private
2
4
  module AMQ
3
5
  # @private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Contains credentials encoding implementations for various
3
5
  # authentication strategies.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bunny/authentication/credentials_encoder"
2
4
 
3
5
  module Bunny
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bunny/authentication/credentials_encoder"
2
4
 
3
5
  module Bunny
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
- if defined?(JRUBY_VERSION)
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 ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
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 ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
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 ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
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 ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
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
- queue("", opts.merge(:exclusive => true))
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
- @connection.send_frame(AMQ::Protocol::Basic::Cancel.encode(@id, consumer_tag, false))
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
- with_continuation_timeout do
1038
- @last_basic_cancel_ok = wait_on_continuations
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, # nowait
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
- if defined?(JRUBY_VERSION)
2105
- # @private
2106
- def new_continuation
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)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "monitor"
3
5
  require "amq/int_allocator"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
  require "thread"
3
5
  require "monitor"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "monitor"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
 
3
5
  module Bunny
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
  require "thread"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Base class that represents consumer interface. Subclasses of this class implement
3
5
  # specific logic of handling consumer life cycle events. Note that when the only event
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Used to generate consumer tags in the client
3
5
  class ConsumerTagGenerator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
 
3
5
  module Bunny
@@ -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)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bunny/versioned_delivery_tag"
2
4
 
3
5
  module Bunny
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Base class for all Bunny exceptions
3
5
  # @api public
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'amq/protocol'
2
4
 
3
5
  module Bunny
data/lib/bunny/framing.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # @private
3
5
  module Framing
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bunny/versioned_delivery_tag"
2
4
 
3
5
  module Bunny
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "amq/protocol/client"
3
5
  require "amq/protocol/frame"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Wraps basic properties hash as returned by amq-protocol to
3
5
  # provide access to the delivery properties as immutable hash as
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
- 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))
432
+ self.class.verify_type!(args)
425
433
  end
426
434
  end
427
435
  end
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Wraps AMQ::Protocol::Basic::Return to
3
5
  # provide access to the delivery properties as immutable hash as
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
- if defined?(JRUBY_VERSION)
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
- # joining the thread here may take forever
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.info "Heartbeat interval used (in seconds): #{@heartbeat}"
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
- if defined?(JRUBY_VERSION)
1413
- # @private
1414
- def reset_continuations
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
- # See #165. MK.
2
- if defined?(JRUBY_VERSION)
3
- require "bunny/jruby/socket"
1
+ # frozen_string_literal: true
4
2
 
5
- module Bunny
6
- SocketImpl = JRuby::Socket
7
- end
8
- else
9
- require "bunny/cruby/socket"
3
+ require "bunny/cruby/socket"
10
4
 
11
- module Bunny
12
- SocketImpl = Socket
13
- end
14
- end
5
+ module Bunny
6
+ # An alias for the standard MRI Socket,
7
+ # exists from the days of JRuby support.
8
+ SocketImpl = Socket
9
+ end
@@ -1,14 +1,9 @@
1
- # See #165. MK.
2
- if defined?(JRUBY_VERSION)
3
- require "bunny/jruby/ssl_socket"
1
+ # frozen_string_literal: true
4
2
 
5
- module Bunny
6
- SSLSocketImpl = JRuby::SSLSocket
7
- end
8
- else
9
- require "bunny/cruby/ssl_socket"
3
+ require "bunny/cruby/ssl_socket"
10
4
 
11
- module Bunny
12
- SSLSocketImpl = SSLSocket
13
- end
14
- end
5
+ module Bunny
6
+ # An alias for the standard SSLSocket,
7
+ # exists from the days of JRuby support.
8
+ SSLSocketImpl = SSLSocket
9
+ end
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "timeout"
4
5
 
data/lib/bunny/timeout.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  Timeout = ::Timeout
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Abstracts away the Ruby (OS) method of retriving timestamps.
3
5
  #
@@ -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
- if defined?(JRUBY_VERSION)
155
- # Writes data to the socket.
156
- def write(data)
157
- return write_without_timeout(data) unless @write_timeout
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
- begin
160
- if open?
161
- @writes_mutex.synchronize do
162
- @socket.write(data)
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
- end
177
- else
178
- # Writes data to the socket. If read/write timeout was specified the operation will return after that
179
- # amount of time has elapsed waiting for the socket.
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
- begin
184
- if open?
185
- @writes_mutex.synchronize do
186
- @socket.write_nonblock_fully(data, @write_timeout)
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
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Bunny
4
5
  # @return [String] Version of the library
5
- VERSION = "2.23.0"
6
+ VERSION = "2.24.0"
6
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bunny
2
4
  # Wraps a delivery tag (which is an integer) so that {Bunny::Channel} could
3
5
  # detect stale tags after connection recovery.
data/lib/bunny.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8; mode: ruby -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "timeout"
4
5
 
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.23.0
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: 2024-07-01 00:00:00.000000000 Z
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
- post_install_message:
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.5.9
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
@@ -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