rdkafka 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +16 -1
- data/CHANGELOG.md +10 -2
- data/docker-compose.yml +15 -11
- data/ext/README.md +3 -15
- data/ext/Rakefile +23 -3
- data/lib/rdkafka/bindings.rb +20 -2
- data/lib/rdkafka/config.rb +2 -4
- data/lib/rdkafka/consumer/headers.rb +7 -5
- data/lib/rdkafka/consumer/topic_partition_list.rb +4 -14
- data/lib/rdkafka/consumer.rb +94 -43
- data/lib/rdkafka/error.rb +5 -0
- data/lib/rdkafka/metadata.rb +91 -0
- data/lib/rdkafka/producer/delivery_report.rb +6 -1
- data/lib/rdkafka/producer.rb +25 -4
- data/lib/rdkafka/version.rb +3 -3
- data/lib/rdkafka.rb +1 -0
- data/rdkafka.gemspec +1 -1
- data/spec/rdkafka/bindings_spec.rb +20 -2
- data/spec/rdkafka/config_spec.rb +6 -2
- data/spec/rdkafka/consumer/message_spec.rb +6 -1
- data/spec/rdkafka/consumer_spec.rb +24 -17
- data/spec/rdkafka/error_spec.rb +3 -3
- data/spec/rdkafka/producer/delivery_report_spec.rb +5 -1
- data/spec/rdkafka/producer_spec.rb +74 -15
- data/spec/spec_helper.rb +14 -3
- metadata +6 -6
@@ -10,11 +10,16 @@ module Rdkafka
|
|
10
10
|
# @return [Integer]
|
11
11
|
attr_reader :offset
|
12
12
|
|
13
|
+
# Error in case happen during produce.
|
14
|
+
# @return [string]
|
15
|
+
attr_reader :error
|
16
|
+
|
13
17
|
private
|
14
18
|
|
15
|
-
def initialize(partition, offset)
|
19
|
+
def initialize(partition, offset, error = nil)
|
16
20
|
@partition = partition
|
17
21
|
@offset = offset
|
22
|
+
@error = error
|
18
23
|
end
|
19
24
|
end
|
20
25
|
end
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -37,10 +37,25 @@ module Rdkafka
|
|
37
37
|
|
38
38
|
# Close this producer and wait for the internal poll queue to empty.
|
39
39
|
def close
|
40
|
+
return unless @native_kafka
|
41
|
+
|
40
42
|
# Indicate to polling thread that we're closing
|
41
43
|
@closing = true
|
42
44
|
# Wait for the polling thread to finish up
|
43
45
|
@polling_thread.join
|
46
|
+
Rdkafka::Bindings.rd_kafka_destroy(@native_kafka)
|
47
|
+
@native_kafka = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Partition count for a given topic.
|
51
|
+
# NOTE: If 'allow.auto.create.topics' is set to true in the broker, the topic will be auto-created after returning nil.
|
52
|
+
#
|
53
|
+
# @param topic [String] The topic name.
|
54
|
+
#
|
55
|
+
# @return partition count [Integer,nil]
|
56
|
+
#
|
57
|
+
def partition_count(topic)
|
58
|
+
Rdkafka::Metadata.new(@native_kafka, topic).topics&.select { |x| x[:topic_name] == topic }&.dig(0, :partition_count)
|
44
59
|
end
|
45
60
|
|
46
61
|
# Produces a message to a Kafka topic. The message is added to rdkafka's queue, call {DeliveryHandle#wait wait} on the returned delivery handle to make sure it is delivered.
|
@@ -58,7 +73,7 @@ module Rdkafka
|
|
58
73
|
# @raise [RdkafkaError] When adding the message to rdkafka's queue failed
|
59
74
|
#
|
60
75
|
# @return [DeliveryHandle] Delivery handle that can be used to wait for the result of producing this message
|
61
|
-
def produce(topic:, payload: nil, key: nil, partition: nil, timestamp: nil, headers: nil)
|
76
|
+
def produce(topic:, payload: nil, key: nil, partition: nil, partition_key: nil, timestamp: nil, headers: nil)
|
62
77
|
# Start by checking and converting the input
|
63
78
|
|
64
79
|
# Get payload length
|
@@ -75,9 +90,15 @@ module Rdkafka
|
|
75
90
|
key.bytesize
|
76
91
|
end
|
77
92
|
|
78
|
-
|
79
|
-
|
80
|
-
|
93
|
+
if partition_key
|
94
|
+
partition_count = partition_count(topic)
|
95
|
+
# If the topic is not present, set to -1
|
96
|
+
partition = Rdkafka::Bindings.partitioner(partition_key, partition_count) if partition_count
|
97
|
+
end
|
98
|
+
|
99
|
+
# If partition is nil, use -1 to let librdafka set the partition randomly or
|
100
|
+
# based on the key when present.
|
101
|
+
partition ||= -1
|
81
102
|
|
82
103
|
# If timestamp is nil use 0 and let Kafka set one. If an integer or time
|
83
104
|
# use it.
|
data/lib/rdkafka/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Rdkafka
|
2
|
-
VERSION = "0.
|
3
|
-
LIBRDKAFKA_VERSION = "1.
|
4
|
-
LIBRDKAFKA_SOURCE_SHA256 = "
|
2
|
+
VERSION = "0.8.0"
|
3
|
+
LIBRDKAFKA_VERSION = "1.4.0"
|
4
|
+
LIBRDKAFKA_SOURCE_SHA256 = "ae27ea3f3d0d32d29004e7f709efbba2666c5383a107cc45b3a1949486b2eb84"
|
5
5
|
end
|
data/lib/rdkafka.rb
CHANGED
@@ -8,6 +8,7 @@ require "rdkafka/consumer/message"
|
|
8
8
|
require "rdkafka/consumer/partition"
|
9
9
|
require "rdkafka/consumer/topic_partition_list"
|
10
10
|
require "rdkafka/error"
|
11
|
+
require "rdkafka/metadata"
|
11
12
|
require "rdkafka/producer"
|
12
13
|
require "rdkafka/producer/delivery_handle"
|
13
14
|
require "rdkafka/producer/delivery_report"
|
data/rdkafka.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_dependency 'ffi', '~> 1.9'
|
21
21
|
gem.add_dependency 'mini_portile2', '~> 2.1'
|
22
|
-
gem.add_dependency 'rake', '
|
22
|
+
gem.add_dependency 'rake', '>= 12.3'
|
23
23
|
|
24
24
|
gem.add_development_dependency 'pry', '~> 0.10'
|
25
25
|
gem.add_development_dependency 'rspec', '~> 3.5'
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require 'zlib'
|
2
3
|
|
3
4
|
describe Rdkafka::Bindings do
|
4
5
|
it "should load librdkafka" do
|
@@ -7,12 +8,12 @@ describe Rdkafka::Bindings do
|
|
7
8
|
|
8
9
|
describe ".lib_extension" do
|
9
10
|
it "should know the lib extension for darwin" do
|
10
|
-
|
11
|
+
stub_const('RbConfig::CONFIG', 'host_os' =>'darwin')
|
11
12
|
expect(Rdkafka::Bindings.lib_extension).to eq "dylib"
|
12
13
|
end
|
13
14
|
|
14
15
|
it "should know the lib extension for linux" do
|
15
|
-
|
16
|
+
stub_const('RbConfig::CONFIG', 'host_os' =>'linux')
|
16
17
|
expect(Rdkafka::Bindings.lib_extension).to eq "so"
|
17
18
|
end
|
18
19
|
end
|
@@ -60,6 +61,23 @@ describe Rdkafka::Bindings do
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
describe "partitioner" do
|
65
|
+
let(:partition_key) { ('a'..'z').to_a.shuffle.take(15).join('') }
|
66
|
+
let(:partition_count) { rand(50) + 1 }
|
67
|
+
|
68
|
+
it "should return the same partition for a similar string and the same partition count" do
|
69
|
+
result_1 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
70
|
+
result_2 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
71
|
+
expect(result_1).to eq(result_2)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should match the old partitioner" do
|
75
|
+
result_1 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
76
|
+
result_2 = (Zlib.crc32(partition_key) % partition_count)
|
77
|
+
expect(result_1).to eq(result_2)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
63
81
|
describe "stats callback" do
|
64
82
|
context "without a stats callback" do
|
65
83
|
it "should do nothing" do
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -50,7 +50,9 @@ describe Rdkafka::Config do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "should create a consumer with valid config" do
|
53
|
-
|
53
|
+
consumer = rdkafka_config.consumer
|
54
|
+
expect(consumer).to be_a Rdkafka::Consumer
|
55
|
+
consumer.close
|
54
56
|
end
|
55
57
|
|
56
58
|
it "should raise an error when creating a consumer with invalid config" do
|
@@ -76,7 +78,9 @@ describe Rdkafka::Config do
|
|
76
78
|
end
|
77
79
|
|
78
80
|
it "should create a producer with valid config" do
|
79
|
-
|
81
|
+
producer = rdkafka_config.producer
|
82
|
+
expect(producer).to be_a Rdkafka::Producer
|
83
|
+
producer.close
|
80
84
|
end
|
81
85
|
|
82
86
|
it "should raise an error when creating a producer with invalid config" do
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Rdkafka::Consumer::Message do
|
4
|
-
let(:
|
4
|
+
let(:native_client) { new_native_client }
|
5
|
+
let(:native_topic) { new_native_topic(native_client: native_client) }
|
5
6
|
let(:payload) { nil }
|
6
7
|
let(:key) { nil }
|
7
8
|
let(:native_message) do
|
@@ -24,6 +25,10 @@ describe Rdkafka::Consumer::Message do
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
28
|
+
after(:each) do
|
29
|
+
Rdkafka::Bindings.rd_kafka_destroy(native_client)
|
30
|
+
end
|
31
|
+
|
27
32
|
subject { Rdkafka::Consumer::Message.new(native_message) }
|
28
33
|
|
29
34
|
before do
|
@@ -6,7 +6,10 @@ describe Rdkafka::Consumer do
|
|
6
6
|
let(:consumer) { config.consumer }
|
7
7
|
let(:producer) { config.producer }
|
8
8
|
|
9
|
-
|
9
|
+
after { consumer.close }
|
10
|
+
after { producer.close }
|
11
|
+
|
12
|
+
describe "#subscribe, #unsubscribe and #subscription" do
|
10
13
|
it "should subscribe, unsubscribe and return the subscription" do
|
11
14
|
expect(consumer.subscription).to be_empty
|
12
15
|
|
@@ -88,7 +91,6 @@ describe Rdkafka::Consumer do
|
|
88
91
|
# 8. ensure that message is successfully consumed
|
89
92
|
records = consumer.poll(timeout)
|
90
93
|
expect(records).not_to be_nil
|
91
|
-
consumer.commit
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
@@ -205,8 +207,6 @@ describe Rdkafka::Consumer do
|
|
205
207
|
expect(records&.payload).to eq "payload c"
|
206
208
|
records = consumer.poll(timeout)
|
207
209
|
expect(records).to be_nil
|
208
|
-
|
209
|
-
consumer.commit
|
210
210
|
end
|
211
211
|
end
|
212
212
|
end
|
@@ -313,11 +313,11 @@ describe Rdkafka::Consumer do
|
|
313
313
|
}.to raise_error TypeError
|
314
314
|
end
|
315
315
|
|
316
|
-
context "with a
|
316
|
+
context "with a committed consumer" do
|
317
317
|
before :all do
|
318
|
-
# Make sure there are some
|
319
|
-
producer = rdkafka_config.producer
|
318
|
+
# Make sure there are some messages.
|
320
319
|
handles = []
|
320
|
+
producer = rdkafka_config.producer
|
321
321
|
10.times do
|
322
322
|
(0..2).each do |i|
|
323
323
|
handles << producer.produce(
|
@@ -329,6 +329,7 @@ describe Rdkafka::Consumer do
|
|
329
329
|
end
|
330
330
|
end
|
331
331
|
handles.each(&:wait)
|
332
|
+
producer.close
|
332
333
|
end
|
333
334
|
|
334
335
|
before do
|
@@ -389,20 +390,26 @@ describe Rdkafka::Consumer do
|
|
389
390
|
|
390
391
|
describe "#store_offset" do
|
391
392
|
before do
|
393
|
+
config = {}
|
392
394
|
config[:'enable.auto.offset.store'] = false
|
393
395
|
config[:'enable.auto.commit'] = false
|
394
|
-
|
395
|
-
|
396
|
+
@new_consumer = rdkafka_config(config).consumer
|
397
|
+
@new_consumer.subscribe("consume_test_topic")
|
398
|
+
wait_for_assignment(@new_consumer)
|
399
|
+
end
|
400
|
+
|
401
|
+
after do
|
402
|
+
@new_consumer.close
|
396
403
|
end
|
397
404
|
|
398
405
|
it "should store the offset for a message" do
|
399
|
-
|
400
|
-
|
406
|
+
@new_consumer.store_offset(message)
|
407
|
+
@new_consumer.commit
|
401
408
|
|
402
409
|
list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
403
410
|
list.add_topic("consume_test_topic", [0, 1, 2])
|
404
411
|
end
|
405
|
-
partitions =
|
412
|
+
partitions = @new_consumer.committed(list).to_h["consume_test_topic"]
|
406
413
|
expect(partitions).not_to be_nil
|
407
414
|
expect(partitions[message.partition].offset).to eq(message.offset + 1)
|
408
415
|
end
|
@@ -410,7 +417,7 @@ describe Rdkafka::Consumer do
|
|
410
417
|
it "should raise an error with invalid input" do
|
411
418
|
allow(message).to receive(:partition).and_return(9999)
|
412
419
|
expect {
|
413
|
-
|
420
|
+
@new_consumer.store_offset(message)
|
414
421
|
}.to raise_error Rdkafka::RdkafkaError
|
415
422
|
end
|
416
423
|
end
|
@@ -554,12 +561,12 @@ describe Rdkafka::Consumer do
|
|
554
561
|
payload: "payload 1",
|
555
562
|
key: "key 1"
|
556
563
|
).wait
|
557
|
-
|
558
564
|
consumer.subscribe("consume_test_topic")
|
559
|
-
message = consumer.
|
560
|
-
expect(message).to be_a Rdkafka::Consumer::Message
|
565
|
+
message = consumer.each {|m| break m}
|
561
566
|
|
562
|
-
|
567
|
+
expect(message).to be_a Rdkafka::Consumer::Message
|
568
|
+
expect(message.payload).to eq('payload 1')
|
569
|
+
expect(message.key).to eq('key 1')
|
563
570
|
end
|
564
571
|
|
565
572
|
it "should raise an error when polling fails" do
|
data/spec/rdkafka/error_spec.rb
CHANGED
@@ -71,15 +71,15 @@ describe Rdkafka::RdkafkaError do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it "should not equal another error with a different error code" do
|
74
|
-
expect(subject).
|
74
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(20, "Error explanation")
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should not equal another error with a different message" do
|
78
|
-
expect(subject).
|
78
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(10, "Different error explanation")
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should not equal another error with no message" do
|
82
|
-
expect(subject).
|
82
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(10)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Rdkafka::Producer::DeliveryReport do
|
4
|
-
subject { Rdkafka::Producer::DeliveryReport.new(2, 100) }
|
4
|
+
subject { Rdkafka::Producer::DeliveryReport.new(2, 100, "error") }
|
5
5
|
|
6
6
|
it "should get the partition" do
|
7
7
|
expect(subject.partition).to eq 2
|
@@ -10,4 +10,8 @@ describe Rdkafka::Producer::DeliveryReport do
|
|
10
10
|
it "should get the offset" do
|
11
11
|
expect(subject.offset).to eq 100
|
12
12
|
end
|
13
|
+
|
14
|
+
it "should get the error" do
|
15
|
+
expect(subject.error).to eq "error"
|
16
|
+
end
|
13
17
|
end
|
@@ -2,10 +2,13 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Rdkafka::Producer do
|
4
4
|
let(:producer) { rdkafka_config.producer }
|
5
|
+
let(:consumer) { rdkafka_config.consumer }
|
5
6
|
|
6
7
|
after do
|
7
8
|
# Registry should always end up being empty
|
8
9
|
expect(Rdkafka::Producer::DeliveryHandle::REGISTRY).to be_empty
|
10
|
+
producer.close
|
11
|
+
consumer.close
|
9
12
|
end
|
10
13
|
|
11
14
|
context "delivery callback" do
|
@@ -27,6 +30,7 @@ describe Rdkafka::Producer do
|
|
27
30
|
it "should call the callback when a message is delivered" do
|
28
31
|
@callback_called = false
|
29
32
|
|
33
|
+
|
30
34
|
producer.delivery_callback = lambda do |report|
|
31
35
|
expect(report).not_to be_nil
|
32
36
|
expect(report.partition).to eq 1
|
@@ -42,7 +46,10 @@ describe Rdkafka::Producer do
|
|
42
46
|
)
|
43
47
|
|
44
48
|
# Wait for it to be delivered
|
45
|
-
handle.wait(max_wait_timeout:
|
49
|
+
handle.wait(max_wait_timeout: 15)
|
50
|
+
|
51
|
+
# Join the producer thread.
|
52
|
+
producer.close
|
46
53
|
|
47
54
|
# Callback should have been called
|
48
55
|
expect(@callback_called).to be true
|
@@ -55,7 +62,7 @@ describe Rdkafka::Producer do
|
|
55
62
|
payload: "payload",
|
56
63
|
key: "key"
|
57
64
|
)
|
58
|
-
}.to raise_error ArgumentError,
|
65
|
+
}.to raise_error ArgumentError, /missing keyword: [\:]?topic/
|
59
66
|
end
|
60
67
|
|
61
68
|
it "should produce a message" do
|
@@ -82,14 +89,15 @@ describe Rdkafka::Producer do
|
|
82
89
|
# Consume message and verify it's content
|
83
90
|
message = wait_for_message(
|
84
91
|
topic: "produce_test_topic",
|
85
|
-
delivery_report: report
|
92
|
+
delivery_report: report,
|
93
|
+
consumer: consumer
|
86
94
|
)
|
87
95
|
expect(message.partition).to eq 1
|
88
96
|
expect(message.payload).to eq "payload"
|
89
97
|
expect(message.key).to eq "key"
|
90
98
|
# Since api.version.request is on by default we will get
|
91
99
|
# the message creation timestamp if it's not set.
|
92
|
-
expect(message.timestamp).to be_within(
|
100
|
+
expect(message.timestamp).to be_within(10).of(Time.now)
|
93
101
|
end
|
94
102
|
|
95
103
|
it "should produce a message with a specified partition" do
|
@@ -105,12 +113,47 @@ describe Rdkafka::Producer do
|
|
105
113
|
# Consume message and verify it's content
|
106
114
|
message = wait_for_message(
|
107
115
|
topic: "produce_test_topic",
|
108
|
-
delivery_report: report
|
116
|
+
delivery_report: report,
|
117
|
+
consumer: consumer
|
109
118
|
)
|
110
119
|
expect(message.partition).to eq 1
|
111
120
|
expect(message.key).to eq "key partition"
|
112
121
|
end
|
113
122
|
|
123
|
+
it "should produce a message to the same partition with a similar partition key" do
|
124
|
+
# Avoid partitioner collisions.
|
125
|
+
while true
|
126
|
+
key = ('a'..'z').to_a.shuffle.take(10).join('')
|
127
|
+
partition_key = ('a'..'z').to_a.shuffle.take(10).join('')
|
128
|
+
partition_count = producer.partition_count('partitioner_test_topic')
|
129
|
+
break if (Zlib.crc32(key) % partition_count) != (Zlib.crc32(partition_key) % partition_count)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Produce a message with key, partition_key and key + partition_key
|
133
|
+
messages = [{key: key}, {partition_key: partition_key}, {key: key, partition_key: partition_key}]
|
134
|
+
|
135
|
+
messages = messages.map do |m|
|
136
|
+
handle = producer.produce(
|
137
|
+
topic: "partitioner_test_topic",
|
138
|
+
payload: "payload partition",
|
139
|
+
key: m[:key],
|
140
|
+
partition_key: m[:partition_key]
|
141
|
+
)
|
142
|
+
report = handle.wait(max_wait_timeout: 5)
|
143
|
+
|
144
|
+
wait_for_message(
|
145
|
+
topic: "partitioner_test_topic",
|
146
|
+
delivery_report: report,
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
expect(messages[0].partition).not_to eq(messages[2].partition)
|
151
|
+
expect(messages[1].partition).to eq(messages[2].partition)
|
152
|
+
expect(messages[0].key).to eq key
|
153
|
+
expect(messages[1].key).to be_nil
|
154
|
+
expect(messages[2].key).to eq key
|
155
|
+
end
|
156
|
+
|
114
157
|
it "should produce a message with utf-8 encoding" do
|
115
158
|
handle = producer.produce(
|
116
159
|
topic: "produce_test_topic",
|
@@ -122,7 +165,8 @@ describe Rdkafka::Producer do
|
|
122
165
|
# Consume message and verify it's content
|
123
166
|
message = wait_for_message(
|
124
167
|
topic: "produce_test_topic",
|
125
|
-
delivery_report: report
|
168
|
+
delivery_report: report,
|
169
|
+
consumer: consumer
|
126
170
|
)
|
127
171
|
|
128
172
|
expect(message.partition).to eq 1
|
@@ -154,7 +198,8 @@ describe Rdkafka::Producer do
|
|
154
198
|
# Consume message and verify it's content
|
155
199
|
message = wait_for_message(
|
156
200
|
topic: "produce_test_topic",
|
157
|
-
delivery_report: report
|
201
|
+
delivery_report: report,
|
202
|
+
consumer: consumer
|
158
203
|
)
|
159
204
|
|
160
205
|
expect(message.partition).to eq 2
|
@@ -174,7 +219,8 @@ describe Rdkafka::Producer do
|
|
174
219
|
# Consume message and verify it's content
|
175
220
|
message = wait_for_message(
|
176
221
|
topic: "produce_test_topic",
|
177
|
-
delivery_report: report
|
222
|
+
delivery_report: report,
|
223
|
+
consumer: consumer
|
178
224
|
)
|
179
225
|
|
180
226
|
expect(message.partition).to eq 2
|
@@ -193,7 +239,8 @@ describe Rdkafka::Producer do
|
|
193
239
|
# Consume message and verify it's content
|
194
240
|
message = wait_for_message(
|
195
241
|
topic: "produce_test_topic",
|
196
|
-
delivery_report: report
|
242
|
+
delivery_report: report,
|
243
|
+
consumer: consumer
|
197
244
|
)
|
198
245
|
|
199
246
|
expect(message.key).to be_nil
|
@@ -210,7 +257,8 @@ describe Rdkafka::Producer do
|
|
210
257
|
# Consume message and verify it's content
|
211
258
|
message = wait_for_message(
|
212
259
|
topic: "produce_test_topic",
|
213
|
-
delivery_report: report
|
260
|
+
delivery_report: report,
|
261
|
+
consumer: consumer
|
214
262
|
)
|
215
263
|
|
216
264
|
expect(message.key).to eq "key no payload"
|
@@ -229,7 +277,8 @@ describe Rdkafka::Producer do
|
|
229
277
|
# Consume message and verify it's content
|
230
278
|
message = wait_for_message(
|
231
279
|
topic: "produce_test_topic",
|
232
|
-
delivery_report: report
|
280
|
+
delivery_report: report,
|
281
|
+
consumer: consumer
|
233
282
|
)
|
234
283
|
|
235
284
|
expect(message.payload).to eq "payload headers"
|
@@ -251,7 +300,8 @@ describe Rdkafka::Producer do
|
|
251
300
|
# Consume message and verify it's content
|
252
301
|
message = wait_for_message(
|
253
302
|
topic: "produce_test_topic",
|
254
|
-
delivery_report: report
|
303
|
+
delivery_report: report,
|
304
|
+
consumer: consumer
|
255
305
|
)
|
256
306
|
|
257
307
|
expect(message.payload).to eq "payload headers"
|
@@ -284,11 +334,17 @@ describe Rdkafka::Producer do
|
|
284
334
|
# Fork, produce a message, send the report over a pipe and
|
285
335
|
# wait for and check the message in the main process.
|
286
336
|
|
337
|
+
# Kernel#fork is not available in JRuby
|
338
|
+
skip if defined?(JRUBY_VERSION)
|
339
|
+
|
287
340
|
reader, writer = IO.pipe
|
288
341
|
|
289
342
|
fork do
|
290
343
|
reader.close
|
291
344
|
|
345
|
+
# Avoids sharing the socket between processes.
|
346
|
+
producer = rdkafka_config.producer
|
347
|
+
|
292
348
|
handle = producer.produce(
|
293
349
|
topic: "produce_test_topic",
|
294
350
|
payload: "payload-forked",
|
@@ -296,7 +352,6 @@ describe Rdkafka::Producer do
|
|
296
352
|
)
|
297
353
|
|
298
354
|
report = handle.wait(max_wait_timeout: 5)
|
299
|
-
producer.close
|
300
355
|
|
301
356
|
report_json = JSON.generate(
|
302
357
|
"partition" => report.partition,
|
@@ -304,20 +359,24 @@ describe Rdkafka::Producer do
|
|
304
359
|
)
|
305
360
|
|
306
361
|
writer.write(report_json)
|
362
|
+
writer.close
|
363
|
+
producer.close
|
307
364
|
end
|
308
365
|
|
309
366
|
writer.close
|
310
|
-
|
311
367
|
report_hash = JSON.parse(reader.read)
|
312
368
|
report = Rdkafka::Producer::DeliveryReport.new(
|
313
369
|
report_hash["partition"],
|
314
370
|
report_hash["offset"]
|
315
371
|
)
|
316
372
|
|
373
|
+
reader.close
|
374
|
+
|
317
375
|
# Consume message and verify it's content
|
318
376
|
message = wait_for_message(
|
319
377
|
topic: "produce_test_topic",
|
320
|
-
delivery_report: report
|
378
|
+
delivery_report: report,
|
379
|
+
consumer: consumer
|
321
380
|
)
|
322
381
|
expect(message.partition).to eq 0
|
323
382
|
expect(message.payload).to eq "payload-forked"
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,14 @@ require "pry"
|
|
7
7
|
require "rspec"
|
8
8
|
require "rdkafka"
|
9
9
|
|
10
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic consume_test_topic`
|
11
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic empty_test_topic`
|
12
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic load_test_topic`
|
13
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic produce_test_topic`
|
14
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic rake_test_topic`
|
15
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --if-not-exists --topic watermarks_test_topic`
|
16
|
+
`docker-compose exec kafka kafka-topics --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 25 --if-not-exists --topic partitioner_test_topic`
|
17
|
+
|
10
18
|
def rdkafka_config(config_overrides={})
|
11
19
|
config = {
|
12
20
|
:"api.version.request" => false,
|
@@ -25,12 +33,12 @@ def rdkafka_config(config_overrides={})
|
|
25
33
|
Rdkafka::Config.new(config)
|
26
34
|
end
|
27
35
|
|
28
|
-
def
|
36
|
+
def new_native_client
|
29
37
|
config = rdkafka_config
|
30
38
|
config.send(:native_kafka, config.send(:native_config), :rd_kafka_producer)
|
31
39
|
end
|
32
40
|
|
33
|
-
def new_native_topic(topic_name="topic_name")
|
41
|
+
def new_native_topic(topic_name="topic_name", native_client: )
|
34
42
|
Rdkafka::Bindings.rd_kafka_topic_new(
|
35
43
|
native_client,
|
36
44
|
topic_name,
|
@@ -39,7 +47,8 @@ def new_native_topic(topic_name="topic_name")
|
|
39
47
|
end
|
40
48
|
|
41
49
|
def wait_for_message(topic:, delivery_report:, timeout_in_seconds: 30, consumer: nil)
|
42
|
-
|
50
|
+
new_consumer = !!consumer
|
51
|
+
consumer ||= rdkafka_config.consumer
|
43
52
|
consumer.subscribe(topic)
|
44
53
|
timeout = Time.now.to_i + timeout_in_seconds
|
45
54
|
loop do
|
@@ -53,6 +62,8 @@ def wait_for_message(topic:, delivery_report:, timeout_in_seconds: 30, consumer:
|
|
53
62
|
return message
|
54
63
|
end
|
55
64
|
end
|
65
|
+
ensure
|
66
|
+
consumer.close if new_consumer
|
56
67
|
end
|
57
68
|
|
58
69
|
def wait_for_assignment(consumer)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdkafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thijs Cadier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -42,14 +42,14 @@ dependencies:
|
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '12.3'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '12.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -136,6 +136,7 @@ files:
|
|
136
136
|
- lib/rdkafka/consumer/partition.rb
|
137
137
|
- lib/rdkafka/consumer/topic_partition_list.rb
|
138
138
|
- lib/rdkafka/error.rb
|
139
|
+
- lib/rdkafka/metadata.rb
|
139
140
|
- lib/rdkafka/producer.rb
|
140
141
|
- lib/rdkafka/producer/delivery_handle.rb
|
141
142
|
- lib/rdkafka/producer/delivery_report.rb
|
@@ -171,8 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
172
|
- !ruby/object:Gem::Version
|
172
173
|
version: '0'
|
173
174
|
requirements: []
|
174
|
-
|
175
|
-
rubygems_version: 2.7.6.2
|
175
|
+
rubygems_version: 3.1.2
|
176
176
|
signing_key:
|
177
177
|
specification_version: 4
|
178
178
|
summary: The rdkafka gem is a modern Kafka client library for Ruby based on librdkafka.
|