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 +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +27 -0
- data/Gemfile.lock +12 -9
- data/README.md +5 -0
- data/lib/rabbit/event_handler.rb +3 -3
- data/lib/rabbit/publishing/channels_pool.rb +26 -3
- data/lib/rabbit/publishing/message.rb +2 -2
- data/lib/rabbit/publishing.rb +51 -22
- data/lib/rabbit/version.rb +1 -1
- data/rabbit_messaging.gemspec +3 -3
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d298261bbcdb67fa9e0a784af3caa96a327a78c53a690eba4a04bd275e5d7d87
|
|
4
|
+
data.tar.gz: 25597ce02a4ff8a14805bfcc0e93356eac64d625327d786e86f35a7b5fa5b3ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee5d09d524dff393bfbf5f1c159c496fdf4b8c28d849ea8b34782400aba76cf32af4ea5a066f008c95e224c6a3a275938baa5552a0ee39ae010f5e69fc5bf4c0
|
|
7
|
+
data.tar.gz: e75cf6c1468c337b8ab5b96bfdbc45cfc7a7fd5421849bc7123d0bb2f9090ed4656a7736476d9166c122c58f6f8a88979d7b6c2bd13ee400cd3bbe9770a6af41
|
data/.github/workflows/test.yml
CHANGED
data/.rubocop.yml
CHANGED
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 (
|
|
12
|
-
bunny (~>
|
|
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.
|
|
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 (
|
|
47
|
-
amq-protocol (~> 2.
|
|
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.
|
|
62
|
-
bunny (~>
|
|
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.
|
|
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
data/lib/rabbit/event_handler.rb
CHANGED
|
@@ -10,9 +10,9 @@ class Rabbit::EventHandler
|
|
|
10
10
|
|
|
11
11
|
def inherited(subclass)
|
|
12
12
|
super
|
|
13
|
-
subclass.ignore_queue_conversion
|
|
14
|
-
subclass.additional_job_configs
|
|
15
|
-
subclass.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
|
-
|
|
18
|
+
loop do
|
|
19
|
+
add_channel if size.zero?
|
|
19
20
|
|
|
20
|
-
|
|
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
|
data/lib/rabbit/publishing.rb
CHANGED
|
@@ -10,34 +10,29 @@ module Rabbit
|
|
|
10
10
|
|
|
11
11
|
MUTEX = Mutex.new
|
|
12
12
|
|
|
13
|
-
def publish(msg)
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
75
|
-
|
|
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:)
|
data/lib/rabbit/version.rb
CHANGED
data/rabbit_messaging.gemspec
CHANGED
|
@@ -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.
|
|
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", "~>
|
|
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:
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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.
|
|
122
|
+
version: '3.2'
|
|
123
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
124
|
requirements:
|
|
125
125
|
- - ">="
|