rdkafka 0.12.0 → 0.13.0.beta.3
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 +6 -2
- data/CHANGELOG.md +12 -0
- data/Gemfile +2 -0
- data/Rakefile +2 -0
- data/ext/Rakefile +2 -0
- data/lib/rdkafka/abstract_handle.rb +2 -0
- data/lib/rdkafka/admin/create_topic_handle.rb +2 -0
- data/lib/rdkafka/admin/create_topic_report.rb +2 -0
- data/lib/rdkafka/admin/delete_topic_handle.rb +2 -0
- data/lib/rdkafka/admin/delete_topic_report.rb +2 -0
- data/lib/rdkafka/admin.rb +40 -35
- data/lib/rdkafka/bindings.rb +22 -6
- data/lib/rdkafka/callbacks.rb +7 -1
- data/lib/rdkafka/config.rb +9 -6
- data/lib/rdkafka/consumer/headers.rb +24 -7
- data/lib/rdkafka/consumer/message.rb +3 -1
- data/lib/rdkafka/consumer/partition.rb +2 -0
- data/lib/rdkafka/consumer/topic_partition_list.rb +2 -0
- data/lib/rdkafka/consumer.rb +37 -29
- data/lib/rdkafka/error.rb +9 -0
- data/lib/rdkafka/metadata.rb +2 -0
- data/lib/rdkafka/native_kafka.rb +62 -0
- data/lib/rdkafka/producer/delivery_handle.rb +5 -2
- data/lib/rdkafka/producer/delivery_report.rb +9 -2
- data/lib/rdkafka/producer.rb +23 -10
- data/lib/rdkafka/version.rb +5 -3
- data/lib/rdkafka.rb +3 -1
- data/rdkafka.gemspec +2 -0
- data/spec/rdkafka/abstract_handle_spec.rb +2 -0
- data/spec/rdkafka/admin/create_topic_handle_spec.rb +2 -0
- data/spec/rdkafka/admin/create_topic_report_spec.rb +2 -0
- data/spec/rdkafka/admin/delete_topic_handle_spec.rb +2 -0
- data/spec/rdkafka/admin/delete_topic_report_spec.rb +2 -0
- data/spec/rdkafka/admin_spec.rb +4 -3
- data/spec/rdkafka/bindings_spec.rb +2 -0
- data/spec/rdkafka/callbacks_spec.rb +2 -0
- data/spec/rdkafka/config_spec.rb +14 -0
- data/spec/rdkafka/consumer/headers_spec.rb +62 -0
- data/spec/rdkafka/consumer/message_spec.rb +3 -1
- data/spec/rdkafka/consumer/partition_spec.rb +2 -0
- data/spec/rdkafka/consumer/topic_partition_list_spec.rb +2 -0
- data/spec/rdkafka/consumer_spec.rb +84 -15
- data/spec/rdkafka/error_spec.rb +2 -0
- data/spec/rdkafka/metadata_spec.rb +3 -1
- data/spec/rdkafka/{producer/client_spec.rb → native_kafka_spec.rb} +22 -10
- data/spec/rdkafka/producer/delivery_handle_spec.rb +5 -0
- data/spec/rdkafka/producer/delivery_report_spec.rb +8 -2
- data/spec/rdkafka/producer_spec.rb +51 -19
- data/spec/spec_helper.rb +16 -0
- metadata +13 -11
- data/lib/rdkafka/producer/client.rb +0 -47
data/lib/rdkafka/consumer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
4
|
# A consumer of Kafka messages. It uses the high-level consumer approach where the Kafka
|
3
5
|
# brokers automatically assign partitions and load balance partitions over consumers that
|
@@ -14,18 +16,24 @@ module Rdkafka
|
|
14
16
|
# @private
|
15
17
|
def initialize(native_kafka)
|
16
18
|
@native_kafka = native_kafka
|
17
|
-
|
19
|
+
end
|
20
|
+
|
21
|
+
def finalizer
|
22
|
+
->(_) { close }
|
18
23
|
end
|
19
24
|
|
20
25
|
# Close this consumer
|
21
26
|
# @return [nil]
|
22
27
|
def close
|
23
|
-
return
|
28
|
+
return if closed?
|
29
|
+
ObjectSpace.undefine_finalizer(self)
|
30
|
+
Rdkafka::Bindings.rd_kafka_consumer_close(@native_kafka.inner)
|
31
|
+
@native_kafka.close
|
32
|
+
end
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@native_kafka = nil
|
34
|
+
# Whether this consumer has closed
|
35
|
+
def closed?
|
36
|
+
@native_kafka.closed?
|
29
37
|
end
|
30
38
|
|
31
39
|
# Subscribe to one or more topics letting Kafka handle partition assignments.
|
@@ -46,7 +54,7 @@ module Rdkafka
|
|
46
54
|
end
|
47
55
|
|
48
56
|
# Subscribe to topic partition list and check this was successful
|
49
|
-
response = Rdkafka::Bindings.rd_kafka_subscribe(@native_kafka, tpl)
|
57
|
+
response = Rdkafka::Bindings.rd_kafka_subscribe(@native_kafka.inner, tpl)
|
50
58
|
if response != 0
|
51
59
|
raise Rdkafka::RdkafkaError.new(response, "Error subscribing to '#{topics.join(', ')}'")
|
52
60
|
end
|
@@ -62,7 +70,7 @@ module Rdkafka
|
|
62
70
|
def unsubscribe
|
63
71
|
closed_consumer_check(__method__)
|
64
72
|
|
65
|
-
response = Rdkafka::Bindings.rd_kafka_unsubscribe(@native_kafka)
|
73
|
+
response = Rdkafka::Bindings.rd_kafka_unsubscribe(@native_kafka.inner)
|
66
74
|
if response != 0
|
67
75
|
raise Rdkafka::RdkafkaError.new(response)
|
68
76
|
end
|
@@ -85,7 +93,7 @@ module Rdkafka
|
|
85
93
|
tpl = list.to_native_tpl
|
86
94
|
|
87
95
|
begin
|
88
|
-
response = Rdkafka::Bindings.rd_kafka_pause_partitions(@native_kafka, tpl)
|
96
|
+
response = Rdkafka::Bindings.rd_kafka_pause_partitions(@native_kafka.inner, tpl)
|
89
97
|
|
90
98
|
if response != 0
|
91
99
|
list = TopicPartitionList.from_native_tpl(tpl)
|
@@ -113,7 +121,7 @@ module Rdkafka
|
|
113
121
|
tpl = list.to_native_tpl
|
114
122
|
|
115
123
|
begin
|
116
|
-
response = Rdkafka::Bindings.rd_kafka_resume_partitions(@native_kafka, tpl)
|
124
|
+
response = Rdkafka::Bindings.rd_kafka_resume_partitions(@native_kafka.inner, tpl)
|
117
125
|
if response != 0
|
118
126
|
raise Rdkafka::RdkafkaError.new(response, "Error resume '#{list.to_h}'")
|
119
127
|
end
|
@@ -131,7 +139,7 @@ module Rdkafka
|
|
131
139
|
closed_consumer_check(__method__)
|
132
140
|
|
133
141
|
ptr = FFI::MemoryPointer.new(:pointer)
|
134
|
-
response = Rdkafka::Bindings.rd_kafka_subscription(@native_kafka, ptr)
|
142
|
+
response = Rdkafka::Bindings.rd_kafka_subscription(@native_kafka.inner, ptr)
|
135
143
|
|
136
144
|
if response != 0
|
137
145
|
raise Rdkafka::RdkafkaError.new(response)
|
@@ -161,7 +169,7 @@ module Rdkafka
|
|
161
169
|
tpl = list.to_native_tpl
|
162
170
|
|
163
171
|
begin
|
164
|
-
response = Rdkafka::Bindings.rd_kafka_assign(@native_kafka, tpl)
|
172
|
+
response = Rdkafka::Bindings.rd_kafka_assign(@native_kafka.inner, tpl)
|
165
173
|
if response != 0
|
166
174
|
raise Rdkafka::RdkafkaError.new(response, "Error assigning '#{list.to_h}'")
|
167
175
|
end
|
@@ -179,7 +187,7 @@ module Rdkafka
|
|
179
187
|
closed_consumer_check(__method__)
|
180
188
|
|
181
189
|
ptr = FFI::MemoryPointer.new(:pointer)
|
182
|
-
response = Rdkafka::Bindings.rd_kafka_assignment(@native_kafka, ptr)
|
190
|
+
response = Rdkafka::Bindings.rd_kafka_assignment(@native_kafka.inner, ptr)
|
183
191
|
if response != 0
|
184
192
|
raise Rdkafka::RdkafkaError.new(response)
|
185
193
|
end
|
@@ -218,7 +226,7 @@ module Rdkafka
|
|
218
226
|
tpl = list.to_native_tpl
|
219
227
|
|
220
228
|
begin
|
221
|
-
response = Rdkafka::Bindings.rd_kafka_committed(@native_kafka, tpl, timeout_ms)
|
229
|
+
response = Rdkafka::Bindings.rd_kafka_committed(@native_kafka.inner, tpl, timeout_ms)
|
222
230
|
if response != 0
|
223
231
|
raise Rdkafka::RdkafkaError.new(response)
|
224
232
|
end
|
@@ -244,7 +252,7 @@ module Rdkafka
|
|
244
252
|
high = FFI::MemoryPointer.new(:int64, 1)
|
245
253
|
|
246
254
|
response = Rdkafka::Bindings.rd_kafka_query_watermark_offsets(
|
247
|
-
@native_kafka,
|
255
|
+
@native_kafka.inner,
|
248
256
|
topic,
|
249
257
|
partition,
|
250
258
|
low,
|
@@ -298,7 +306,7 @@ module Rdkafka
|
|
298
306
|
# @return [String, nil]
|
299
307
|
def cluster_id
|
300
308
|
closed_consumer_check(__method__)
|
301
|
-
Rdkafka::Bindings.rd_kafka_clusterid(@native_kafka)
|
309
|
+
Rdkafka::Bindings.rd_kafka_clusterid(@native_kafka.inner)
|
302
310
|
end
|
303
311
|
|
304
312
|
# Returns this client's broker-assigned group member id
|
@@ -308,7 +316,7 @@ module Rdkafka
|
|
308
316
|
# @return [String, nil]
|
309
317
|
def member_id
|
310
318
|
closed_consumer_check(__method__)
|
311
|
-
Rdkafka::Bindings.rd_kafka_memberid(@native_kafka)
|
319
|
+
Rdkafka::Bindings.rd_kafka_memberid(@native_kafka.inner)
|
312
320
|
end
|
313
321
|
|
314
322
|
# Store offset of a message to be used in the next commit of this consumer
|
@@ -326,7 +334,7 @@ module Rdkafka
|
|
326
334
|
# rd_kafka_offset_store is one of the few calls that does not support
|
327
335
|
# a string as the topic, so create a native topic for it.
|
328
336
|
native_topic = Rdkafka::Bindings.rd_kafka_topic_new(
|
329
|
-
@native_kafka,
|
337
|
+
@native_kafka.inner,
|
330
338
|
message.topic,
|
331
339
|
nil
|
332
340
|
)
|
@@ -358,7 +366,7 @@ module Rdkafka
|
|
358
366
|
# rd_kafka_offset_store is one of the few calls that does not support
|
359
367
|
# a string as the topic, so create a native topic for it.
|
360
368
|
native_topic = Rdkafka::Bindings.rd_kafka_topic_new(
|
361
|
-
@native_kafka,
|
369
|
+
@native_kafka.inner,
|
362
370
|
message.topic,
|
363
371
|
nil
|
364
372
|
)
|
@@ -402,7 +410,7 @@ module Rdkafka
|
|
402
410
|
tpl = list ? list.to_native_tpl : nil
|
403
411
|
|
404
412
|
begin
|
405
|
-
response = Rdkafka::Bindings.rd_kafka_commit(@native_kafka, tpl, async)
|
413
|
+
response = Rdkafka::Bindings.rd_kafka_commit(@native_kafka.inner, tpl, async)
|
406
414
|
if response != 0
|
407
415
|
raise Rdkafka::RdkafkaError.new(response)
|
408
416
|
end
|
@@ -421,7 +429,7 @@ module Rdkafka
|
|
421
429
|
def poll(timeout_ms)
|
422
430
|
closed_consumer_check(__method__)
|
423
431
|
|
424
|
-
message_ptr = Rdkafka::Bindings.rd_kafka_consumer_poll(@native_kafka, timeout_ms)
|
432
|
+
message_ptr = Rdkafka::Bindings.rd_kafka_consumer_poll(@native_kafka.inner, timeout_ms)
|
425
433
|
if message_ptr.null?
|
426
434
|
nil
|
427
435
|
else
|
@@ -436,7 +444,7 @@ module Rdkafka
|
|
436
444
|
end
|
437
445
|
ensure
|
438
446
|
# Clean up rdkafka message if there is one
|
439
|
-
if
|
447
|
+
if message_ptr && !message_ptr.null?
|
440
448
|
Rdkafka::Bindings.rd_kafka_message_destroy(message_ptr)
|
441
449
|
end
|
442
450
|
end
|
@@ -459,7 +467,7 @@ module Rdkafka
|
|
459
467
|
if message
|
460
468
|
yield(message)
|
461
469
|
else
|
462
|
-
if
|
470
|
+
if closed?
|
463
471
|
break
|
464
472
|
else
|
465
473
|
next
|
@@ -468,10 +476,6 @@ module Rdkafka
|
|
468
476
|
end
|
469
477
|
end
|
470
478
|
|
471
|
-
def closed_consumer_check(method)
|
472
|
-
raise Rdkafka::ClosedConsumerError.new(method) if @native_kafka.nil?
|
473
|
-
end
|
474
|
-
|
475
479
|
# Poll for new messages and yield them in batches that may contain
|
476
480
|
# messages from more than one partition.
|
477
481
|
#
|
@@ -527,7 +531,7 @@ module Rdkafka
|
|
527
531
|
bytes = 0
|
528
532
|
end_time = monotonic_now + timeout_ms / 1000.0
|
529
533
|
loop do
|
530
|
-
break if
|
534
|
+
break if closed?
|
531
535
|
max_wait = end_time - monotonic_now
|
532
536
|
max_wait_ms = if max_wait <= 0
|
533
537
|
0 # should not block, but may retrieve a message
|
@@ -545,7 +549,7 @@ module Rdkafka
|
|
545
549
|
end
|
546
550
|
if message
|
547
551
|
slice << message
|
548
|
-
bytes += message.payload.bytesize
|
552
|
+
bytes += message.payload.bytesize if message.payload
|
549
553
|
end
|
550
554
|
if slice.size == max_items || bytes >= bytes_threshold || monotonic_now >= end_time - 0.001
|
551
555
|
yield slice.dup, nil
|
@@ -561,5 +565,9 @@ module Rdkafka
|
|
561
565
|
# needed because Time.now can go backwards
|
562
566
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
563
567
|
end
|
568
|
+
|
569
|
+
def closed_consumer_check(method)
|
570
|
+
raise Rdkafka::ClosedConsumerError.new(method) if closed?
|
571
|
+
end
|
564
572
|
end
|
565
573
|
end
|
data/lib/rdkafka/error.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
4
|
# Base error class.
|
3
5
|
class BaseError < RuntimeError; end
|
@@ -83,4 +85,11 @@ module Rdkafka
|
|
83
85
|
super("Illegal call to #{method.to_s} on a closed producer")
|
84
86
|
end
|
85
87
|
end
|
88
|
+
|
89
|
+
# Error class for public consumer method calls on a closed admin.
|
90
|
+
class ClosedAdminError < BaseError
|
91
|
+
def initialize(method)
|
92
|
+
super("Illegal call to #{method.to_s} on a closed admin")
|
93
|
+
end
|
94
|
+
end
|
86
95
|
end
|
data/lib/rdkafka/metadata.rb
CHANGED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rdkafka
|
4
|
+
# @private
|
5
|
+
# A wrapper around a native kafka that polls and cleanly exits
|
6
|
+
class NativeKafka
|
7
|
+
def initialize(inner, run_polling_thread:)
|
8
|
+
@inner = inner
|
9
|
+
|
10
|
+
if run_polling_thread
|
11
|
+
# Start thread to poll client for delivery callbacks,
|
12
|
+
# not used in consumer.
|
13
|
+
@polling_thread = Thread.new do
|
14
|
+
loop do
|
15
|
+
Rdkafka::Bindings.rd_kafka_poll(inner, 250)
|
16
|
+
# Exit thread if closing and the poll queue is empty
|
17
|
+
if Thread.current[:closing] && Rdkafka::Bindings.rd_kafka_outq_len(inner) == 0
|
18
|
+
break
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@polling_thread.abort_on_exception = true
|
23
|
+
@polling_thread[:closing] = false
|
24
|
+
end
|
25
|
+
|
26
|
+
@closing = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def inner
|
30
|
+
@inner
|
31
|
+
end
|
32
|
+
|
33
|
+
def finalizer
|
34
|
+
->(_) { close }
|
35
|
+
end
|
36
|
+
|
37
|
+
def closed?
|
38
|
+
@closing || @inner.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def close(object_id=nil)
|
42
|
+
return if closed?
|
43
|
+
|
44
|
+
# Indicate to the outside world that we are closing
|
45
|
+
@closing = true
|
46
|
+
|
47
|
+
if @polling_thread
|
48
|
+
# Indicate to polling thread that we're closing
|
49
|
+
@polling_thread[:closing] = true
|
50
|
+
# Wait for the polling thread to finish up
|
51
|
+
@polling_thread.join
|
52
|
+
end
|
53
|
+
|
54
|
+
# Destroy the client
|
55
|
+
Rdkafka::Bindings.rd_kafka_destroy_flags(
|
56
|
+
@inner,
|
57
|
+
Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE
|
58
|
+
)
|
59
|
+
@inner = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
4
|
class Producer
|
3
5
|
# Handle to wait for a delivery report which is returned when
|
@@ -6,7 +8,8 @@ module Rdkafka
|
|
6
8
|
layout :pending, :bool,
|
7
9
|
:response, :int,
|
8
10
|
:partition, :int,
|
9
|
-
:offset, :int64
|
11
|
+
:offset, :int64,
|
12
|
+
:topic_name, :pointer
|
10
13
|
|
11
14
|
# @return [String] the name of the operation (e.g. "delivery")
|
12
15
|
def operation_name
|
@@ -15,7 +18,7 @@ module Rdkafka
|
|
15
18
|
|
16
19
|
# @return [DeliveryReport] a report on the delivery of the message
|
17
20
|
def create_result
|
18
|
-
DeliveryReport.new(self[:partition], self[:offset])
|
21
|
+
DeliveryReport.new(self[:partition], self[:offset], self[:topic_name].read_string)
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
4
|
class Producer
|
3
5
|
# Delivery report for a successfully produced message.
|
@@ -10,15 +12,20 @@ module Rdkafka
|
|
10
12
|
# @return [Integer]
|
11
13
|
attr_reader :offset
|
12
14
|
|
13
|
-
#
|
15
|
+
# The name of the topic this message was produced to.
|
14
16
|
# @return [String]
|
17
|
+
attr_reader :topic_name
|
18
|
+
|
19
|
+
# Error in case happen during produce.
|
20
|
+
# @return [Integer]
|
15
21
|
attr_reader :error
|
16
22
|
|
17
23
|
private
|
18
24
|
|
19
|
-
def initialize(partition, offset, error = nil)
|
25
|
+
def initialize(partition, offset, topic_name = nil, error = nil)
|
20
26
|
@partition = partition
|
21
27
|
@offset = offset
|
28
|
+
@topic_name = topic_name
|
22
29
|
@error = error
|
23
30
|
end
|
24
31
|
end
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "objspace"
|
2
4
|
|
3
5
|
module Rdkafka
|
@@ -16,12 +18,12 @@ module Rdkafka
|
|
16
18
|
attr_reader :delivery_callback_arity
|
17
19
|
|
18
20
|
# @private
|
19
|
-
def initialize(
|
20
|
-
@
|
21
|
+
def initialize(native_kafka, partitioner_name)
|
22
|
+
@native_kafka = native_kafka
|
21
23
|
@partitioner_name = partitioner_name || "consistent_random"
|
22
24
|
|
23
|
-
# Makes sure, that
|
24
|
-
ObjectSpace.define_finalizer(self,
|
25
|
+
# Makes sure, that native kafka gets closed before it gets GCed by Ruby
|
26
|
+
ObjectSpace.define_finalizer(self, native_kafka.finalizer)
|
25
27
|
end
|
26
28
|
|
27
29
|
# Set a callback that will be called every time a message is successfully produced.
|
@@ -38,9 +40,21 @@ module Rdkafka
|
|
38
40
|
|
39
41
|
# Close this producer and wait for the internal poll queue to empty.
|
40
42
|
def close
|
43
|
+
return if closed?
|
41
44
|
ObjectSpace.undefine_finalizer(self)
|
45
|
+
@native_kafka.close
|
46
|
+
end
|
42
47
|
|
43
|
-
|
48
|
+
# Whether this producer has closed
|
49
|
+
def closed?
|
50
|
+
@native_kafka.closed?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Wait until all outstanding producer requests are completed, with the given timeout
|
54
|
+
# in seconds. Call this before closing a producer to ensure delivery of all messages.
|
55
|
+
def flush(timeout_ms=5_000)
|
56
|
+
closed_producer_check(__method__)
|
57
|
+
Rdkafka::Bindings.rd_kafka_flush(@native_kafka.inner, timeout_ms)
|
44
58
|
end
|
45
59
|
|
46
60
|
# Partition count for a given topic.
|
@@ -49,10 +63,9 @@ module Rdkafka
|
|
49
63
|
# @param topic [String] The topic name.
|
50
64
|
#
|
51
65
|
# @return partition count [Integer,nil]
|
52
|
-
#
|
53
66
|
def partition_count(topic)
|
54
67
|
closed_producer_check(__method__)
|
55
|
-
Rdkafka::Metadata.new(@
|
68
|
+
Rdkafka::Metadata.new(@native_kafka.inner, topic).topics&.first[:partition_count]
|
56
69
|
end
|
57
70
|
|
58
71
|
# 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.
|
@@ -144,7 +157,7 @@ module Rdkafka
|
|
144
157
|
|
145
158
|
# Produce the message
|
146
159
|
response = Rdkafka::Bindings.rd_kafka_producev(
|
147
|
-
@
|
160
|
+
@native_kafka.inner,
|
148
161
|
*args
|
149
162
|
)
|
150
163
|
|
@@ -157,7 +170,6 @@ module Rdkafka
|
|
157
170
|
delivery_handle
|
158
171
|
end
|
159
172
|
|
160
|
-
# @private
|
161
173
|
def call_delivery_callback(delivery_report, delivery_handle)
|
162
174
|
return unless @delivery_callback
|
163
175
|
|
@@ -171,8 +183,9 @@ module Rdkafka
|
|
171
183
|
callback.method(:call).arity
|
172
184
|
end
|
173
185
|
|
186
|
+
private
|
174
187
|
def closed_producer_check(method)
|
175
|
-
raise Rdkafka::ClosedProducerError.new(method) if
|
188
|
+
raise Rdkafka::ClosedProducerError.new(method) if closed?
|
176
189
|
end
|
177
190
|
end
|
178
191
|
end
|
data/lib/rdkafka/version.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
|
-
VERSION = "0.
|
3
|
-
LIBRDKAFKA_VERSION = "1.9.
|
4
|
-
LIBRDKAFKA_SOURCE_SHA256 = "
|
4
|
+
VERSION = "0.13.0.beta.3"
|
5
|
+
LIBRDKAFKA_VERSION = "1.9.2"
|
6
|
+
LIBRDKAFKA_SOURCE_SHA256 = "3fba157a9f80a0889c982acdd44608be8a46142270a389008b22d921be1198ad"
|
5
7
|
end
|
data/lib/rdkafka.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rdkafka/version"
|
2
4
|
|
3
5
|
require "rdkafka/abstract_handle"
|
@@ -16,7 +18,7 @@ require "rdkafka/consumer/partition"
|
|
16
18
|
require "rdkafka/consumer/topic_partition_list"
|
17
19
|
require "rdkafka/error"
|
18
20
|
require "rdkafka/metadata"
|
21
|
+
require "rdkafka/native_kafka"
|
19
22
|
require "rdkafka/producer"
|
20
|
-
require "rdkafka/producer/client"
|
21
23
|
require "rdkafka/producer/delivery_handle"
|
22
24
|
require "rdkafka/producer/delivery_report"
|
data/rdkafka.gemspec
CHANGED
data/spec/rdkafka/admin_spec.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
require "ostruct"
|
3
5
|
|
4
6
|
describe Rdkafka::Admin do
|
5
|
-
let(:config)
|
6
|
-
let(:admin)
|
7
|
+
let(:config) { rdkafka_config }
|
8
|
+
let(:admin) { config.admin }
|
7
9
|
|
8
10
|
after do
|
9
11
|
# Registry should always end up being empty
|
@@ -174,7 +176,6 @@ describe Rdkafka::Admin do
|
|
174
176
|
end
|
175
177
|
end
|
176
178
|
|
177
|
-
|
178
179
|
it "deletes a topic that was newly created" do
|
179
180
|
create_topic_handle = admin.create_topic(topic_name, topic_partition_count, topic_replication_factor)
|
180
181
|
create_topic_report = create_topic_handle.wait(max_wait_timeout: 15.0)
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
describe Rdkafka::Config do
|
@@ -148,6 +150,18 @@ describe Rdkafka::Config do
|
|
148
150
|
}.to raise_error(Rdkafka::Config::ConfigError, "No such configuration property: \"invalid.key\"")
|
149
151
|
end
|
150
152
|
|
153
|
+
it "allows string partitioner key" do
|
154
|
+
expect(Rdkafka::Producer).to receive(:new).with(kind_of(Rdkafka::NativeKafka), "murmur2")
|
155
|
+
config = Rdkafka::Config.new("partitioner" => "murmur2")
|
156
|
+
config.producer
|
157
|
+
end
|
158
|
+
|
159
|
+
it "allows symbol partitioner key" do
|
160
|
+
expect(Rdkafka::Producer).to receive(:new).with(kind_of(Rdkafka::NativeKafka), "murmur2")
|
161
|
+
config = Rdkafka::Config.new(:partitioner => "murmur2")
|
162
|
+
config.producer
|
163
|
+
end
|
164
|
+
|
151
165
|
it "should allow configuring zstd compression" do
|
152
166
|
config = Rdkafka::Config.new('compression.codec' => 'zstd')
|
153
167
|
begin
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Rdkafka::Consumer::Headers do
|
6
|
+
let(:headers) do
|
7
|
+
{ # Note String keys!
|
8
|
+
"version" => "2.1.3",
|
9
|
+
"type" => "String"
|
10
|
+
}
|
11
|
+
end
|
12
|
+
let(:native_message) { double('native message') }
|
13
|
+
let(:headers_ptr) { double('headers pointer') }
|
14
|
+
|
15
|
+
describe '.from_native' do
|
16
|
+
before do
|
17
|
+
expect(Rdkafka::Bindings).to receive(:rd_kafka_message_headers).with(native_message, anything) do |_, headers_ptrptr|
|
18
|
+
expect(headers_ptrptr).to receive(:read_pointer).and_return(headers_ptr)
|
19
|
+
Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
20
|
+
end
|
21
|
+
|
22
|
+
expect(Rdkafka::Bindings).to \
|
23
|
+
receive(:rd_kafka_header_get_all)
|
24
|
+
.with(headers_ptr, 0, anything, anything, anything) do |_, _, name_ptrptr, value_ptrptr, size_ptr|
|
25
|
+
expect(name_ptrptr).to receive(:read_pointer).and_return(double("pointer 0", read_string_to_null: headers.keys[0]))
|
26
|
+
expect(size_ptr).to receive(:[]).with(:value).and_return(headers.keys[0].size)
|
27
|
+
expect(value_ptrptr).to receive(:read_pointer).and_return(double("value pointer 0", read_string: headers.values[0]))
|
28
|
+
Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
29
|
+
end
|
30
|
+
|
31
|
+
expect(Rdkafka::Bindings).to \
|
32
|
+
receive(:rd_kafka_header_get_all)
|
33
|
+
.with(headers_ptr, 1, anything, anything, anything) do |_, _, name_ptrptr, value_ptrptr, size_ptr|
|
34
|
+
expect(name_ptrptr).to receive(:read_pointer).and_return(double("pointer 1", read_string_to_null: headers.keys[1]))
|
35
|
+
expect(size_ptr).to receive(:[]).with(:value).and_return(headers.keys[1].size)
|
36
|
+
expect(value_ptrptr).to receive(:read_pointer).and_return(double("value pointer 1", read_string: headers.values[1]))
|
37
|
+
Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(Rdkafka::Bindings).to \
|
41
|
+
receive(:rd_kafka_header_get_all)
|
42
|
+
.with(headers_ptr, 2, anything, anything, anything)
|
43
|
+
.and_return(Rdkafka::Bindings::RD_KAFKA_RESP_ERR__NOENT)
|
44
|
+
end
|
45
|
+
|
46
|
+
subject { described_class.from_native(native_message) }
|
47
|
+
|
48
|
+
it { is_expected.to eq(headers) }
|
49
|
+
it { is_expected.to be_frozen }
|
50
|
+
|
51
|
+
it 'allows String key' do
|
52
|
+
expect(subject['version']).to eq("2.1.3")
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'allows Symbol key, but warns' do
|
56
|
+
expect(Kernel).to \
|
57
|
+
receive(:warn).with("rdkafka deprecation warning: header access with Symbol key :version treated as a String. " \
|
58
|
+
"Please change your code to use String keys to avoid this warning. Symbol keys will break in version 1.")
|
59
|
+
expect(subject[:version]).to eq("2.1.3")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
describe Rdkafka::Consumer::Message do
|
@@ -26,7 +28,7 @@ describe Rdkafka::Consumer::Message do
|
|
26
28
|
end
|
27
29
|
|
28
30
|
after(:each) do
|
29
|
-
Rdkafka::Bindings.
|
31
|
+
Rdkafka::Bindings.rd_kafka_destroy_flags(native_client, Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE)
|
30
32
|
end
|
31
33
|
|
32
34
|
subject { Rdkafka::Consumer::Message.new(native_message) }
|