deimos-ruby 2.3.0.pre.beta4 → 2.4.0.pre.beta1

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: f8e48e6252ea21b5af3a7f2ec921f7a82db95e6286eaf52ac15f94ad8e1043d6
4
- data.tar.gz: 99bf9b5ecb064e644897e1ef2177704d460b9531a9fc51e551b8462f22fe1943
3
+ metadata.gz: 597f226ba74e9b5acce2906ee0fea563a3ff2b7a5b47bef0d4e66d840410ed42
4
+ data.tar.gz: 876b9a70bc598bb99084a0bad47d6285c728efa54d98346761346c4313dda968
5
5
  SHA512:
6
- metadata.gz: 7cf3edfdf000781943adb58eddc2e73e2fa2c8b7cede12cfbebc1407235af33459b44402602a9e26534187f81df9ed67a38029ffc917d0c94e4e0a8924645929
7
- data.tar.gz: da90d82a5919b02893b7877e668a287f3deb64c766f6b5a5543d6217b2782c14ab4b0c87f87f0dcad8e537905b5b480d53f756530eb1b4c6e187c0569f13b0f0
6
+ metadata.gz: 58d7dfcf2cfbbbda7c4ce3459931a89ba6bf6261f6bd4a2cdf1bc2de640200fdc2a9a36f0af414bbcfef3de45fe8b3053795cdd5b139cf10a747a16a82989ccc
7
+ data.tar.gz: 35ab518ca7bcbc48d2810ec67ce30a9331816fdc08caa52c602406f6b79346f7bf806af3adc50b427e5d412ce478c55f5e29b49f0bc61f2c88dc1ca81b11f993
data/CHANGELOG.md CHANGED
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - Major change: Switch from using `avro_turf` and `proto_turf` to use `schema_registry_client`, which handles both Avro and Protobuf.
11
11
 
12
+ # 2.3.0 - 2026-01-13
13
+
14
+ - Feature: Support broker setting per topic in producer configs.
15
+
12
16
  # 2.2.2 - 2025-11-7
13
17
 
14
18
  - Fix: Calling `producer_classes` on a topic config could make all topics disappear. :(
data/README.md CHANGED
@@ -139,6 +139,12 @@ end
139
139
 
140
140
  Note that if you are using Protobuf, you need to pass a Protobuf message object as the payload - you can't use a bare hash.
141
141
 
142
+ ## Multiple clusters
143
+
144
+ If you have topics that are being routed to different clusters via Karafka configs, you can continue to make use of Deimos producers without having to instantiate the producer itself. Instead of calling `MyProducer.produce(message)`, you can call `Deimos.producer_for('MyTopic').produce(message)`.
145
+
146
+ Deimos will keep around one producer per broker server (i.e. `bootstrap.servers` config) that it sees on startup.
147
+
142
148
  ## Auto-added Fields
143
149
 
144
150
  If your schema has a field called `message_id`, and the payload you give
@@ -6,7 +6,7 @@ module Deimos
6
6
  class Kafka < Base
7
7
  # :nodoc:
8
8
  def self.execute(producer_class:, messages:)
9
- Karafka.producer.produce_many_sync(messages)
9
+ Deimos.producer_for(producer_class.topic).produce_many_sync(messages)
10
10
  end
11
11
  end
12
12
  end
@@ -4,9 +4,10 @@ module Deimos
4
4
  module Backends
5
5
  # Backend which produces to Kafka via an async producer.
6
6
  class KafkaAsync < Base
7
+
7
8
  # :nodoc:
8
9
  def self.execute(producer_class:, messages:)
9
- Karafka.producer.produce_many_async(messages)
10
+ Deimos.producer_for(producer_class.topic).produce_many_async(messages)
10
11
  end
11
12
  end
12
13
  end
@@ -58,7 +58,9 @@ module Deimos
58
58
  end
59
59
  end
60
60
  Karafka::Setup::Config.setup if Karafka.producer.nil?
61
- Karafka.producer.monitor.subscribe(waterdrop_listener)
61
+ Deimos.waterdrop_producers.each do |producer|
62
+ producer.monitor.subscribe(waterdrop_listener)
63
+ end
62
64
  end
63
65
 
64
66
  # :nodoc:
@@ -16,6 +16,14 @@ module Deimos
16
16
  def self.included(base)
17
17
  super
18
18
  base.include Karafka::Testing::RSpec::Helpers
19
+
20
+ # Ensure that we only use Karafka.producer, not the producers we set up for multi-broker
21
+ # configs. Only Karafka.producer works with Karafka test helpers.
22
+ RSpec.configure do |config|
23
+ config.before(:each) do
24
+ allow(Deimos).to receive(:producer_for).and_return(Karafka.producer)
25
+ end
26
+ end
19
27
  end
20
28
 
21
29
  # @return [Array<Hash>]
@@ -207,7 +207,7 @@ module Deimos
207
207
 
208
208
  batch[current_index..].in_groups_of(batch_size, false).each do |group|
209
209
  @logger.debug("Publishing #{group.size} messages to #{@current_topic}")
210
- Karafka.producer.produce_many_sync(group)
210
+ Deimos.producer_for(@current_topic).produce_many_sync(group)
211
211
  current_index += group.size
212
212
  @logger.info("Sent #{group.size} messages to #{@current_topic}")
213
213
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '2.3.0-beta4'
4
+ VERSION = '2.4.0-beta1'
5
5
  end
data/lib/deimos.rb CHANGED
@@ -142,23 +142,34 @@ module Deimos
142
142
  signal_handler.run!
143
143
  end
144
144
 
145
- def setup_karafka
146
- Karafka.producer.middleware.append(Deimos::ProducerMiddleware)
147
- # for multiple setup calls
148
- Karafka.producer.config.kafka =
149
- Karafka::Setup::AttributesMap.producer(Karafka::Setup::Config.config.kafka.dup)
150
- EVENT_TYPES.each { |type| Karafka.monitor.notifications_bus.register_event(type) }
151
-
152
- Karafka.producer.monitor.subscribe(ProducerMetricsListener.new)
145
+ def setup_producers
146
+ @producers = {}
147
+ producers_by_broker = {}
148
+ Deimos.karafka_configs.each do |topic|
149
+ broker = topic.kafka[:'bootstrap.servers']
150
+ producers_by_broker[broker] ||= ::WaterDrop::Producer.new do |p_config|
151
+ config_hash = Karafka::Setup::Config.config.kafka.merge(topic.kafka)
152
+ p_config.kafka = Karafka::Setup::AttributesMap.producer(config_hash)
153
+ end
154
+ @producers[topic.name] = producers_by_broker[broker]
155
+ end
156
+ end
153
157
 
154
- Karafka.producer.monitor.subscribe('error.occurred') do |event|
155
- if event.payload.key?(:messages)
156
- topic = event[:messages].first[:topic]
157
- config = Deimos.karafka_config_for(topic: topic)
158
- message = Deimos::Logging.messages_log_text(config&.payload_log, event[:messages])
159
- Karafka.logger.error("Error producing messages: #{event[:error].message} #{message.to_json}")
158
+ def setup_karafka
159
+ setup_producers
160
+ waterdrop_producers.each do |producer|
161
+ producer.middleware.append(Deimos::ProducerMiddleware)
162
+ producer.monitor.subscribe(ProducerMetricsListener.new)
163
+ producer.monitor.subscribe('error.occurred') do |event|
164
+ if event.payload.key?(:messages)
165
+ topic = event[:messages].first[:topic]
166
+ config = Deimos.karafka_config_for(topic: topic)
167
+ message = Deimos::Logging.messages_log_text(config&.payload_log, event[:messages])
168
+ Karafka.logger.error("Error producing messages: #{event[:error].message} #{message.to_json}")
169
+ end
160
170
  end
161
171
  end
172
+ EVENT_TYPES.each { |type| Karafka.monitor.notifications_bus.register_event(type) }
162
173
  end
163
174
 
164
175
  # @return [Array<Karafka::Routing::Topic]
@@ -176,7 +187,16 @@ module Deimos
176
187
  end
177
188
  end
178
189
 
179
- # @param handler_class [Class]
190
+ # @return [Array<::WaterDrop::Producer>]
191
+ def waterdrop_producers
192
+ (@producers.values + [Karafka.producer]).uniq
193
+ end
194
+
195
+ # @param topic [String]
196
+ def producer_for(topic)
197
+ @producers[topic] || Karafka.producer
198
+ end
199
+
180
200
  # @return [String,nil]
181
201
  def topic_for_consumer(handler_class)
182
202
  Deimos.karafka_configs.each do |topic|
data/spec/deimos_spec.rb CHANGED
@@ -50,4 +50,36 @@ describe Deimos do
50
50
  end
51
51
  end
52
52
 
53
+ specify '#producer_for' do
54
+ allow(described_class).to receive(:producer_for).and_call_original
55
+ Karafka::App.routes.redraw do
56
+ topic 'main-broker' do
57
+ active false
58
+ kafka({
59
+ 'bootstrap.servers': 'broker1:9092'
60
+ })
61
+ end
62
+ topic 'main-broker2' do
63
+ active false
64
+ kafka({
65
+ 'bootstrap.servers': 'broker1:9092'
66
+ })
67
+ end
68
+ topic 'other-broker' do
69
+ active false
70
+ kafka({
71
+ 'bootstrap.servers': 'broker2:9092'
72
+ })
73
+ end
74
+ end
75
+ described_class.setup_producers
76
+
77
+ producer1 = described_class.producer_for('main-broker')
78
+ producer2 = described_class.producer_for('main-broker2')
79
+ producer3 = described_class.producer_for('other-broker')
80
+ expect(producer1).to eq(producer2)
81
+ expect(producer1.config.kafka[:'bootstrap.servers']).to eq('broker1:9092')
82
+ expect(producer3.config.kafka[:'bootstrap.servers']).to eq('broker2:9092')
83
+ end
84
+
53
85
  end
@@ -37,10 +37,9 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
37
37
 
38
38
  context 'with a Consumers Schema' do
39
39
  before(:each) do
40
- Deimos.configure do
41
- consumer do
42
- class_name 'ConsumerTest::MyConsumer'
43
- topic 'MyTopic'
40
+ Karafka::App.routes.redraw do
41
+ topic 'MyTopic' do
42
+ consumer ConsumerTest::MyConsumer
44
43
  schema 'Generated'
45
44
  namespace 'com.my-namespace'
46
45
  key_config field: :a_string
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
@@ -137,6 +137,13 @@ module Schemas; module Com; module MyNamespace
137
137
  'com.my-namespace'
138
138
  end
139
139
 
140
+ def self.tombstone(key)
141
+ record = self.allocate
142
+ record.tombstone_key = key
143
+ record.a_string = key
144
+ record
145
+ end
146
+
140
147
  # @override
141
148
  def as_json(_opts={})
142
149
  {
@@ -266,13 +273,6 @@ module Schemas; module Com; module MyNamespace
266
273
  'com.my-namespace'
267
274
  end
268
275
 
269
- def self.tombstone(key)
270
- record = self.allocate
271
- record.tombstone_key = key
272
- record.test_id = key
273
- record
274
- end
275
-
276
276
  # @override
277
277
  def as_json(_opts={})
278
278
  {
@@ -137,6 +137,13 @@ module Schemas; module MyNamespace
137
137
  'com.my-namespace'
138
138
  end
139
139
 
140
+ def self.tombstone(key)
141
+ record = self.allocate
142
+ record.tombstone_key = key
143
+ record.a_string = key
144
+ record
145
+ end
146
+
140
147
  # @override
141
148
  def as_json(_opts={})
142
149
  {
@@ -311,13 +318,6 @@ module Schemas; module MyNamespace
311
318
  'com.my-namespace'
312
319
  end
313
320
 
314
- def self.tombstone(key)
315
- record = self.allocate
316
- record.tombstone_key = key
317
- record.test_id = key
318
- record
319
- end
320
-
321
321
  # @override
322
322
  def as_json(_opts={})
323
323
  {
@@ -217,6 +217,13 @@ module Schemas
217
217
  'com.my-namespace'
218
218
  end
219
219
 
220
+ def self.tombstone(key)
221
+ record = self.allocate
222
+ record.tombstone_key = key
223
+ record.a_string = key
224
+ record
225
+ end
226
+
220
227
  # @override
221
228
  def as_json(_opts={})
222
229
  {
@@ -437,13 +444,6 @@ module Schemas
437
444
  'com.my-namespace'
438
445
  end
439
446
 
440
- def self.tombstone(key)
441
- record = self.allocate
442
- record.tombstone_key = key
443
- record.test_id = key
444
- record
445
- end
446
-
447
447
  # @override
448
448
  def as_json(_opts={})
449
449
  {
@@ -177,6 +177,13 @@ module Schemas
177
177
  'com.my-namespace'
178
178
  end
179
179
 
180
+ def self.tombstone(key)
181
+ record = self.allocate
182
+ record.tombstone_key = key
183
+ record.a_string = key
184
+ record
185
+ end
186
+
180
187
  # @override
181
188
  def as_json(_opts={})
182
189
  {
@@ -391,13 +398,6 @@ module Schemas
391
398
  'com.my-namespace'
392
399
  end
393
400
 
394
- def self.tombstone(key)
395
- record = self.allocate
396
- record.tombstone_key = key
397
- record.test_id = key
398
- record
399
- end
400
-
401
401
  # @override
402
402
  def as_json(_opts={})
403
403
  {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deimos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0.pre.beta4
4
+ version: 2.4.0.pre.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner