rabbit_messaging 1.9.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38dfb0f21f2e7b583ed1fab761768332e01bd18b68ad1ebd4bb66a0168d1c57e
4
- data.tar.gz: b5c19ca62b8d7157ae8a8718d26ec888e53a677b4cac6474204b8dbf3531aff2
3
+ metadata.gz: d298261bbcdb67fa9e0a784af3caa96a327a78c53a690eba4a04bd275e5d7d87
4
+ data.tar.gz: 25597ce02a4ff8a14805bfcc0e93356eac64d625327d786e86f35a7b5fa5b3ad
5
5
  SHA512:
6
- metadata.gz: 2ee5d32fa8ef2c1dbdc4df42d49d47039f4e20f2f5f6f4bbb98717ba1ee35c6b643e55bbc18d8ba2d6f4e8bcbc1f6d00cfcd163dd8017ea5c673fef919b4370e
7
- data.tar.gz: ebb8390a9e8c042fc0cac96dda5a591ddf563c818adc730321cf693a5a9abc867d13f8704e37e7adc8171373b08f7c93b34e0677b6c6de7a134ba3b9bdc4bb2c
6
+ metadata.gz: ee5d09d524dff393bfbf5f1c159c496fdf4b8c28d849ea8b34782400aba76cf32af4ea5a066f008c95e224c6a3a275938baa5552a0ee39ae010f5e69fc5bf4c0
7
+ data.tar.gz: e75cf6c1468c337b8ab5b96bfdbc45cfc7a7fd5421849bc7123d0bb2f9090ed4656a7736476d9166c122c58f6f8a88979d7b6c2bd13ee400cd3bbe9770a6af41
@@ -32,7 +32,7 @@ jobs:
32
32
  strategy:
33
33
  fail-fast: false
34
34
  matrix:
35
- ruby: ["3.1", "3.2", "3.3", "3.4"]
35
+ ruby: ["3.2", "3.3", "3.4"]
36
36
 
37
37
  steps:
38
38
  - uses: actions/checkout@v2
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_gem:
3
3
 
4
4
  AllCops:
5
5
  DisplayCopNames: true
6
- TargetRubyVersion: 3.0
6
+ TargetRubyVersion: 3.2
7
7
  SuggestExtensions: false
8
8
  Include:
9
9
  - lib/**/*.rb
data/CHANGELOG.md CHANGED
@@ -1,6 +1,33 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [2.0.0] - 2026-09-23
5
+ ### Changed
6
+ - Upgraded `bunny` dependency to `~> 3.0`.
7
+ - Minimum supported Ruby version is now 3.2, as required by Bunny 3.
8
+ - `kicks` dependency now requires `>= 3.4`, the first version built on Bunny 3.
9
+
10
+ ### Removed
11
+ - Dropped support for Ruby 3.0 and 3.1.
12
+
13
+ ### Fixed
14
+ - `Rabbit::Publishing::Message` no longer raises `NoMethodError` when `headers` is
15
+ `nil` (regression in 1.8.0); such headers are published as an empty hash.
16
+ - `Rabbit::EventHandler.inherited` no longer overwrites a queue,
17
+ `ignore_queue_conversion` or job configs the subclass assigned before calling
18
+ `super` (the queue overwrite was introduced in 1.9.0).
19
+ - Publishing during a reconnect is retried again. Bunny 3.1+ raises
20
+ `Bunny::ChannelAlreadyClosed` instead of `Bunny::ConnectionClosedError` there,
21
+ which used to reach the caller. A publish already waiting for publisher confirms
22
+ when the connection drops still fails with `Rabbit::MessageNotDelivered` after
23
+ `continuation_timeout`.
24
+ - A channel the broker closed (e.g. a missing exchange) is retried once on a fresh
25
+ channel instead of `connection_reset_max_retries` times, and no longer fails an
26
+ unrelated publish that picks it from the pool.
27
+ - Rebuilding the channels pool no longer leaks the old connection: it is closed
28
+ (after recovery, if it is still recovering), concurrent failures rebuild the
29
+ pool once, and close errors go to `exception_notifier`.
30
+
4
31
  ## [1.9.0] - 2026-04-23
5
32
  ### Added
6
33
  - Fixed `queue` class variable inheritance for `queue_as` method.
data/Gemfile.lock CHANGED
@@ -8,9 +8,9 @@ GIT
8
8
  PATH
9
9
  remote: .
10
10
  specs:
11
- rabbit_messaging (1.9.0)
12
- bunny (~> 2.0)
13
- kicks
11
+ rabbit_messaging (2.0.0)
12
+ bunny (~> 3.0)
13
+ kicks (>= 3.4)
14
14
  msgpack
15
15
  zlib
16
16
 
@@ -38,13 +38,15 @@ GEM
38
38
  minitest (>= 5.1)
39
39
  securerandom (>= 0.3)
40
40
  tzinfo (~> 2.0, >= 2.0.5)
41
- amq-protocol (2.3.2)
41
+ amq-protocol (2.9.0)
42
42
  ast (2.4.2)
43
43
  base64 (0.2.0)
44
44
  benchmark (0.4.0)
45
45
  bigdecimal (3.1.9)
46
- bunny (2.23.0)
47
- amq-protocol (~> 2.3, >= 2.3.1)
46
+ bunny (3.4.0)
47
+ amq-protocol (~> 2.9)
48
+ logger (~> 1, >= 1.7)
49
+ openssl (>= 3.3)
48
50
  sorted_set (~> 1, >= 1.0.2)
49
51
  coderay (1.1.3)
50
52
  concurrent-ruby (1.3.5)
@@ -58,17 +60,18 @@ GEM
58
60
  concurrent-ruby (~> 1.0)
59
61
  io-console (0.8.0)
60
62
  json (2.10.0)
61
- kicks (3.2.0)
62
- bunny (~> 2.19)
63
+ kicks (3.4.0)
64
+ bunny (~> 3.0)
63
65
  concurrent-ruby (~> 1.0)
64
66
  rake (>= 12.3, < 14.0)
65
67
  serverengine (~> 2.1)
66
68
  thor
67
69
  language_server-protocol (3.17.0.4)
68
- logger (1.6.5)
70
+ logger (1.7.0)
69
71
  method_source (1.1.0)
70
72
  minitest (5.25.4)
71
73
  msgpack (1.8.0)
74
+ openssl (4.0.2)
72
75
  parallel (1.26.3)
73
76
  parser (3.3.7.1)
74
77
  ast (~> 2.4.1)
data/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Provides client and server support for RabbitMQ
4
4
 
5
+ ## Requirements
6
+
7
+ - Ruby >= 3.2
8
+ - Bunny ~> 3.0 (requires OpenSSL with TLS 1.3 support)
9
+
5
10
  ## Installation
6
11
 
7
12
  ```ruby
@@ -10,9 +10,9 @@ class Rabbit::EventHandler
10
10
 
11
11
  def inherited(subclass)
12
12
  super
13
- subclass.ignore_queue_conversion = false
14
- subclass.additional_job_configs = {}
15
- subclass.queue = queue
13
+ subclass.ignore_queue_conversion ||= false
14
+ subclass.additional_job_configs ||= {}
15
+ subclass.queue ||= queue
16
16
  end
17
17
 
18
18
  private
@@ -15,9 +15,14 @@ module Rabbit
15
15
  end
16
16
 
17
17
  def pop
18
- add_channel if size.zero?
18
+ loop do
19
+ add_channel if size.zero?
19
20
 
20
- super
21
+ channel = super
22
+ return channel if channel.open? || !ChannelsPool.live?(@session)
23
+
24
+ @ch_dec_mon.synchronize { @ch_size -= 1 }
25
+ end
21
26
  end
22
27
  alias_method :deq, :pop
23
28
 
@@ -53,7 +58,12 @@ module Rabbit
53
58
  end
54
59
  end
55
60
 
61
+ def self.live?(session)
62
+ !session.nil? && session.open? && !session.recovering_from_network_failure?
63
+ end
64
+
56
65
  def initialize(session)
66
+ @session = session
57
67
  max_size = session.channel_max
58
68
 
59
69
  @pools = {
@@ -62,12 +72,25 @@ module Rabbit
62
72
  }.freeze
63
73
  end
64
74
 
75
+ def close
76
+ @session.after_recovery_completed { Thread.new { close_session } }
77
+ close_session unless @session.recovering_from_network_failure?
78
+ end
79
+
65
80
  def with_channel(confirm)
66
81
  pool = @pools[confirm]
67
82
  ch = pool.deq
68
83
  yield ch
69
84
  ensure
70
- pool.enq ch
85
+ pool.enq ch if ch
86
+ end
87
+
88
+ private
89
+
90
+ def close_session
91
+ @session.close(false)
92
+ rescue StandardError => error
93
+ Rabbit.config.exception_notifier.call(error)
71
94
  end
72
95
  end
73
96
  end
@@ -25,9 +25,9 @@ module Rabbit::Publishing
25
25
  self.exchange_name = Array(exchange_name)
26
26
  self.confirm_select = confirm_select
27
27
  self.realtime = realtime
28
- self.headers = headers
28
+ self.headers = headers.to_h
29
29
  self.message_id = message_id
30
- self.compress = headers.with_indifferent_access.fetch(:compress, false)
30
+ self.compress = self.headers.with_indifferent_access.fetch(:compress, false)
31
31
  end
32
32
 
33
33
  def to_hash
@@ -10,34 +10,29 @@ module Rabbit
10
10
 
11
11
  MUTEX = Mutex.new
12
12
 
13
- def publish(msg) # rubocop:disable Metrics/MethodLength
13
+ def publish(msg)
14
14
  return if Rabbit.config.skip_publish?
15
15
 
16
16
  attempt = 0
17
+ retried_on_live_connection = false
17
18
  begin
18
- pool.with_channel msg.confirm_select? do |ch|
19
- ch.basic_publish *msg.basic_publish_args
19
+ current_pool = pool
20
+ deliver(current_pool, msg)
21
+ rescue Bunny::ChannelAlreadyClosed => error
22
+ if ChannelsPool.live?(error.channel&.connection)
23
+ raise error if retried_on_live_connection
20
24
 
21
- raise MessageNotDelivered, "RabbitMQ message not delivered: #{msg}" \
22
- if msg.confirm_select? && !ch.wait_for_confirms
23
-
24
- log msg
25
- end
26
- rescue *Rabbit.config.connection_reset_exceptions => error
27
- attempt += 1
28
- if attempt <= Rabbit.config.connection_reset_max_retries
29
- sleep(Rabbit.config.connection_reset_timeout)
30
- reinitialize_channels_pool
25
+ retried_on_live_connection = true
31
26
  retry
32
- else
33
- raise error
34
27
  end
28
+
29
+ attempt = reconnect_or_raise(error, attempt, current_pool)
30
+ retry
31
+ rescue *Rabbit.config.connection_reset_exceptions => error
32
+ attempt = reconnect_or_raise(error, attempt, current_pool)
33
+ retry
35
34
  rescue Timeout::Error
36
- raise MessageNotDelivered, <<~MESSAGE
37
- Timeout while sending message #{msg}. Possible reasons:
38
- - #{msg.real_exchange_name} exchange is not found
39
- - RabbitMQ is extremely high loaded
40
- MESSAGE
35
+ raise MessageNotDelivered, timeout_message(msg)
41
36
  end
42
37
  end
43
38
 
@@ -47,6 +42,17 @@ module Rabbit
47
42
 
48
43
  private
49
44
 
45
+ def deliver(channels_pool, msg)
46
+ channels_pool.with_channel msg.confirm_select? do |ch|
47
+ ch.basic_publish *msg.basic_publish_args
48
+
49
+ raise MessageNotDelivered, "RabbitMQ message not delivered: #{msg}" \
50
+ if msg.confirm_select? && !ch.wait_for_confirms
51
+
52
+ log msg
53
+ end
54
+ end
55
+
50
56
  def create_queue_if_not_exists(channel, message)
51
57
  channel.queue(message.routing_key, durable: true)
52
58
  end
@@ -71,8 +77,31 @@ module Rabbit
71
77
  log_by_parts(message, metadata: metadata)
72
78
  end
73
79
 
74
- def reinitialize_channels_pool
75
- MUTEX.synchronize { @pool = ChannelsPool.new(create_client) }
80
+ def timeout_message(msg)
81
+ <<~MESSAGE
82
+ Timeout while sending message #{msg}. Possible reasons:
83
+ - #{msg.real_exchange_name} exchange is not found
84
+ - RabbitMQ is extremely high loaded
85
+ MESSAGE
86
+ end
87
+
88
+ def reconnect_or_raise(error, attempt, failed_pool)
89
+ attempt += 1
90
+ raise error if attempt > Rabbit.config.connection_reset_max_retries
91
+
92
+ sleep(Rabbit.config.connection_reset_timeout)
93
+ reinitialize_channels_pool(failed_pool)
94
+ attempt
95
+ end
96
+
97
+ def reinitialize_channels_pool(failed_pool)
98
+ MUTEX.synchronize do
99
+ return unless @pool.equal?(failed_pool)
100
+
101
+ @pool = ChannelsPool.new(create_client)
102
+ end
103
+
104
+ failed_pool&.close
76
105
  end
77
106
 
78
107
  def log_compressed(message_for_publish, metadata:)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabbit
4
- VERSION = "1.9.0"
4
+ VERSION = "2.0.0"
5
5
  end
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "rabbit/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.required_ruby_version = ">= 3.0"
8
+ spec.required_ruby_version = ">= 3.2"
9
9
 
10
10
  spec.name = "rabbit_messaging"
11
11
  spec.version = Rabbit::VERSION
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency "bunny", "~> 2.0"
23
- spec.add_dependency "kicks"
22
+ spec.add_dependency "bunny", "~> 3.0"
23
+ spec.add_dependency "kicks", ">= 3.4"
24
24
  spec.add_dependency "msgpack"
25
25
  spec.add_dependency "zlib"
26
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabbit_messaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Umbrellio
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '2.0'
18
+ version: '3.0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '2.0'
25
+ version: '3.0'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: kicks
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: '3.4'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
39
+ version: '3.4'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: msgpack
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -119,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - ">="
121
121
  - !ruby/object:Gem::Version
122
- version: '3.0'
122
+ version: '3.2'
123
123
  required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - ">="