karafka-rdkafka 0.14.4 → 0.14.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +2 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +7 -0
- data/docker-compose.yml +1 -1
- data/lib/rdkafka/bindings.rb +1 -1
- data/lib/rdkafka/callbacks.rb +10 -1
- data/lib/rdkafka/consumer/partition.rb +7 -1
- data/lib/rdkafka/consumer/topic_partition_list.rb +23 -3
- data/lib/rdkafka/consumer.rb +24 -6
- data/lib/rdkafka/producer/delivery_handle.rb +8 -2
- data/lib/rdkafka/producer/delivery_report.rb +5 -1
- data/lib/rdkafka/producer.rb +3 -1
- data/lib/rdkafka/version.rb +1 -1
- data/spec/rdkafka/consumer_spec.rb +23 -4
- data/spec/rdkafka/producer_spec.rb +11 -3
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7376c9030672ba0205c3973317a626b7ececd3b100c312e5ef310d08de397cc
|
4
|
+
data.tar.gz: b843498f05cdadfd034c9c20338fd698b37df792c0bd54919c19632ae6ac8d29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca8944dae92ea927a09748524a04df8079e9a1bef1c84034cdf2d5c372ca122e652a1b728c5a497ac26cefa3ae6b2eeb52da3df988332f06ef1a153ce8773028
|
7
|
+
data.tar.gz: 5772911202fae3ccd51d54300a0dd74159188d17395e4ee6895132abcc30a916a9adcf9643f1626dc9884f8a17c88e6d3d546bb0191218a4e263a4cbb37b3009
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/ci.yml
CHANGED
@@ -22,7 +22,7 @@ jobs:
|
|
22
22
|
fail-fast: false
|
23
23
|
matrix:
|
24
24
|
ruby:
|
25
|
-
- '3.3
|
25
|
+
- '3.3'
|
26
26
|
- '3.2'
|
27
27
|
- '3.1'
|
28
28
|
- '3.1.0'
|
@@ -31,7 +31,7 @@ jobs:
|
|
31
31
|
- '2.7'
|
32
32
|
- '2.7.0'
|
33
33
|
include:
|
34
|
-
- ruby: '3.
|
34
|
+
- ruby: '3.3'
|
35
35
|
coverage: 'true'
|
36
36
|
steps:
|
37
37
|
- uses: actions/checkout@v4
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.3.0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Rdkafka Changelog
|
2
2
|
|
3
|
+
## 0.14.6 (2023-12-29)
|
4
|
+
- **[Feature]** Support storing metadata alongside offsets via `rd_kafka_offsets_store` in `#store_offset` (mensfeld)
|
5
|
+
- [Enhancement] Increase the `#committed` default timeout from 1_200ms to 2000ms. This will compensate for network glitches and remote clusters operations and will align with metadata query timeout.
|
6
|
+
|
7
|
+
## 0.14.5 (2023-12-20)
|
8
|
+
- [Enhancement] Provide `label` producer handler and report reference for improved traceability.
|
9
|
+
|
3
10
|
## 0.14.4 (2023-12-19)
|
4
11
|
- [Enhancement] Add ability to store offsets in a transaction (mensfeld)
|
5
12
|
|
data/docker-compose.yml
CHANGED
data/lib/rdkafka/bindings.rb
CHANGED
@@ -92,7 +92,7 @@ module Rdkafka
|
|
92
92
|
end
|
93
93
|
|
94
94
|
attach_function :rd_kafka_topic_partition_list_new, [:int32], :pointer
|
95
|
-
attach_function :rd_kafka_topic_partition_list_add, [:pointer, :string, :int32], :
|
95
|
+
attach_function :rd_kafka_topic_partition_list_add, [:pointer, :string, :int32], :pointer
|
96
96
|
attach_function :rd_kafka_topic_partition_list_set_offset, [:pointer, :string, :int32, :int64], :void
|
97
97
|
attach_function :rd_kafka_topic_partition_list_destroy, [:pointer], :void
|
98
98
|
attach_function :rd_kafka_topic_partition_list_copy, [:pointer], :pointer
|
data/lib/rdkafka/callbacks.rb
CHANGED
@@ -288,7 +288,16 @@ module Rdkafka
|
|
288
288
|
|
289
289
|
# Call delivery callback on opaque
|
290
290
|
if opaque = Rdkafka::Config.opaques[opaque_ptr.to_i]
|
291
|
-
opaque.call_delivery_callback(
|
291
|
+
opaque.call_delivery_callback(
|
292
|
+
Rdkafka::Producer::DeliveryReport.new(
|
293
|
+
message[:partition],
|
294
|
+
message[:offset],
|
295
|
+
topic_name,
|
296
|
+
message[:err],
|
297
|
+
delivery_handle.label
|
298
|
+
),
|
299
|
+
delivery_handle
|
300
|
+
)
|
292
301
|
end
|
293
302
|
end
|
294
303
|
end
|
@@ -16,11 +16,16 @@ module Rdkafka
|
|
16
16
|
# @return [Integer]
|
17
17
|
attr_reader :err
|
18
18
|
|
19
|
+
# Partition metadata in the context of a consumer
|
20
|
+
# @return [String, nil]
|
21
|
+
attr_reader :metadata
|
22
|
+
|
19
23
|
# @private
|
20
|
-
def initialize(partition, offset, err = 0)
|
24
|
+
def initialize(partition, offset, err = 0, metadata = nil)
|
21
25
|
@partition = partition
|
22
26
|
@offset = offset
|
23
27
|
@err = err
|
28
|
+
@metadata = metadata
|
24
29
|
end
|
25
30
|
|
26
31
|
# Human readable representation of this partition.
|
@@ -29,6 +34,7 @@ module Rdkafka
|
|
29
34
|
message = "<Partition #{partition}"
|
30
35
|
message += " offset=#{offset}" if offset
|
31
36
|
message += " err=#{err}" if err != 0
|
37
|
+
message += " metadata=#{metadata}" if metadata != nil
|
32
38
|
message += ">"
|
33
39
|
message
|
34
40
|
end
|
@@ -66,10 +66,14 @@ module Rdkafka
|
|
66
66
|
#
|
67
67
|
# @param topic [String] The topic's name
|
68
68
|
# @param partitions_with_offsets [Hash<Integer, Integer>] The topic's partitions and offsets
|
69
|
+
# @param partitions_with_offsets [Array<Consumer::Partition>] The topic's partitions with offsets
|
70
|
+
# and metadata (if any)
|
69
71
|
#
|
70
72
|
# @return [nil]
|
71
73
|
def add_topic_and_partitions_with_offsets(topic, partitions_with_offsets)
|
72
|
-
@data[topic.to_s] = partitions_with_offsets.map
|
74
|
+
@data[topic.to_s] = partitions_with_offsets.map do |p, o|
|
75
|
+
p.is_a?(Partition) ? p : Partition.new(p, o)
|
76
|
+
end
|
73
77
|
end
|
74
78
|
|
75
79
|
# Return a `Hash` with the topics as keys and and an array of partition information as the value if present.
|
@@ -114,7 +118,13 @@ module Rdkafka
|
|
114
118
|
else
|
115
119
|
elem[:offset]
|
116
120
|
end
|
117
|
-
|
121
|
+
|
122
|
+
partition = Partition.new(
|
123
|
+
elem[:partition],
|
124
|
+
offset,
|
125
|
+
elem[:err],
|
126
|
+
elem[:metadata].null? ? nil : elem[:metadata].read_string(elem[:metadata_size])
|
127
|
+
)
|
118
128
|
partitions.push(partition)
|
119
129
|
data[elem[:topic]] = partitions
|
120
130
|
end
|
@@ -136,12 +146,22 @@ module Rdkafka
|
|
136
146
|
@data.each do |topic, partitions|
|
137
147
|
if partitions
|
138
148
|
partitions.each do |p|
|
139
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
149
|
+
ref = Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
140
150
|
tpl,
|
141
151
|
topic,
|
142
152
|
p.partition
|
143
153
|
)
|
144
154
|
|
155
|
+
if p.metadata
|
156
|
+
part = Rdkafka::Bindings::TopicPartition.new(ref)
|
157
|
+
str_ptr = FFI::MemoryPointer.from_string(p.metadata)
|
158
|
+
# released here:
|
159
|
+
# https://github.com/confluentinc/librdkafka/blob/e03d3bb91ed92a38f38d9806b8d8deffe78a1de5/src/rdkafka_partition.c#L2682C18-L2682C18
|
160
|
+
str_ptr.autorelease = false
|
161
|
+
part[:metadata] = str_ptr
|
162
|
+
part[:metadata_size] = p.metadata.bytesize
|
163
|
+
end
|
164
|
+
|
145
165
|
if p.offset
|
146
166
|
offset = p.offset.is_a?(Time) ? p.offset.to_f * 1_000 : p.offset
|
147
167
|
|
data/lib/rdkafka/consumer.rb
CHANGED
@@ -243,7 +243,7 @@ module Rdkafka
|
|
243
243
|
# @param timeout_ms [Integer] The timeout for fetching this information.
|
244
244
|
# @return [TopicPartitionList]
|
245
245
|
# @raise [RdkafkaError] When getting the committed positions fails.
|
246
|
-
def committed(list=nil, timeout_ms=
|
246
|
+
def committed(list=nil, timeout_ms=2_000)
|
247
247
|
closed_consumer_check(__method__)
|
248
248
|
|
249
249
|
if list.nil?
|
@@ -383,16 +383,34 @@ module Rdkafka
|
|
383
383
|
# When using this `enable.auto.offset.store` should be set to `false` in the config.
|
384
384
|
#
|
385
385
|
# @param message [Rdkafka::Consumer::Message] The message which offset will be stored
|
386
|
+
# @param metadata [String, nil] commit metadata string or nil if none
|
386
387
|
# @return [nil]
|
387
388
|
# @raise [RdkafkaError] When storing the offset fails
|
388
|
-
def store_offset(message)
|
389
|
+
def store_offset(message, metadata = nil)
|
389
390
|
closed_consumer_check(__method__)
|
390
391
|
|
391
392
|
list = TopicPartitionList.new
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
393
|
+
|
394
|
+
# For metadata aware commits we build the partition reference directly to save on
|
395
|
+
# objects allocations
|
396
|
+
if metadata
|
397
|
+
list.add_topic_and_partitions_with_offsets(
|
398
|
+
message.topic,
|
399
|
+
[
|
400
|
+
Consumer::Partition.new(
|
401
|
+
message.partition,
|
402
|
+
message.offset + 1,
|
403
|
+
0,
|
404
|
+
metadata
|
405
|
+
)
|
406
|
+
]
|
407
|
+
)
|
408
|
+
else
|
409
|
+
list.add_topic_and_partitions_with_offsets(
|
410
|
+
message.topic,
|
411
|
+
message.partition => message.offset + 1
|
412
|
+
)
|
413
|
+
end
|
396
414
|
|
397
415
|
tpl = list.to_native_tpl
|
398
416
|
|
@@ -11,6 +11,9 @@ module Rdkafka
|
|
11
11
|
:offset, :int64,
|
12
12
|
:topic_name, :pointer
|
13
13
|
|
14
|
+
# @return [Object, nil] label set during message production or nil by default
|
15
|
+
attr_accessor :label
|
16
|
+
|
14
17
|
# @return [String] the name of the operation (e.g. "delivery")
|
15
18
|
def operation_name
|
16
19
|
"delivery"
|
@@ -22,7 +25,9 @@ module Rdkafka
|
|
22
25
|
DeliveryReport.new(
|
23
26
|
self[:partition],
|
24
27
|
self[:offset],
|
25
|
-
self[:topic_name].read_string
|
28
|
+
self[:topic_name].read_string,
|
29
|
+
nil,
|
30
|
+
label
|
26
31
|
)
|
27
32
|
else
|
28
33
|
DeliveryReport.new(
|
@@ -31,7 +36,8 @@ module Rdkafka
|
|
31
36
|
# For part of errors, we will not get a topic name reference and in cases like this
|
32
37
|
# we should not return it
|
33
38
|
self[:topic_name].null? ? nil : self[:topic_name].read_string,
|
34
|
-
Rdkafka::RdkafkaError.build(self[:response])
|
39
|
+
Rdkafka::RdkafkaError.build(self[:response]),
|
40
|
+
label
|
35
41
|
)
|
36
42
|
end
|
37
43
|
end
|
@@ -21,6 +21,9 @@ module Rdkafka
|
|
21
21
|
# @return [Integer]
|
22
22
|
attr_reader :error
|
23
23
|
|
24
|
+
# @return [Object, nil] label set during message production or nil by default
|
25
|
+
attr_reader :label
|
26
|
+
|
24
27
|
# We alias the `#topic_name` under `#topic` to make this consistent with `Consumer::Message`
|
25
28
|
# where the topic name is under `#topic` method. That way we have a consistent name that
|
26
29
|
# is present in both places
|
@@ -30,11 +33,12 @@ module Rdkafka
|
|
30
33
|
|
31
34
|
private
|
32
35
|
|
33
|
-
def initialize(partition, offset, topic_name = nil, error = nil)
|
36
|
+
def initialize(partition, offset, topic_name = nil, error = nil, label = nil)
|
34
37
|
@partition = partition
|
35
38
|
@offset = offset
|
36
39
|
@topic_name = topic_name
|
37
40
|
@error = error
|
41
|
+
@label = label
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -226,11 +226,12 @@ module Rdkafka
|
|
226
226
|
# @param partition_key [String, nil] Optional partition key based on which partition assignment can happen
|
227
227
|
# @param timestamp [Time,Integer,nil] Optional timestamp of this message. Integer timestamp is in milliseconds since Jan 1 1970.
|
228
228
|
# @param headers [Hash<String,String>] Optional message headers
|
229
|
+
# @param label [Object, nil] a label that can be assigned when producing a message that will be part of the delivery handle and the delivery report
|
229
230
|
#
|
230
231
|
# @return [DeliveryHandle] Delivery handle that can be used to wait for the result of producing this message
|
231
232
|
#
|
232
233
|
# @raise [RdkafkaError] When adding the message to rdkafka's queue failed
|
233
|
-
def produce(topic:, payload: nil, key: nil, partition: nil, partition_key: nil, timestamp: nil, headers: nil)
|
234
|
+
def produce(topic:, payload: nil, key: nil, partition: nil, partition_key: nil, timestamp: nil, headers: nil, label: nil)
|
234
235
|
closed_producer_check(__method__)
|
235
236
|
|
236
237
|
# Start by checking and converting the input
|
@@ -272,6 +273,7 @@ module Rdkafka
|
|
272
273
|
end
|
273
274
|
|
274
275
|
delivery_handle = DeliveryHandle.new
|
276
|
+
delivery_handle.label = label
|
275
277
|
delivery_handle[:pending] = true
|
276
278
|
delivery_handle[:response] = -1
|
277
279
|
delivery_handle[:partition] = -1
|
data/lib/rdkafka/version.rb
CHANGED
@@ -480,12 +480,18 @@ describe Rdkafka::Consumer do
|
|
480
480
|
|
481
481
|
describe "#store_offset" do
|
482
482
|
let(:consumer) { rdkafka_consumer_config('enable.auto.offset.store': false).consumer }
|
483
|
+
let(:metadata) { SecureRandom.uuid }
|
484
|
+
let(:group_id) { SecureRandom.uuid }
|
485
|
+
let(:base_config) do
|
486
|
+
{
|
487
|
+
'group.id': group_id,
|
488
|
+
'enable.auto.offset.store': false,
|
489
|
+
'enable.auto.commit': false
|
490
|
+
}
|
491
|
+
end
|
483
492
|
|
484
493
|
before do
|
485
|
-
|
486
|
-
config[:'enable.auto.offset.store'] = false
|
487
|
-
config[:'enable.auto.commit'] = false
|
488
|
-
@new_consumer = rdkafka_consumer_config(config).consumer
|
494
|
+
@new_consumer = rdkafka_consumer_config(base_config).consumer
|
489
495
|
@new_consumer.subscribe("consume_test_topic")
|
490
496
|
wait_for_assignment(@new_consumer)
|
491
497
|
end
|
@@ -508,6 +514,19 @@ describe Rdkafka::Consumer do
|
|
508
514
|
expect(partitions[message.partition].offset).to eq(message.offset + 1)
|
509
515
|
end
|
510
516
|
|
517
|
+
it "should store the offset for a message with metadata" do
|
518
|
+
@new_consumer.store_offset(message, metadata)
|
519
|
+
@new_consumer.commit
|
520
|
+
@new_consumer.close
|
521
|
+
|
522
|
+
meta_consumer = rdkafka_consumer_config(base_config).consumer
|
523
|
+
meta_consumer.subscribe("consume_test_topic")
|
524
|
+
wait_for_assignment(meta_consumer)
|
525
|
+
meta_consumer.poll(1_000)
|
526
|
+
expect(meta_consumer.committed.to_h[message.topic][message.partition].metadata).to eq(metadata)
|
527
|
+
meta_consumer.close
|
528
|
+
end
|
529
|
+
|
511
530
|
it "should raise an error with invalid input" do
|
512
531
|
allow(message).to receive(:partition).and_return(9999)
|
513
532
|
expect {
|
@@ -34,6 +34,7 @@ describe Rdkafka::Producer do
|
|
34
34
|
|
35
35
|
producer.delivery_callback = lambda do |report|
|
36
36
|
expect(report).not_to be_nil
|
37
|
+
expect(report.label).to eq "label"
|
37
38
|
expect(report.partition).to eq 1
|
38
39
|
expect(report.offset).to be >= 0
|
39
40
|
expect(report.topic_name).to eq "produce_test_topic"
|
@@ -44,9 +45,12 @@ describe Rdkafka::Producer do
|
|
44
45
|
handle = producer.produce(
|
45
46
|
topic: "produce_test_topic",
|
46
47
|
payload: "payload",
|
47
|
-
key: "key"
|
48
|
+
key: "key",
|
49
|
+
label: "label"
|
48
50
|
)
|
49
51
|
|
52
|
+
expect(handle.label).to eq "label"
|
53
|
+
|
50
54
|
# Wait for it to be delivered
|
51
55
|
handle.wait(max_wait_timeout: 15)
|
52
56
|
|
@@ -175,11 +179,13 @@ describe Rdkafka::Producer do
|
|
175
179
|
handle = producer.produce(
|
176
180
|
topic: "produce_test_topic",
|
177
181
|
payload: "payload",
|
178
|
-
key: "key"
|
182
|
+
key: "key",
|
183
|
+
label: "label"
|
179
184
|
)
|
180
185
|
|
181
186
|
# Should be pending at first
|
182
187
|
expect(handle.pending?).to be true
|
188
|
+
expect(handle.label).to eq "label"
|
183
189
|
|
184
190
|
# Check delivery handle and report
|
185
191
|
report = handle.wait(max_wait_timeout: 5)
|
@@ -187,6 +193,7 @@ describe Rdkafka::Producer do
|
|
187
193
|
expect(report).not_to be_nil
|
188
194
|
expect(report.partition).to eq 1
|
189
195
|
expect(report.offset).to be >= 0
|
196
|
+
expect(report.label).to eq "label"
|
190
197
|
|
191
198
|
# Flush and close producer
|
192
199
|
producer.flush
|
@@ -567,10 +574,11 @@ describe Rdkafka::Producer do
|
|
567
574
|
end
|
568
575
|
|
569
576
|
it "should contain the error in the response when not deliverable" do
|
570
|
-
handler = producer.produce(topic: 'produce_test_topic', payload: nil)
|
577
|
+
handler = producer.produce(topic: 'produce_test_topic', payload: nil, label: 'na')
|
571
578
|
# Wait for the async callbacks and delivery registry to update
|
572
579
|
sleep(2)
|
573
580
|
expect(handler.create_result.error).to be_a(Rdkafka::RdkafkaError)
|
581
|
+
expect(handler.create_result.label).to eq('na')
|
574
582
|
end
|
575
583
|
end
|
576
584
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: karafka-rdkafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thijs Cadier
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
|
36
36
|
msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2023-12-
|
38
|
+
date: 2023-12-29 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: ffi
|
@@ -277,7 +277,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
277
277
|
- !ruby/object:Gem::Version
|
278
278
|
version: '0'
|
279
279
|
requirements: []
|
280
|
-
rubygems_version: 3.
|
280
|
+
rubygems_version: 3.5.3
|
281
281
|
signing_key:
|
282
282
|
specification_version: 4
|
283
283
|
summary: The rdkafka gem is a modern Kafka client library for Ruby based on librdkafka.
|
metadata.gz.sig
CHANGED
Binary file
|