karafka-rdkafka 0.14.9 → 0.15.0.alpha1
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +8 -0
- data/README.md +19 -9
- data/docker-compose.yml +1 -1
- data/karafka-rdkafka.gemspec +2 -2
- data/lib/rdkafka/abstract_handle.rb +44 -20
- data/lib/rdkafka/admin/config_binding_result.rb +30 -0
- data/lib/rdkafka/admin/config_resource_binding_result.rb +18 -0
- data/lib/rdkafka/admin/create_topic_report.rb +1 -1
- data/lib/rdkafka/admin/delete_groups_report.rb +1 -1
- data/lib/rdkafka/admin/delete_topic_report.rb +1 -1
- data/lib/rdkafka/admin/describe_acl_report.rb +1 -0
- data/lib/rdkafka/admin/describe_configs_handle.rb +33 -0
- data/lib/rdkafka/admin/describe_configs_report.rb +48 -0
- data/lib/rdkafka/admin/incremental_alter_configs_handle.rb +33 -0
- data/lib/rdkafka/admin/incremental_alter_configs_report.rb +48 -0
- data/lib/rdkafka/admin.rb +159 -0
- data/lib/rdkafka/bindings.rb +44 -0
- data/lib/rdkafka/callbacks.rb +103 -19
- data/lib/rdkafka/config.rb +24 -7
- data/lib/rdkafka/version.rb +1 -1
- data/lib/rdkafka.rb +6 -0
- data/spec/rdkafka/abstract_handle_spec.rb +34 -21
- data/spec/rdkafka/admin_spec.rb +275 -3
- data/spec/rdkafka/config_spec.rb +20 -0
- data/spec/rdkafka/consumer_spec.rb +5 -0
- data/spec/spec_helper.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +10 -3
- metadata.gz.sig +0 -0
data/spec/rdkafka/admin_spec.rb
CHANGED
@@ -16,12 +16,12 @@ describe Rdkafka::Admin do
|
|
16
16
|
admin.close
|
17
17
|
end
|
18
18
|
|
19
|
-
let(:topic_name) { "test-topic-#{
|
19
|
+
let(:topic_name) { "test-topic-#{SecureRandom.uuid}" }
|
20
20
|
let(:topic_partition_count) { 3 }
|
21
21
|
let(:topic_replication_factor) { 1 }
|
22
22
|
let(:topic_config) { {"cleanup.policy" => "compact", "min.cleanable.dirty.ratio" => 0.8} }
|
23
23
|
let(:invalid_topic_config) { {"cleeeeenup.policee" => "campact"} }
|
24
|
-
let(:group_name) { "test-group-#{
|
24
|
+
let(:group_name) { "test-group-#{SecureRandom.uuid}" }
|
25
25
|
|
26
26
|
let(:resource_name) {"acl-test-topic"}
|
27
27
|
let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
|
@@ -129,6 +129,275 @@ describe Rdkafka::Admin do
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
+
describe "describe_configs" do
|
133
|
+
subject(:resources_results) { admin.describe_configs(resources).wait.resources }
|
134
|
+
|
135
|
+
before do
|
136
|
+
admin.create_topic(topic_name, 2, 1).wait
|
137
|
+
sleep(1)
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when describing config of an existing topic' do
|
141
|
+
let(:resources) { [{ resource_type: 2, resource_name: topic_name }] }
|
142
|
+
|
143
|
+
it do
|
144
|
+
expect(resources_results.size).to eq(1)
|
145
|
+
expect(resources_results.first.type).to eq(2)
|
146
|
+
expect(resources_results.first.name).to eq(topic_name)
|
147
|
+
expect(resources_results.first.configs.size).to be > 25
|
148
|
+
expect(resources_results.first.configs.first.name).to eq('compression.type')
|
149
|
+
expect(resources_results.first.configs.first.value).to eq('producer')
|
150
|
+
expect(resources_results.first.configs.map(&:synonyms)).not_to be_empty
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when describing config of a non-existing topic' do
|
155
|
+
let(:resources) { [{ resource_type: 2, resource_name: SecureRandom.uuid }] }
|
156
|
+
|
157
|
+
it 'expect to raise error' do
|
158
|
+
expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /unknown_topic_or_part/)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when describing both existing and non-existing topics' do
|
163
|
+
let(:resources) do
|
164
|
+
[
|
165
|
+
{ resource_type: 2, resource_name: topic_name },
|
166
|
+
{ resource_type: 2, resource_name: SecureRandom.uuid }
|
167
|
+
]
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'expect to raise error' do
|
171
|
+
expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /unknown_topic_or_part/)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'when describing multiple existing topics' do
|
176
|
+
let(:resources) do
|
177
|
+
[
|
178
|
+
{ resource_type: 2, resource_name: 'example_topic' },
|
179
|
+
{ resource_type: 2, resource_name: topic_name }
|
180
|
+
]
|
181
|
+
end
|
182
|
+
|
183
|
+
it do
|
184
|
+
expect(resources_results.size).to eq(2)
|
185
|
+
expect(resources_results.first.type).to eq(2)
|
186
|
+
expect(resources_results.first.name).to eq('example_topic')
|
187
|
+
expect(resources_results.last.type).to eq(2)
|
188
|
+
expect(resources_results.last.name).to eq(topic_name)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'when trying to describe invalid resource type' do
|
193
|
+
let(:resources) { [{ resource_type: 0, resource_name: SecureRandom.uuid }] }
|
194
|
+
|
195
|
+
it 'expect to raise error' do
|
196
|
+
expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_request/)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'when trying to describe invalid broker' do
|
201
|
+
let(:resources) { [{ resource_type: 4, resource_name: 'non-existing' }] }
|
202
|
+
|
203
|
+
it 'expect to raise error' do
|
204
|
+
expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_arg/)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'when trying to describe valid broker' do
|
209
|
+
let(:resources) { [{ resource_type: 4, resource_name: '1' }] }
|
210
|
+
|
211
|
+
it do
|
212
|
+
expect(resources_results.size).to eq(1)
|
213
|
+
expect(resources_results.first.type).to eq(4)
|
214
|
+
expect(resources_results.first.name).to eq('1')
|
215
|
+
expect(resources_results.first.configs.size).to be > 230
|
216
|
+
expect(resources_results.first.configs.first.name).to eq('log.cleaner.min.compaction.lag.ms')
|
217
|
+
expect(resources_results.first.configs.first.value).to eq('0')
|
218
|
+
expect(resources_results.first.configs.map(&:synonyms)).not_to be_empty
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'when describing valid broker with topics in one request' do
|
223
|
+
let(:resources) do
|
224
|
+
[
|
225
|
+
{ resource_type: 4, resource_name: '1' },
|
226
|
+
{ resource_type: 2, resource_name: topic_name }
|
227
|
+
]
|
228
|
+
end
|
229
|
+
|
230
|
+
it do
|
231
|
+
expect(resources_results.size).to eq(2)
|
232
|
+
expect(resources_results.first.type).to eq(4)
|
233
|
+
expect(resources_results.first.name).to eq('1')
|
234
|
+
expect(resources_results.first.configs.size).to be > 230
|
235
|
+
expect(resources_results.first.configs.first.name).to eq('log.cleaner.min.compaction.lag.ms')
|
236
|
+
expect(resources_results.first.configs.first.value).to eq('0')
|
237
|
+
expect(resources_results.last.type).to eq(2)
|
238
|
+
expect(resources_results.last.name).to eq(topic_name)
|
239
|
+
expect(resources_results.last.configs.size).to be > 25
|
240
|
+
expect(resources_results.last.configs.first.name).to eq('compression.type')
|
241
|
+
expect(resources_results.last.configs.first.value).to eq('producer')
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "incremental_alter_configs" do
|
247
|
+
subject(:resources_results) { admin.incremental_alter_configs(resources_with_configs).wait.resources }
|
248
|
+
|
249
|
+
before do
|
250
|
+
admin.create_topic(topic_name, 2, 1).wait
|
251
|
+
sleep(1)
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when altering one topic with one valid config via set' do
|
255
|
+
let(:target_retention) { (86400002 + rand(10_000)).to_s }
|
256
|
+
let(:resources_with_configs) do
|
257
|
+
[
|
258
|
+
{
|
259
|
+
resource_type: 2,
|
260
|
+
resource_name: topic_name,
|
261
|
+
configs: [
|
262
|
+
{
|
263
|
+
name: 'delete.retention.ms',
|
264
|
+
value: target_retention,
|
265
|
+
op_type: 0
|
266
|
+
}
|
267
|
+
]
|
268
|
+
}
|
269
|
+
]
|
270
|
+
end
|
271
|
+
|
272
|
+
it do
|
273
|
+
expect(resources_results.size).to eq(1)
|
274
|
+
expect(resources_results.first.type).to eq(2)
|
275
|
+
expect(resources_results.first.name).to eq(topic_name)
|
276
|
+
|
277
|
+
ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
|
278
|
+
config.name == 'delete.retention.ms'
|
279
|
+
end
|
280
|
+
|
281
|
+
expect(ret_config.value).to eq(target_retention)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'when altering one topic with one valid config via delete' do
|
286
|
+
let(:target_retention) { (8640002 + rand(10_000)).to_s }
|
287
|
+
let(:resources_with_configs) do
|
288
|
+
[
|
289
|
+
{
|
290
|
+
resource_type: 2,
|
291
|
+
resource_name: topic_name,
|
292
|
+
configs: [
|
293
|
+
{
|
294
|
+
name: 'delete.retention.ms',
|
295
|
+
value: target_retention,
|
296
|
+
op_type: 1
|
297
|
+
}
|
298
|
+
]
|
299
|
+
}
|
300
|
+
]
|
301
|
+
end
|
302
|
+
|
303
|
+
it do
|
304
|
+
expect(resources_results.size).to eq(1)
|
305
|
+
expect(resources_results.first.type).to eq(2)
|
306
|
+
expect(resources_results.first.name).to eq(topic_name)
|
307
|
+
ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
|
308
|
+
config.name == 'delete.retention.ms'
|
309
|
+
end
|
310
|
+
|
311
|
+
expect(ret_config.value).to eq('86400000')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
context 'when altering one topic with one valid config via append' do
|
316
|
+
let(:target_policy) { 'compact' }
|
317
|
+
let(:resources_with_configs) do
|
318
|
+
[
|
319
|
+
{
|
320
|
+
resource_type: 2,
|
321
|
+
resource_name: topic_name,
|
322
|
+
configs: [
|
323
|
+
{
|
324
|
+
name: 'cleanup.policy',
|
325
|
+
value: target_policy,
|
326
|
+
op_type: 2
|
327
|
+
}
|
328
|
+
]
|
329
|
+
}
|
330
|
+
]
|
331
|
+
end
|
332
|
+
|
333
|
+
it do
|
334
|
+
expect(resources_results.size).to eq(1)
|
335
|
+
expect(resources_results.first.type).to eq(2)
|
336
|
+
expect(resources_results.first.name).to eq(topic_name)
|
337
|
+
|
338
|
+
ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
|
339
|
+
config.name == 'cleanup.policy'
|
340
|
+
end
|
341
|
+
|
342
|
+
expect(ret_config.value).to eq("delete,#{target_policy}")
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'when altering one topic with one valid config via subtrack' do
|
347
|
+
let(:target_policy) { 'delete' }
|
348
|
+
let(:resources_with_configs) do
|
349
|
+
[
|
350
|
+
{
|
351
|
+
resource_type: 2,
|
352
|
+
resource_name: topic_name,
|
353
|
+
configs: [
|
354
|
+
{
|
355
|
+
name: 'cleanup.policy',
|
356
|
+
value: target_policy,
|
357
|
+
op_type: 3
|
358
|
+
}
|
359
|
+
]
|
360
|
+
}
|
361
|
+
]
|
362
|
+
end
|
363
|
+
|
364
|
+
it do
|
365
|
+
expect(resources_results.size).to eq(1)
|
366
|
+
expect(resources_results.first.type).to eq(2)
|
367
|
+
expect(resources_results.first.name).to eq(topic_name)
|
368
|
+
|
369
|
+
ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
|
370
|
+
config.name == 'cleanup.policy'
|
371
|
+
end
|
372
|
+
|
373
|
+
expect(ret_config.value).to eq('')
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context 'when altering one topic with invalid config' do
|
378
|
+
let(:target_retention) { '-10' }
|
379
|
+
let(:resources_with_configs) do
|
380
|
+
[
|
381
|
+
{
|
382
|
+
resource_type: 2,
|
383
|
+
resource_name: topic_name,
|
384
|
+
configs: [
|
385
|
+
{
|
386
|
+
name: 'delete.retention.ms',
|
387
|
+
value: target_retention,
|
388
|
+
op_type: 0
|
389
|
+
}
|
390
|
+
]
|
391
|
+
}
|
392
|
+
]
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'expect to raise error' do
|
396
|
+
expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_config/)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
132
401
|
describe "#delete_topic" do
|
133
402
|
describe "called with invalid input" do
|
134
403
|
# https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/internals/Topic.java#L29
|
@@ -396,7 +665,10 @@ describe Rdkafka::Admin do
|
|
396
665
|
end
|
397
666
|
|
398
667
|
context 'when topic has less then desired number of partitions' do
|
399
|
-
before
|
668
|
+
before do
|
669
|
+
admin.create_topic(topic_name, 1, 1).wait
|
670
|
+
sleep(1)
|
671
|
+
end
|
400
672
|
|
401
673
|
it 'expect to change number of partitions' do
|
402
674
|
admin.create_partitions(topic_name, 10).wait
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -22,6 +22,7 @@ describe Rdkafka::Config do
|
|
22
22
|
it "supports logging queue" do
|
23
23
|
log = StringIO.new
|
24
24
|
Rdkafka::Config.logger = Logger.new(log)
|
25
|
+
Rdkafka::Config.ensure_log_thread
|
25
26
|
|
26
27
|
Rdkafka::Config.log_queue << [Logger::FATAL, "I love testing"]
|
27
28
|
20.times do
|
@@ -31,6 +32,25 @@ describe Rdkafka::Config do
|
|
31
32
|
|
32
33
|
expect(log.string).to include "FATAL -- : I love testing"
|
33
34
|
end
|
35
|
+
|
36
|
+
it "expect to start new logger thread after fork and work" do
|
37
|
+
reader, writer = IO.pipe
|
38
|
+
|
39
|
+
pid = fork do
|
40
|
+
$stdout.reopen(writer)
|
41
|
+
Rdkafka::Config.logger = Logger.new($stdout)
|
42
|
+
reader.close
|
43
|
+
producer = rdkafka_producer_config(debug: 'all').producer
|
44
|
+
producer.close
|
45
|
+
writer.close
|
46
|
+
sleep(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
writer.close
|
50
|
+
Process.wait(pid)
|
51
|
+
output = reader.read
|
52
|
+
expect(output.split("\n").size).to be >= 20
|
53
|
+
end
|
34
54
|
end
|
35
55
|
|
36
56
|
context "statistics callback" do
|
@@ -211,6 +211,11 @@ describe Rdkafka::Consumer do
|
|
211
211
|
|
212
212
|
# 7. ensure same message is read again
|
213
213
|
message2 = consumer.poll(timeout)
|
214
|
+
|
215
|
+
# This is needed because `enable.auto.offset.store` is true but when running in CI that
|
216
|
+
# is overloaded, offset store lags
|
217
|
+
sleep(2)
|
218
|
+
|
214
219
|
consumer.commit
|
215
220
|
expect(message1.offset).to eq message2.offset
|
216
221
|
expect(message1.payload).to eq message2.payload
|
data/spec/spec_helper.rb
CHANGED
@@ -139,7 +139,7 @@ RSpec.configure do |config|
|
|
139
139
|
}.each do |topic, partitions|
|
140
140
|
create_topic_handle = admin.create_topic(topic.to_s, partitions, 1)
|
141
141
|
begin
|
142
|
-
create_topic_handle.wait(max_wait_timeout:
|
142
|
+
create_topic_handle.wait(max_wait_timeout: 1.0)
|
143
143
|
rescue Rdkafka::RdkafkaError => ex
|
144
144
|
raise unless ex.message.match?(/topic_already_exists/)
|
145
145
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: karafka-rdkafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0.alpha1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thijs Cadier
|
8
|
+
- Maciej Mensfeld
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain:
|
@@ -35,7 +36,7 @@ cert_chain:
|
|
35
36
|
AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
|
36
37
|
msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
|
37
38
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-
|
39
|
+
date: 2024-03-17 00:00:00.000000000 Z
|
39
40
|
dependencies:
|
40
41
|
- !ruby/object:Gem::Dependency
|
41
42
|
name: ffi
|
@@ -193,6 +194,8 @@ files:
|
|
193
194
|
- lib/rdkafka/abstract_handle.rb
|
194
195
|
- lib/rdkafka/admin.rb
|
195
196
|
- lib/rdkafka/admin/acl_binding_result.rb
|
197
|
+
- lib/rdkafka/admin/config_binding_result.rb
|
198
|
+
- lib/rdkafka/admin/config_resource_binding_result.rb
|
196
199
|
- lib/rdkafka/admin/create_acl_handle.rb
|
197
200
|
- lib/rdkafka/admin/create_acl_report.rb
|
198
201
|
- lib/rdkafka/admin/create_partitions_handle.rb
|
@@ -207,6 +210,10 @@ files:
|
|
207
210
|
- lib/rdkafka/admin/delete_topic_report.rb
|
208
211
|
- lib/rdkafka/admin/describe_acl_handle.rb
|
209
212
|
- lib/rdkafka/admin/describe_acl_report.rb
|
213
|
+
- lib/rdkafka/admin/describe_configs_handle.rb
|
214
|
+
- lib/rdkafka/admin/describe_configs_report.rb
|
215
|
+
- lib/rdkafka/admin/incremental_alter_configs_handle.rb
|
216
|
+
- lib/rdkafka/admin/incremental_alter_configs_report.rb
|
210
217
|
- lib/rdkafka/bindings.rb
|
211
218
|
- lib/rdkafka/callbacks.rb
|
212
219
|
- lib/rdkafka/config.rb
|
@@ -282,7 +289,7 @@ signing_key:
|
|
282
289
|
specification_version: 4
|
283
290
|
summary: The rdkafka gem is a modern Kafka client library for Ruby based on librdkafka.
|
284
291
|
It wraps the production-ready C client using the ffi gem and targets Kafka 1.0+
|
285
|
-
and Ruby 2.
|
292
|
+
and Ruby 2.7+.
|
286
293
|
test_files:
|
287
294
|
- spec/rdkafka/abstract_handle_spec.rb
|
288
295
|
- spec/rdkafka/admin/create_acl_handle_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|