rdkafka 0.6.0 → 0.9.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 +4 -4
- data/.semaphore/semaphore.yml +23 -0
- data/CHANGELOG.md +27 -0
- data/README.md +9 -9
- data/docker-compose.yml +17 -11
- data/ext/README.md +10 -15
- data/ext/Rakefile +24 -3
- data/lib/rdkafka.rb +8 -0
- data/lib/rdkafka/abstract_handle.rb +82 -0
- data/lib/rdkafka/admin.rb +155 -0
- data/lib/rdkafka/admin/create_topic_handle.rb +27 -0
- data/lib/rdkafka/admin/create_topic_report.rb +22 -0
- data/lib/rdkafka/admin/delete_topic_handle.rb +27 -0
- data/lib/rdkafka/admin/delete_topic_report.rb +22 -0
- data/lib/rdkafka/bindings.rb +64 -18
- data/lib/rdkafka/callbacks.rb +106 -0
- data/lib/rdkafka/config.rb +38 -9
- data/lib/rdkafka/consumer.rb +221 -46
- data/lib/rdkafka/consumer/headers.rb +7 -5
- data/lib/rdkafka/consumer/partition.rb +1 -1
- data/lib/rdkafka/consumer/topic_partition_list.rb +6 -16
- data/lib/rdkafka/error.rb +35 -4
- data/lib/rdkafka/metadata.rb +92 -0
- data/lib/rdkafka/producer.rb +50 -24
- data/lib/rdkafka/producer/delivery_handle.rb +7 -49
- data/lib/rdkafka/producer/delivery_report.rb +7 -2
- data/lib/rdkafka/version.rb +3 -3
- data/rdkafka.gemspec +3 -3
- data/spec/rdkafka/abstract_handle_spec.rb +114 -0
- data/spec/rdkafka/admin/create_topic_handle_spec.rb +52 -0
- data/spec/rdkafka/admin/create_topic_report_spec.rb +16 -0
- data/spec/rdkafka/admin/delete_topic_handle_spec.rb +52 -0
- data/spec/rdkafka/admin/delete_topic_report_spec.rb +16 -0
- data/spec/rdkafka/admin_spec.rb +203 -0
- data/spec/rdkafka/bindings_spec.rb +28 -10
- data/spec/rdkafka/callbacks_spec.rb +20 -0
- data/spec/rdkafka/config_spec.rb +51 -9
- data/spec/rdkafka/consumer/message_spec.rb +6 -1
- data/spec/rdkafka/consumer_spec.rb +287 -20
- data/spec/rdkafka/error_spec.rb +7 -3
- data/spec/rdkafka/metadata_spec.rb +78 -0
- data/spec/rdkafka/producer/delivery_handle_spec.rb +3 -43
- data/spec/rdkafka/producer/delivery_report_spec.rb +5 -1
- data/spec/rdkafka/producer_spec.rb +220 -100
- data/spec/spec_helper.rb +34 -6
- metadata +37 -13
- data/.travis.yml +0 -34
data/spec/rdkafka/error_spec.rb
CHANGED
@@ -11,6 +11,10 @@ describe Rdkafka::RdkafkaError do
|
|
11
11
|
expect(Rdkafka::RdkafkaError.new(10, "message prefix").message_prefix).to eq "message prefix"
|
12
12
|
end
|
13
13
|
|
14
|
+
it "should create an error with a broker message" do
|
15
|
+
expect(Rdkafka::RdkafkaError.new(10, broker_message: "broker message").broker_message).to eq "broker message"
|
16
|
+
end
|
17
|
+
|
14
18
|
describe "#code" do
|
15
19
|
it "should handle an invalid response" do
|
16
20
|
expect(Rdkafka::RdkafkaError.new(933975).code).to eq :err_933975?
|
@@ -71,15 +75,15 @@ describe Rdkafka::RdkafkaError do
|
|
71
75
|
end
|
72
76
|
|
73
77
|
it "should not equal another error with a different error code" do
|
74
|
-
expect(subject).
|
78
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(20, "Error explanation")
|
75
79
|
end
|
76
80
|
|
77
81
|
it "should not equal another error with a different message" do
|
78
|
-
expect(subject).
|
82
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(10, "Different error explanation")
|
79
83
|
end
|
80
84
|
|
81
85
|
it "should not equal another error with no message" do
|
82
|
-
expect(subject).
|
86
|
+
expect(subject).not_to eq Rdkafka::RdkafkaError.new(10)
|
83
87
|
end
|
84
88
|
end
|
85
89
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "securerandom"
|
3
|
+
|
4
|
+
describe Rdkafka::Metadata do
|
5
|
+
let(:config) { rdkafka_config }
|
6
|
+
let(:native_config) { config.send(:native_config) }
|
7
|
+
let(:native_kafka) { config.send(:native_kafka, native_config, :rd_kafka_consumer) }
|
8
|
+
|
9
|
+
after do
|
10
|
+
Rdkafka::Bindings.rd_kafka_consumer_close(native_kafka)
|
11
|
+
Rdkafka::Bindings.rd_kafka_destroy(native_kafka)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "passing in a topic name" do
|
15
|
+
context "that is non-existent topic" do
|
16
|
+
let(:topic_name) { SecureRandom.uuid.to_s }
|
17
|
+
|
18
|
+
it "raises an appropriate exception" do
|
19
|
+
expect {
|
20
|
+
described_class.new(native_kafka, topic_name)
|
21
|
+
}.to raise_exception(Rdkafka::RdkafkaError, "Broker: Leader not available (leader_not_available)")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "that is one of our test topics" do
|
26
|
+
subject { described_class.new(native_kafka, topic_name) }
|
27
|
+
let(:topic_name) { "partitioner_test_topic" }
|
28
|
+
|
29
|
+
it "#brokers returns our single broker" do
|
30
|
+
expect(subject.brokers.length).to eq(1)
|
31
|
+
expect(subject.brokers[0][:broker_id]).to eq(1)
|
32
|
+
expect(subject.brokers[0][:broker_name]).to eq("localhost")
|
33
|
+
expect(subject.brokers[0][:broker_port]).to eq(9092)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#topics returns data on our test topic" do
|
37
|
+
expect(subject.topics.length).to eq(1)
|
38
|
+
expect(subject.topics[0][:partition_count]).to eq(25)
|
39
|
+
expect(subject.topics[0][:partitions].length).to eq(25)
|
40
|
+
expect(subject.topics[0][:topic_name]).to eq(topic_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "not passing in a topic name" do
|
46
|
+
subject { described_class.new(native_kafka, topic_name) }
|
47
|
+
let(:topic_name) { nil }
|
48
|
+
let(:test_topics) {
|
49
|
+
%w(consume_test_topic empty_test_topic load_test_topic produce_test_topic rake_test_topic watermarks_test_topic partitioner_test_topic)
|
50
|
+
} # Test topics crated in spec_helper.rb
|
51
|
+
|
52
|
+
it "#brokers returns our single broker" do
|
53
|
+
expect(subject.brokers.length).to eq(1)
|
54
|
+
expect(subject.brokers[0][:broker_id]).to eq(1)
|
55
|
+
expect(subject.brokers[0][:broker_name]).to eq("localhost")
|
56
|
+
expect(subject.brokers[0][:broker_port]).to eq(9092)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "#topics returns data about all of our test topics" do
|
60
|
+
result = subject.topics.map { |topic| topic[:topic_name] }
|
61
|
+
expect(result).to include(*test_topics)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when a non-zero error code is returned" do
|
66
|
+
let(:topic_name) { SecureRandom.uuid.to_s }
|
67
|
+
|
68
|
+
before do
|
69
|
+
allow(Rdkafka::Bindings).to receive(:rd_kafka_metadata).and_return(-165)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "creating the instance raises an exception" do
|
73
|
+
expect {
|
74
|
+
described_class.new(native_kafka, topic_name)
|
75
|
+
}.to raise_error(Rdkafka::RdkafkaError, /Local: Required feature not supported by broker \(unsupported_feature\)/)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -12,42 +12,13 @@ describe Rdkafka::Producer::DeliveryHandle do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
describe ".register and .remove" do
|
16
|
-
let(:pending_handle) { true }
|
17
|
-
|
18
|
-
it "should register and remove a delivery handle" do
|
19
|
-
Rdkafka::Producer::DeliveryHandle.register(subject.to_ptr.address, subject)
|
20
|
-
removed = Rdkafka::Producer::DeliveryHandle.remove(subject.to_ptr.address)
|
21
|
-
expect(removed).to eq subject
|
22
|
-
expect(Rdkafka::Producer::DeliveryHandle::REGISTRY).to be_empty
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe "#pending?" do
|
27
|
-
context "when true" do
|
28
|
-
let(:pending_handle) { true }
|
29
|
-
|
30
|
-
it "should be true" do
|
31
|
-
expect(subject.pending?).to be true
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "when not true" do
|
36
|
-
let(:pending_handle) { false }
|
37
|
-
|
38
|
-
it "should be false" do
|
39
|
-
expect(subject.pending?).to be false
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
15
|
describe "#wait" do
|
45
16
|
let(:pending_handle) { true }
|
46
17
|
|
47
18
|
it "should wait until the timeout and then raise an error" do
|
48
19
|
expect {
|
49
|
-
subject.wait(0.1)
|
50
|
-
}.to raise_error Rdkafka::Producer::DeliveryHandle::WaitTimeoutError
|
20
|
+
subject.wait(max_wait_timeout: 0.1)
|
21
|
+
}.to raise_error Rdkafka::Producer::DeliveryHandle::WaitTimeoutError, /delivery/
|
51
22
|
end
|
52
23
|
|
53
24
|
context "when not pending anymore and no error" do
|
@@ -61,22 +32,11 @@ describe Rdkafka::Producer::DeliveryHandle do
|
|
61
32
|
end
|
62
33
|
|
63
34
|
it "should wait without a timeout" do
|
64
|
-
report = subject.wait(nil)
|
35
|
+
report = subject.wait(max_wait_timeout: nil)
|
65
36
|
|
66
37
|
expect(report.partition).to eq(2)
|
67
38
|
expect(report.offset).to eq(100)
|
68
39
|
end
|
69
40
|
end
|
70
|
-
|
71
|
-
context "when not pending anymore and there was an error" do
|
72
|
-
let(:pending_handle) { false }
|
73
|
-
let(:response) { 20 }
|
74
|
-
|
75
|
-
it "should raise an rdkafka error" do
|
76
|
-
expect {
|
77
|
-
subject.wait
|
78
|
-
}.to raise_error Rdkafka::RdkafkaError
|
79
|
-
end
|
80
|
-
end
|
81
41
|
end
|
82
42
|
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,50 +2,102 @@ 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
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
context "with a proc/lambda" do
|
16
|
+
it "should set the callback" do
|
17
|
+
expect {
|
18
|
+
producer.delivery_callback = lambda do |delivery_handle|
|
19
|
+
puts delivery_handle
|
20
|
+
end
|
21
|
+
}.not_to raise_error
|
22
|
+
expect(producer.delivery_callback).to respond_to :call
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should call the callback when a message is delivered" do
|
26
|
+
@callback_called = false
|
27
|
+
|
28
|
+
producer.delivery_callback = lambda do |report|
|
29
|
+
expect(report).not_to be_nil
|
30
|
+
expect(report.partition).to eq 1
|
31
|
+
expect(report.offset).to be >= 0
|
32
|
+
@callback_called = true
|
16
33
|
end
|
17
|
-
}.not_to raise_error
|
18
|
-
expect(producer.delivery_callback).to be_a Proc
|
19
|
-
end
|
20
34
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
35
|
+
# Produce a message
|
36
|
+
handle = producer.produce(
|
37
|
+
topic: "produce_test_topic",
|
38
|
+
payload: "payload",
|
39
|
+
key: "key"
|
40
|
+
)
|
41
|
+
|
42
|
+
# Wait for it to be delivered
|
43
|
+
handle.wait(max_wait_timeout: 15)
|
26
44
|
|
27
|
-
|
28
|
-
|
45
|
+
# Join the producer thread.
|
46
|
+
producer.close
|
29
47
|
|
30
|
-
|
31
|
-
expect(
|
32
|
-
expect(report.partition).to eq 1
|
33
|
-
expect(report.offset).to be >= 0
|
34
|
-
@callback_called = true
|
48
|
+
# Callback should have been called
|
49
|
+
expect(@callback_called).to be true
|
35
50
|
end
|
51
|
+
end
|
36
52
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
53
|
+
context "with a callable object" do
|
54
|
+
it "should set the callback" do
|
55
|
+
callback = Class.new do
|
56
|
+
def call(stats); end
|
57
|
+
end
|
58
|
+
expect {
|
59
|
+
producer.delivery_callback = callback.new
|
60
|
+
}.not_to raise_error
|
61
|
+
expect(producer.delivery_callback).to respond_to :call
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call the callback when a message is delivered" do
|
65
|
+
called_report = []
|
66
|
+
callback = Class.new do
|
67
|
+
def initialize(called_report)
|
68
|
+
@called_report = called_report
|
69
|
+
end
|
70
|
+
|
71
|
+
def call(report)
|
72
|
+
@called_report << report
|
73
|
+
end
|
74
|
+
end
|
75
|
+
producer.delivery_callback = callback.new(called_report)
|
76
|
+
|
77
|
+
# Produce a message
|
78
|
+
handle = producer.produce(
|
79
|
+
topic: "produce_test_topic",
|
80
|
+
payload: "payload",
|
81
|
+
key: "key"
|
82
|
+
)
|
83
|
+
|
84
|
+
# Wait for it to be delivered
|
85
|
+
handle.wait(max_wait_timeout: 15)
|
43
86
|
|
44
|
-
|
45
|
-
|
87
|
+
# Join the producer thread.
|
88
|
+
producer.close
|
46
89
|
|
47
|
-
|
48
|
-
|
90
|
+
# Callback should have been called
|
91
|
+
expect(called_report.first).not_to be_nil
|
92
|
+
expect(called_report.first.partition).to eq 1
|
93
|
+
expect(called_report.first.offset).to be >= 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not accept a callback that's not callable" do
|
98
|
+
expect {
|
99
|
+
producer.delivery_callback = 'a string'
|
100
|
+
}.to raise_error(TypeError)
|
49
101
|
end
|
50
102
|
end
|
51
103
|
|
@@ -55,7 +107,7 @@ describe Rdkafka::Producer do
|
|
55
107
|
payload: "payload",
|
56
108
|
key: "key"
|
57
109
|
)
|
58
|
-
}.to raise_error ArgumentError,
|
110
|
+
}.to raise_error ArgumentError, /missing keyword: [\:]?topic/
|
59
111
|
end
|
60
112
|
|
61
113
|
it "should produce a message" do
|
@@ -70,7 +122,7 @@ describe Rdkafka::Producer do
|
|
70
122
|
expect(handle.pending?).to be true
|
71
123
|
|
72
124
|
# Check delivery handle and report
|
73
|
-
report = handle.wait(5)
|
125
|
+
report = handle.wait(max_wait_timeout: 5)
|
74
126
|
expect(handle.pending?).to be false
|
75
127
|
expect(report).not_to be_nil
|
76
128
|
expect(report.partition).to eq 1
|
@@ -82,14 +134,15 @@ describe Rdkafka::Producer do
|
|
82
134
|
# Consume message and verify it's content
|
83
135
|
message = wait_for_message(
|
84
136
|
topic: "produce_test_topic",
|
85
|
-
delivery_report: report
|
137
|
+
delivery_report: report,
|
138
|
+
consumer: consumer
|
86
139
|
)
|
87
140
|
expect(message.partition).to eq 1
|
88
141
|
expect(message.payload).to eq "payload"
|
89
142
|
expect(message.key).to eq "key"
|
90
143
|
# Since api.version.request is on by default we will get
|
91
144
|
# the message creation timestamp if it's not set.
|
92
|
-
expect(message.timestamp).to be_within(
|
145
|
+
expect(message.timestamp).to be_within(10).of(Time.now)
|
93
146
|
end
|
94
147
|
|
95
148
|
it "should produce a message with a specified partition" do
|
@@ -100,29 +153,65 @@ describe Rdkafka::Producer do
|
|
100
153
|
key: "key partition",
|
101
154
|
partition: 1
|
102
155
|
)
|
103
|
-
report = handle.wait(5)
|
156
|
+
report = handle.wait(max_wait_timeout: 5)
|
104
157
|
|
105
158
|
# Consume message and verify it's content
|
106
159
|
message = wait_for_message(
|
107
160
|
topic: "produce_test_topic",
|
108
|
-
delivery_report: report
|
161
|
+
delivery_report: report,
|
162
|
+
consumer: consumer
|
109
163
|
)
|
110
164
|
expect(message.partition).to eq 1
|
111
165
|
expect(message.key).to eq "key partition"
|
112
166
|
end
|
113
167
|
|
168
|
+
it "should produce a message to the same partition with a similar partition key" do
|
169
|
+
# Avoid partitioner collisions.
|
170
|
+
while true
|
171
|
+
key = ('a'..'z').to_a.shuffle.take(10).join('')
|
172
|
+
partition_key = ('a'..'z').to_a.shuffle.take(10).join('')
|
173
|
+
partition_count = producer.partition_count('partitioner_test_topic')
|
174
|
+
break if (Zlib.crc32(key) % partition_count) != (Zlib.crc32(partition_key) % partition_count)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Produce a message with key, partition_key and key + partition_key
|
178
|
+
messages = [{key: key}, {partition_key: partition_key}, {key: key, partition_key: partition_key}]
|
179
|
+
|
180
|
+
messages = messages.map do |m|
|
181
|
+
handle = producer.produce(
|
182
|
+
topic: "partitioner_test_topic",
|
183
|
+
payload: "payload partition",
|
184
|
+
key: m[:key],
|
185
|
+
partition_key: m[:partition_key]
|
186
|
+
)
|
187
|
+
report = handle.wait(max_wait_timeout: 5)
|
188
|
+
|
189
|
+
wait_for_message(
|
190
|
+
topic: "partitioner_test_topic",
|
191
|
+
delivery_report: report,
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
expect(messages[0].partition).not_to eq(messages[2].partition)
|
196
|
+
expect(messages[1].partition).to eq(messages[2].partition)
|
197
|
+
expect(messages[0].key).to eq key
|
198
|
+
expect(messages[1].key).to be_nil
|
199
|
+
expect(messages[2].key).to eq key
|
200
|
+
end
|
201
|
+
|
114
202
|
it "should produce a message with utf-8 encoding" do
|
115
203
|
handle = producer.produce(
|
116
204
|
topic: "produce_test_topic",
|
117
205
|
payload: "Τη γλώσσα μου έδωσαν ελληνική",
|
118
206
|
key: "key utf8"
|
119
207
|
)
|
120
|
-
report = handle.wait(5)
|
208
|
+
report = handle.wait(max_wait_timeout: 5)
|
121
209
|
|
122
210
|
# Consume message and verify it's content
|
123
211
|
message = wait_for_message(
|
124
212
|
topic: "produce_test_topic",
|
125
|
-
delivery_report: report
|
213
|
+
delivery_report: report,
|
214
|
+
consumer: consumer
|
126
215
|
)
|
127
216
|
|
128
217
|
expect(message.partition).to eq 1
|
@@ -149,12 +238,13 @@ describe Rdkafka::Producer do
|
|
149
238
|
key: "key timestamp",
|
150
239
|
timestamp: 1505069646252
|
151
240
|
)
|
152
|
-
report = handle.wait(5)
|
241
|
+
report = handle.wait(max_wait_timeout: 5)
|
153
242
|
|
154
243
|
# Consume message and verify it's content
|
155
244
|
message = wait_for_message(
|
156
245
|
topic: "produce_test_topic",
|
157
|
-
delivery_report: report
|
246
|
+
delivery_report: report,
|
247
|
+
consumer: consumer
|
158
248
|
)
|
159
249
|
|
160
250
|
expect(message.partition).to eq 2
|
@@ -169,12 +259,13 @@ describe Rdkafka::Producer do
|
|
169
259
|
key: "key timestamp",
|
170
260
|
timestamp: Time.at(1505069646, 353_000)
|
171
261
|
)
|
172
|
-
report = handle.wait(5)
|
262
|
+
report = handle.wait(max_wait_timeout: 5)
|
173
263
|
|
174
264
|
# Consume message and verify it's content
|
175
265
|
message = wait_for_message(
|
176
266
|
topic: "produce_test_topic",
|
177
|
-
delivery_report: report
|
267
|
+
delivery_report: report,
|
268
|
+
consumer: consumer
|
178
269
|
)
|
179
270
|
|
180
271
|
expect(message.partition).to eq 2
|
@@ -188,12 +279,13 @@ describe Rdkafka::Producer do
|
|
188
279
|
topic: "produce_test_topic",
|
189
280
|
payload: "payload no key"
|
190
281
|
)
|
191
|
-
report = handle.wait(5)
|
282
|
+
report = handle.wait(max_wait_timeout: 5)
|
192
283
|
|
193
284
|
# Consume message and verify it's content
|
194
285
|
message = wait_for_message(
|
195
286
|
topic: "produce_test_topic",
|
196
|
-
delivery_report: report
|
287
|
+
delivery_report: report,
|
288
|
+
consumer: consumer
|
197
289
|
)
|
198
290
|
|
199
291
|
expect(message.key).to be_nil
|
@@ -205,12 +297,13 @@ describe Rdkafka::Producer do
|
|
205
297
|
topic: "produce_test_topic",
|
206
298
|
key: "key no payload"
|
207
299
|
)
|
208
|
-
report = handle.wait(5)
|
300
|
+
report = handle.wait(max_wait_timeout: 5)
|
209
301
|
|
210
302
|
# Consume message and verify it's content
|
211
303
|
message = wait_for_message(
|
212
304
|
topic: "produce_test_topic",
|
213
|
-
delivery_report: report
|
305
|
+
delivery_report: report,
|
306
|
+
consumer: consumer
|
214
307
|
)
|
215
308
|
|
216
309
|
expect(message.key).to eq "key no payload"
|
@@ -224,12 +317,13 @@ describe Rdkafka::Producer do
|
|
224
317
|
key: "key headers",
|
225
318
|
headers: { foo: :bar, baz: :foobar }
|
226
319
|
)
|
227
|
-
report = handle.wait(5)
|
320
|
+
report = handle.wait(max_wait_timeout: 5)
|
228
321
|
|
229
322
|
# Consume message and verify it's content
|
230
323
|
message = wait_for_message(
|
231
324
|
topic: "produce_test_topic",
|
232
|
-
delivery_report: report
|
325
|
+
delivery_report: report,
|
326
|
+
consumer: consumer
|
233
327
|
)
|
234
328
|
|
235
329
|
expect(message.payload).to eq "payload headers"
|
@@ -246,12 +340,13 @@ describe Rdkafka::Producer do
|
|
246
340
|
key: "key headers",
|
247
341
|
headers: {}
|
248
342
|
)
|
249
|
-
report = handle.wait(5)
|
343
|
+
report = handle.wait(max_wait_timeout: 5)
|
250
344
|
|
251
345
|
# Consume message and verify it's content
|
252
346
|
message = wait_for_message(
|
253
347
|
topic: "produce_test_topic",
|
254
|
-
delivery_report: report
|
348
|
+
delivery_report: report,
|
349
|
+
consumer: consumer
|
255
350
|
)
|
256
351
|
|
257
352
|
expect(message.payload).to eq "payload headers"
|
@@ -280,55 +375,58 @@ describe Rdkafka::Producer do
|
|
280
375
|
end
|
281
376
|
end
|
282
377
|
|
283
|
-
|
284
|
-
#
|
285
|
-
#
|
286
|
-
|
287
|
-
#
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
378
|
+
it "should produce a message in a forked process" do
|
379
|
+
# Fork, produce a message, send the report over a pipe and
|
380
|
+
# wait for and check the message in the main process.
|
381
|
+
|
382
|
+
# Kernel#fork is not available in JRuby
|
383
|
+
skip if defined?(JRUBY_VERSION)
|
384
|
+
|
385
|
+
reader, writer = IO.pipe
|
386
|
+
|
387
|
+
fork do
|
388
|
+
reader.close
|
389
|
+
|
390
|
+
# Avoids sharing the socket between processes.
|
391
|
+
producer = rdkafka_config.producer
|
392
|
+
|
393
|
+
handle = producer.produce(
|
394
|
+
topic: "produce_test_topic",
|
395
|
+
payload: "payload-forked",
|
396
|
+
key: "key-forked"
|
397
|
+
)
|
398
|
+
|
399
|
+
report = handle.wait(max_wait_timeout: 5)
|
400
|
+
|
401
|
+
report_json = JSON.generate(
|
402
|
+
"partition" => report.partition,
|
403
|
+
"offset" => report.offset
|
404
|
+
)
|
405
|
+
|
406
|
+
writer.write(report_json)
|
407
|
+
writer.close
|
408
|
+
producer.close
|
409
|
+
end
|
410
|
+
|
411
|
+
writer.close
|
412
|
+
report_hash = JSON.parse(reader.read)
|
413
|
+
report = Rdkafka::Producer::DeliveryReport.new(
|
414
|
+
report_hash["partition"],
|
415
|
+
report_hash["offset"]
|
416
|
+
)
|
417
|
+
|
418
|
+
reader.close
|
419
|
+
|
420
|
+
# Consume message and verify it's content
|
421
|
+
message = wait_for_message(
|
422
|
+
topic: "produce_test_topic",
|
423
|
+
delivery_report: report,
|
424
|
+
consumer: consumer
|
425
|
+
)
|
426
|
+
expect(message.partition).to eq 0
|
427
|
+
expect(message.payload).to eq "payload-forked"
|
428
|
+
expect(message.key).to eq "key-forked"
|
429
|
+
end
|
332
430
|
|
333
431
|
it "should raise an error when producing fails" do
|
334
432
|
expect(Rdkafka::Bindings).to receive(:rd_kafka_producev).and_return(20)
|
@@ -348,10 +446,32 @@ describe Rdkafka::Producer do
|
|
348
446
|
key: "key timeout"
|
349
447
|
)
|
350
448
|
expect {
|
351
|
-
handle.wait(0)
|
449
|
+
handle.wait(max_wait_timeout: 0)
|
352
450
|
}.to raise_error Rdkafka::Producer::DeliveryHandle::WaitTimeoutError
|
353
451
|
|
354
452
|
# Waiting a second time should work
|
355
|
-
handle.wait(5)
|
453
|
+
handle.wait(max_wait_timeout: 5)
|
454
|
+
end
|
455
|
+
|
456
|
+
context "methods that should not be called after a producer has been closed" do
|
457
|
+
before do
|
458
|
+
producer.close
|
459
|
+
end
|
460
|
+
|
461
|
+
# Affected methods and a non-invalid set of parameters for the method
|
462
|
+
{
|
463
|
+
:produce => { topic: nil },
|
464
|
+
:partition_count => nil,
|
465
|
+
}.each do |method, args|
|
466
|
+
it "raises an exception if #{method} is called" do
|
467
|
+
expect {
|
468
|
+
if args.is_a?(Hash)
|
469
|
+
producer.public_send(method, **args)
|
470
|
+
else
|
471
|
+
producer.public_send(method, args)
|
472
|
+
end
|
473
|
+
}.to raise_exception(Rdkafka::ClosedProducerError, /#{method.to_s}/)
|
474
|
+
end
|
475
|
+
end
|
356
476
|
end
|
357
477
|
end
|