rabbit_messaging 1.6.3 → 1.8.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: c45c2e39c99e1b98df503e6e3bca993494c23de174c4128fc01d92a52c6c14aa
4
- data.tar.gz: 18cbcd032389ba70240633bb06929c5f1c6ea687cdf5b52e311f50d99dca2778
3
+ metadata.gz: a10737146cf3e6407d500b5cb61af3c6340a435babad47ac7087a5bb966dfd69
4
+ data.tar.gz: '0589fbc1d041763ee953c7a4763814daa66b1f241c8536a2096f43420d2b00e4'
5
5
  SHA512:
6
- metadata.gz: 9e59c4b4e78c0839abff9afcd4aaaaf649d0f81ff14a95864ea46091247eb299a22aac0c1b84ab310c026375c7902077abf39bc4a2b767e672dab7032045e6b7
7
- data.tar.gz: 0aac8ba6c08010ffae05038aa46ff924672d3ec4ae2d96bf2669ba6be6013224574dfdd7c5f2231a6ff6072bb51634a5b522cca87a29bccfcce39050821cdfad
6
+ metadata.gz: 8976861c50915a84af982e2f98d35fd982cce74bd52aa59974bfb213a8dcb65fa10b7b45fee8faf4b13b663ed1b12fb97b23c4d635eb272ddfe8982656da661a
7
+ data.tar.gz: 7db3fad61e5d9caa136a0799d3b96f6785e4b94f68db8fca7d9d1f60862c6e2821f7a0fe2b47ef8b1f650881aae772a17632dcf6635ec728290da8cc27e37670
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [1.8.0] - 2026-03-25
5
+ ### Added
6
+ - Ability to compress data on publisher level and decompress on consumer
7
+
8
+ ## [1.7.0] - 2025-08-19
9
+ ### Added
10
+ - Ability to specify a custom job class for publishing via `publishing_job_class_callable` config.
11
+ - Ability to specify a default queue for publishing jobs via `default_publishing_job_queue` config.
12
+ - Ability to specify a custom queue per publish call via `custom_queue_name` argument.
13
+
4
14
  ## [1.5.0] - 2025-05-19
5
15
  ### Added
6
16
  - Added ability to split log message into parts
data/Gemfile.lock CHANGED
@@ -8,9 +8,11 @@ GIT
8
8
  PATH
9
9
  remote: .
10
10
  specs:
11
- rabbit_messaging (1.6.3)
11
+ rabbit_messaging (1.8.0)
12
12
  bunny (~> 2.0)
13
13
  kicks
14
+ msgpack
15
+ zlib
14
16
 
15
17
  GEM
16
18
  remote: https://rubygems.org/
@@ -66,6 +68,7 @@ GEM
66
68
  logger (1.6.5)
67
69
  method_source (1.1.0)
68
70
  minitest (5.25.4)
71
+ msgpack (1.8.0)
69
72
  parallel (1.26.3)
70
73
  parser (3.3.7.1)
71
74
  ast (~> 2.4.1)
@@ -158,6 +161,7 @@ GEM
158
161
  unicode-display_width (3.1.4)
159
162
  unicode-emoji (~> 4.0, >= 4.0.4)
160
163
  unicode-emoji (4.0.4)
164
+ zlib (3.2.3)
161
165
 
162
166
  PLATFORMS
163
167
  arm64-darwin
data/README.md CHANGED
@@ -97,6 +97,14 @@ require "rabbit_messaging"
97
97
  }
98
98
  ```
99
99
 
100
+ - `publishing_job_class_callable` (`Proc`)
101
+
102
+ Custom job class (e.g. ActiveJob or Sidekiq::Job) to work with published messages.
103
+
104
+ - `default_publishing_job_queue` (`String` or `Symbol`)
105
+
106
+ The name of the queue that will be used by default for publishing jobs. `default` by default.
107
+
100
108
  - `before_receiving_hooks, after_receiving_hooks` (`Array of Procs`)
101
109
 
102
110
  Before and after hooks with message processing in the middle. Where `before_receiving_hooks` and `after_receiving_hooks` are empty arrays by default.
@@ -139,7 +147,7 @@ require "rabbit_messaging"
139
147
  - `connection_reset_max_retries` (`Integer`)
140
148
 
141
149
  Maximum number of reconnection attempts after a connection loss. Default: 10.
142
-
150
+
143
151
  ```ruby
144
152
  config.connection_reset_max_retries = 20
145
153
  ```
@@ -165,13 +173,16 @@ require "rabbit_messaging"
165
173
 
166
174
  ```ruby
167
175
  Rabbit.publish(
168
- routing_key: :support,
169
- event: :ping,
170
- data: { foo: :bar }, # default is {}
171
- exchange_name: 'fanout', # default is fine too
172
- confirm_select: true, # setting this to false grants you great speed up and absolutelly no guarantees
173
- headers: { "foo" => "bar" }, # custom arguments for routing, default is {}
174
- message_id: "asdadsadsad", # A unique identifier such as a UUID that your application can use to identify the message.
176
+ {
177
+ routing_key: :support,
178
+ event: :ping,
179
+ data: { foo: :bar }, # default is {}
180
+ exchange_name: 'fanout', # default is fine too
181
+ confirm_select: true, # setting this to false grants you great speed up and absolutelly no guarantees
182
+ headers: { "foo" => "bar" }, # custom arguments for routing, default is {}
183
+ message_id: "asdadsadsad", # A unique identifier such as a UUID that your application can use to identify the message.
184
+ },
185
+ custom_queue_name: :my_custom_queue, # The name of the queue for publishing jobs. Overrides the default queue.
175
186
  )
176
187
  ```
177
188
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "msgpack"
4
+ require "zlib"
5
+ require "base64"
6
+
7
+ module Rabbit::Compressor
8
+ Error = Class.new(StandardError)
9
+ UncompressingError = Class.new(Error)
10
+
11
+ extend self
12
+
13
+ delegate :decode64, :strict_encode64, to: Base64
14
+
15
+ def dump(data, msgpack_options: {}, with_base64: false)
16
+ dumped = Zlib::Deflate.deflate(MessagePack.pack(data, msgpack_options))
17
+
18
+ return dumped unless with_base64
19
+
20
+ strict_encode64(dumped)
21
+ end
22
+
23
+ def load(data, msgpack_options: {}, with_base64: false)
24
+ return {} unless data
25
+
26
+ data = decode64(data) if with_base64
27
+
28
+ MessagePack.unpack(Zlib::Inflate.inflate(data), msgpack_options)
29
+ rescue Zlib::Error, MessagePack::UnpackError => error
30
+ raise UncompressingError, "Unable to uncompress data, #{error}"
31
+ end
32
+ end
data/lib/rabbit/helper.rb CHANGED
@@ -2,16 +2,22 @@
2
2
 
3
3
  module Rabbit
4
4
  module Helper
5
- def self.generate_message(message_part, parts, index)
5
+ def self.generate_message(message_part, parts, index, compressed: false)
6
6
  if parts == 1
7
- message_part
7
+ format(message_part, compressed)
8
8
  elsif index.zero?
9
- "#{message_part}..."
9
+ "#{format(message_part, compressed)}..."
10
10
  elsif index == parts - 1
11
- "...#{message_part}"
11
+ "...#{format(message_part, compressed)}"
12
12
  else
13
- "...#{message_part}..."
13
+ "...#{format(message_part, compressed)}..."
14
14
  end
15
15
  end
16
+
17
+ def self.format(message_part, compressed)
18
+ return message_part unless compressed
19
+
20
+ "message bytes #{message_part.bytesize}"
21
+ end
16
22
  end
17
23
  end
@@ -5,7 +5,7 @@ require "rabbit/publishing"
5
5
  module Rabbit::Publishing
6
6
  class Job < ActiveJob::Base
7
7
  def perform(message)
8
- Rabbit::Publishing.publish(Message.new(message))
8
+ Rabbit::Publishing.publish(Message.new(**message))
9
9
  end
10
10
  end
11
11
  end
@@ -2,30 +2,41 @@
2
2
 
3
3
  module Rabbit::Publishing
4
4
  class Message
5
- attr_accessor :routing_key, :event, :data,
5
+ attr_accessor :routing_key, :event, :data, :compress,
6
6
  :confirm_select, :realtime, :headers, :message_id
7
7
  attr_reader :exchange_name
8
8
 
9
9
  alias_method :confirm_select?, :confirm_select
10
10
  alias_method :realtime?, :realtime
11
11
 
12
- def initialize(attributes = {})
13
- self.routing_key = attributes[:routing_key]
14
- self.event = attributes[:event]&.to_s
15
- self.data = attributes.fetch(:data, {})
16
- self.exchange_name = Array(attributes.fetch(:exchange_name, []))
17
- self.confirm_select = attributes.fetch(:confirm_select, true)
18
- self.realtime = attributes.fetch(:realtime, false)
19
- self.headers = attributes.fetch(:headers, {})
20
- self.message_id = attributes[:message_id]
12
+ def initialize(
13
+ routing_key: nil,
14
+ event: nil,
15
+ data: {},
16
+ exchange_name: [],
17
+ confirm_select: true,
18
+ realtime: false,
19
+ headers: {},
20
+ message_id: nil
21
+ )
22
+ self.routing_key = routing_key
23
+ self.event = event&.to_s
24
+ self.data = data
25
+ self.exchange_name = Array(exchange_name)
26
+ self.confirm_select = confirm_select
27
+ self.realtime = realtime
28
+ self.headers = headers
29
+ self.message_id = message_id
30
+ self.compress = headers.with_indifferent_access.fetch(:compress, false)
21
31
  end
22
32
 
23
33
  def to_hash
24
34
  instance_variables.each_with_object({}) do |var, hash|
25
35
  key = var.to_s.delete("@").to_sym
36
+ next if key == :compress
26
37
  value = instance_variable_get(var)
27
38
  hash[key] = value
28
- end.merge(data: JSON.parse(data.to_json))
39
+ end.merge(data: data_for_hash)
29
40
  end
30
41
 
31
42
  def to_s
@@ -46,9 +57,11 @@ module Rabbit::Publishing
46
57
  app_id: Rabbit.config.app_name,
47
58
  headers: headers,
48
59
  message_id: message_id,
49
- }
60
+ }.tap do |ops|
61
+ ops[:content_encoding] = "gzip" if compress
62
+ end
50
63
 
51
- [JSON.dump(data), real_exchange_name, routing_key.to_s, options]
64
+ [dumped_data, real_exchange_name, routing_key.to_s, options]
52
65
  end
53
66
 
54
67
  def exchange_name=(names)
@@ -58,5 +71,22 @@ module Rabbit::Publishing
58
71
  def real_exchange_name
59
72
  [Rabbit.config.group_id, Rabbit.config.project_id, *exchange_name].join(".")
60
73
  end
74
+
75
+ def dumped_data
76
+ return JSON.dump(data) unless compress
77
+ # NOTE: when compress true and realtime false it means data from job
78
+ # already has been compressed and encoded in base64
79
+ return Rabbit::Compressor.dump(data) if realtime
80
+
81
+ Rabbit::Compressor.decode64(data)
82
+ end
83
+
84
+ private
85
+
86
+ def data_for_hash
87
+ return JSON.parse(data.to_json) unless compress
88
+
89
+ Rabbit::Compressor.dump(data, with_base64: true)
90
+ end
61
91
  end
62
92
  end
@@ -66,17 +66,35 @@ module Rabbit
66
66
  message.event, message.confirm_select? ? "confirm" : "no-confirm"
67
67
  ]
68
68
 
69
- message_parts = JSON.dump(message.data)
70
- .scan(/.{1,#{Rabbit.config.logger_message_size_limit}}/)
69
+ return log_compressed(message.dumped_data, metadata: metadata) if message.compress
71
70
 
72
- message_parts.each_with_index do |message_part, index|
73
- message = Rabbit::Helper.generate_message(message_part, message_parts.size, index)
74
- @logger.debug "#{metadata.join ' / '}: #{message}"
75
- end
71
+ log_by_parts(message, metadata: metadata)
76
72
  end
77
73
 
78
74
  def reinitialize_channels_pool
79
75
  MUTEX.synchronize { @pool = ChannelsPool.new(create_client) }
80
76
  end
77
+
78
+ def log_compressed(message_for_publish, metadata:)
79
+ formatted_message = Rabbit::Helper.generate_message(
80
+ message_for_publish, 1, 0, compressed: true
81
+ )
82
+
83
+ @logger.debug "#{metadata.join ' / '}: #{formatted_message}"
84
+ end
85
+
86
+ def log_by_parts(message_for_publish, metadata:)
87
+ message_parts =
88
+ message_for_publish
89
+ .dumped_data
90
+ .scan(/.{1,#{Rabbit.config.logger_message_size_limit}}/)
91
+
92
+ message_parts.each_with_index do |message_part, index|
93
+ formatted_message = Rabbit::Helper.generate_message(
94
+ message_part, message_parts.size, index
95
+ )
96
+ @logger.debug "#{metadata.join ' / '}: #{formatted_message}"
97
+ end
98
+ end
81
99
  end
82
100
  end
@@ -4,7 +4,7 @@ require "rabbit/receiving/malformed_message"
4
4
 
5
5
  module Rabbit::Receiving
6
6
  class Message
7
- attr_accessor :group_id, :project_id, :message_id,
7
+ attr_accessor :group_id, :project_id, :message_id, :compress,
8
8
  :event, :arguments, :original_message
9
9
  attr_reader :data
10
10
 
@@ -15,6 +15,7 @@ module Rabbit::Receiving
15
15
  group_id: group_id,
16
16
  project_id: project_id,
17
17
  event: arguments.fetch(:type),
18
+ compress: arguments.dig(:headers, "compress") || false,
18
19
  data: message,
19
20
  message_id: arguments.fetch(:message_id, nil),
20
21
  arguments: arguments,
@@ -28,12 +29,14 @@ module Rabbit::Receiving
28
29
  event: nil,
29
30
  data: nil,
30
31
  arguments: nil,
31
- original_message: nil
32
+ original_message: nil,
33
+ compress: false
32
34
  )
33
35
  self.group_id = group_id
34
36
  self.project_id = project_id
35
37
  self.message_id = message_id
36
38
  self.event = event
39
+ self.compress = compress
37
40
  self.data = data unless data.nil?
38
41
  self.arguments = arguments
39
42
  self.original_message = original_message
@@ -41,7 +44,7 @@ module Rabbit::Receiving
41
44
 
42
45
  def data=(value)
43
46
  self.original_message = value
44
- parsed = JSON.parse(value).deep_symbolize_keys
47
+ parsed = parsed_data(value)
45
48
  @data = parsed
46
49
  rescue JSON::ParserError => error
47
50
  mark_as_malformed!("JSON::ParserError: #{error.message}")
@@ -60,7 +63,16 @@ module Rabbit::Receiving
60
63
  data: data,
61
64
  arguments: arguments,
62
65
  original_message: original_message,
66
+ compress: compress,
63
67
  }
64
68
  end
69
+
70
+ private
71
+
72
+ def parsed_data(value)
73
+ return JSON.parse(value).deep_symbolize_keys unless compress
74
+
75
+ Rabbit::Compressor.load(value, msgpack_options: { symbolize_keys: true }, with_base64: true)
76
+ end
65
77
  end
66
78
  end
@@ -4,6 +4,7 @@ require "sneakers"
4
4
 
5
5
  require "rabbit"
6
6
  require "rabbit/receiving/receive"
7
+ require "base64"
7
8
 
8
9
  class Rabbit::Receiving::Worker
9
10
  include Sneakers::Worker
@@ -29,8 +30,10 @@ class Rabbit::Receiving::Worker
29
30
  end
30
31
 
31
32
  def receive_message(message, delivery_info, arguments)
33
+ compress = arguments.dig(:headers, "compress") || false
34
+
32
35
  Rabbit::Receiving::Receive.new(
33
- message: message.dup.force_encoding("UTF-8"),
36
+ message: prepare_message_for_receiving(message.dup, compress),
34
37
  delivery_info: delivery_info,
35
38
  arguments: arguments,
36
39
  ).call
@@ -49,4 +52,12 @@ class Rabbit::Receiving::Worker
49
52
  @queue.instance_variable_set(:@banny, nil)
50
53
  run
51
54
  end
55
+
56
+ private
57
+
58
+ def prepare_message_for_receiving(message, compress)
59
+ return Base64.strict_encode64(message.b) if compress
60
+
61
+ message.force_encoding("UTF-8")
62
+ end
52
63
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabbit
4
- VERSION = "1.6.3"
4
+ VERSION = "1.8.0"
5
5
  end
data/lib/rabbit.rb CHANGED
@@ -4,6 +4,7 @@ require "rabbit/version"
4
4
  require "rabbit/daemon"
5
5
  require "rabbit/publishing"
6
6
  require "rabbit/event_handler"
7
+ require "rabbit/compressor"
7
8
 
8
9
  require "rabbit/extensions/bunny/channel"
9
10
 
@@ -18,6 +19,8 @@ module Rabbit
18
19
  :hooks,
19
20
  :queue_name_conversion,
20
21
  :receiving_job_class_callable,
22
+ :publishing_job_class_callable,
23
+ :default_publishing_job_queue,
21
24
  :handler_resolver_callable,
22
25
  :exception_notifier,
23
26
  :before_receiving_hooks,
@@ -41,6 +44,8 @@ module Rabbit
41
44
  environment: :production,
42
45
  queue_name_conversion: nil,
43
46
  receiving_job_class_callable: nil,
47
+ publishing_job_class_callable: nil,
48
+ default_publishing_job_queue: :default,
44
49
  handler_resolver_callable: nil,
45
50
  exception_notifier: nil,
46
51
  before_receiving_hooks: [],
@@ -63,6 +68,8 @@ module Rabbit
63
68
  self.environment = environment.to_sym
64
69
  self.queue_name_conversion = queue_name_conversion
65
70
  self.receiving_job_class_callable = receiving_job_class_callable
71
+ self.publishing_job_class_callable = publishing_job_class_callable
72
+ self.default_publishing_job_queue = default_publishing_job_queue
66
73
  self.handler_resolver_callable = handler_resolver_callable
67
74
  self.exception_notifier = exception_notifier
68
75
  self.before_receiving_hooks = before_receiving_hooks
@@ -163,13 +170,35 @@ module Rabbit
163
170
  config.validate!
164
171
  end
165
172
 
166
- def publish(message_options)
167
- message = Publishing::Message.new(message_options)
173
+ def publish(
174
+ routing_key: nil,
175
+ event: nil,
176
+ data: {},
177
+ exchange_name: [],
178
+ confirm_select: true,
179
+ realtime: false,
180
+ headers: {},
181
+ message_id: nil,
182
+ custom_queue_name: nil
183
+ )
184
+ message = Publishing::Message.new(
185
+ routing_key: routing_key,
186
+ event: event,
187
+ data: data,
188
+ exchange_name: exchange_name,
189
+ confirm_select: confirm_select,
190
+ realtime: realtime,
191
+ headers: headers,
192
+ message_id: message_id,
193
+ )
194
+ job_class = config.publishing_job_class_callable
195
+ publish_job_callable = job_class.is_a?(Proc) ? job_class.call : (job_class || Publishing::Job)
196
+ queue_name = custom_queue_name || default_queue_name
168
197
 
169
198
  if message.realtime?
170
199
  Publishing.publish(message)
171
200
  else
172
- Publishing::Job.set(queue: default_queue_name).perform_later(message.to_hash)
201
+ publish_job_callable.set(queue: queue_name).perform_later(message.to_hash)
173
202
  end
174
203
  end
175
204
 
@@ -179,6 +208,6 @@ module Rabbit
179
208
  end
180
209
 
181
210
  def default_queue_name(ignore_conversion: false)
182
- queue_name(:default, ignore_conversion: ignore_conversion)
211
+ queue_name(config.default_publishing_job_queue, ignore_conversion: ignore_conversion)
183
212
  end
184
213
  end
@@ -21,4 +21,6 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_dependency "bunny", "~> 2.0"
23
23
  spec.add_dependency "kicks"
24
+ spec.add_dependency "msgpack"
25
+ spec.add_dependency "zlib"
24
26
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabbit_messaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.3
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Umbrellio
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-06-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bunny
@@ -38,6 +37,34 @@ dependencies:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
39
  version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: msgpack
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: zlib
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
41
68
  description: Rabbit (Rabbit Messaging)
42
69
  email:
43
70
  - oss@umbrellio.biz
@@ -60,6 +87,7 @@ files:
60
87
  - config/sneakers.yml
61
88
  - environments/development.rb
62
89
  - lib/rabbit.rb
90
+ - lib/rabbit/compressor.rb
63
91
  - lib/rabbit/daemon.rb
64
92
  - lib/rabbit/event_handler.rb
65
93
  - lib/rabbit/extensions/bunny/channel.rb
@@ -84,7 +112,6 @@ files:
84
112
  homepage: https://github.com/umbrellio/rabbit_messaging
85
113
  licenses: []
86
114
  metadata: {}
87
- post_install_message:
88
115
  rdoc_options: []
89
116
  require_paths:
90
117
  - lib
@@ -99,8 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
126
  - !ruby/object:Gem::Version
100
127
  version: '0'
101
128
  requirements: []
102
- rubygems_version: 3.5.3
103
- signing_key:
129
+ rubygems_version: 3.6.9
104
130
  specification_version: 4
105
131
  summary: Rabbit (Rabbit Messaging)
106
132
  test_files: []