rdkafka 0.4.2 → 0.8.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/.travis.yml +17 -4
- data/CHANGELOG.md +23 -0
- data/README.md +5 -8
- data/docker-compose.yml +15 -11
- data/ext/README.md +3 -15
- data/ext/Rakefile +23 -3
- data/lib/rdkafka.rb +2 -0
- data/lib/rdkafka/bindings.rb +76 -2
- data/lib/rdkafka/config.rb +38 -7
- data/lib/rdkafka/consumer.rb +185 -40
- data/lib/rdkafka/consumer/headers.rb +63 -0
- data/lib/rdkafka/consumer/message.rb +11 -1
- data/lib/rdkafka/consumer/partition.rb +11 -6
- data/lib/rdkafka/consumer/topic_partition_list.rb +33 -30
- data/lib/rdkafka/error.rb +17 -0
- data/lib/rdkafka/metadata.rb +91 -0
- data/lib/rdkafka/producer.rb +54 -18
- data/lib/rdkafka/producer/delivery_handle.rb +12 -8
- data/lib/rdkafka/producer/delivery_report.rb +7 -2
- data/lib/rdkafka/version.rb +3 -3
- data/rdkafka.gemspec +3 -3
- data/spec/rdkafka/bindings_spec.rb +20 -2
- data/spec/rdkafka/config_spec.rb +6 -2
- data/spec/rdkafka/consumer/message_spec.rb +23 -1
- data/spec/rdkafka/consumer/partition_spec.rb +17 -4
- data/spec/rdkafka/consumer/topic_partition_list_spec.rb +1 -1
- data/spec/rdkafka/consumer_spec.rb +322 -16
- data/spec/rdkafka/error_spec.rb +3 -3
- data/spec/rdkafka/producer/delivery_handle_spec.rb +2 -2
- data/spec/rdkafka/producer/delivery_report_spec.rb +5 -1
- data/spec/rdkafka/producer_spec.rb +163 -68
- data/spec/spec_helper.rb +21 -3
- metadata +11 -9
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rdkafka
|
2
|
+
class Consumer
|
3
|
+
# A message headers
|
4
|
+
class Headers
|
5
|
+
# Reads a native kafka's message header into ruby's hash
|
6
|
+
#
|
7
|
+
# @return [Hash<String, String>] a message headers
|
8
|
+
#
|
9
|
+
# @raise [Rdkafka::RdkafkaError] when fail to read headers
|
10
|
+
#
|
11
|
+
# @private
|
12
|
+
def self.from_native(native_message)
|
13
|
+
headers_ptrptr = FFI::MemoryPointer.new(:pointer)
|
14
|
+
err = Rdkafka::Bindings.rd_kafka_message_headers(native_message, headers_ptrptr)
|
15
|
+
|
16
|
+
if err == Rdkafka::Bindings::RD_KAFKA_RESP_ERR__NOENT
|
17
|
+
return {}
|
18
|
+
elsif err != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
19
|
+
raise Rdkafka::RdkafkaError.new(err, "Error reading message headers")
|
20
|
+
end
|
21
|
+
|
22
|
+
headers_ptr = headers_ptrptr.read_pointer
|
23
|
+
|
24
|
+
name_ptrptr = FFI::MemoryPointer.new(:pointer)
|
25
|
+
value_ptrptr = FFI::MemoryPointer.new(:pointer)
|
26
|
+
size_ptr = Rdkafka::Bindings::SizePtr.new
|
27
|
+
headers = {}
|
28
|
+
|
29
|
+
idx = 0
|
30
|
+
loop do
|
31
|
+
err = Rdkafka::Bindings.rd_kafka_header_get_all(
|
32
|
+
headers_ptr,
|
33
|
+
idx,
|
34
|
+
name_ptrptr,
|
35
|
+
value_ptrptr,
|
36
|
+
size_ptr
|
37
|
+
)
|
38
|
+
|
39
|
+
if err == Rdkafka::Bindings::RD_KAFKA_RESP_ERR__NOENT
|
40
|
+
break
|
41
|
+
elsif err != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
42
|
+
raise Rdkafka::RdkafkaError.new(err, "Error reading a message header at index #{idx}")
|
43
|
+
end
|
44
|
+
|
45
|
+
name_ptr = name_ptrptr.read_pointer
|
46
|
+
name = name_ptr.respond_to?(:read_string_to_null) ? name_ptr.read_string_to_null : name_ptr.read_string
|
47
|
+
|
48
|
+
size = size_ptr[:value]
|
49
|
+
|
50
|
+
value_ptr = value_ptrptr.read_pointer
|
51
|
+
|
52
|
+
value = value_ptr.read_string(size)
|
53
|
+
|
54
|
+
headers[name.to_sym] = value
|
55
|
+
|
56
|
+
idx += 1
|
57
|
+
end
|
58
|
+
|
59
|
+
headers
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -26,6 +26,9 @@ module Rdkafka
|
|
26
26
|
# @return [Time, nil]
|
27
27
|
attr_reader :timestamp
|
28
28
|
|
29
|
+
# @return [Hash<String, String>] a message headers
|
30
|
+
attr_reader :headers
|
31
|
+
|
29
32
|
# @private
|
30
33
|
def initialize(native_message)
|
31
34
|
# Set topic
|
@@ -54,12 +57,16 @@ module Rdkafka
|
|
54
57
|
else
|
55
58
|
nil
|
56
59
|
end
|
60
|
+
|
61
|
+
@headers = Headers.from_native(native_message)
|
57
62
|
end
|
58
63
|
|
59
64
|
# Human readable representation of this message.
|
60
65
|
# @return [String]
|
61
66
|
def to_s
|
62
|
-
|
67
|
+
is_headers = @headers.empty? ? "" : ", headers #{headers.size}"
|
68
|
+
|
69
|
+
"<Message in '#{topic}' with key '#{truncate(key)}', payload '#{truncate(payload)}', partition #{partition}, offset #{offset}, timestamp #{timestamp}#{is_headers}>"
|
63
70
|
end
|
64
71
|
|
65
72
|
def truncate(string)
|
@@ -69,6 +76,9 @@ module Rdkafka
|
|
69
76
|
string
|
70
77
|
end
|
71
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
72
82
|
end
|
73
83
|
end
|
74
84
|
end
|
@@ -10,20 +10,25 @@ module Rdkafka
|
|
10
10
|
# @return [Integer, nil]
|
11
11
|
attr_reader :offset
|
12
12
|
|
13
|
+
# Partition's error code
|
14
|
+
# @return [Integer]
|
15
|
+
attr_reader :err
|
16
|
+
|
13
17
|
# @private
|
14
|
-
def initialize(partition, offset)
|
18
|
+
def initialize(partition, offset, err = 0)
|
15
19
|
@partition = partition
|
16
20
|
@offset = offset
|
21
|
+
@err = err
|
17
22
|
end
|
18
23
|
|
19
24
|
# Human readable representation of this partition.
|
20
25
|
# @return [String]
|
21
26
|
def to_s
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
message = "<Partition #{partition}"
|
28
|
+
message += " offset=#{offset}" if offset
|
29
|
+
message += " err=#{err}" if err != 0
|
30
|
+
message += ">"
|
31
|
+
message
|
27
32
|
end
|
28
33
|
|
29
34
|
# Human readable representation of this partition.
|
@@ -4,7 +4,7 @@ module Rdkafka
|
|
4
4
|
class TopicPartitionList
|
5
5
|
# Create a topic partition list.
|
6
6
|
#
|
7
|
-
# @param data [Hash
|
7
|
+
# @param data [Hash{String => nil,Partition}] The topic and partition data or nil to create an empty list
|
8
8
|
#
|
9
9
|
# @return [TopicPartitionList]
|
10
10
|
def initialize(data=nil)
|
@@ -54,7 +54,7 @@ module Rdkafka
|
|
54
54
|
if partitions.is_a? Integer
|
55
55
|
partitions = (0..partitions - 1)
|
56
56
|
end
|
57
|
-
@data[topic.to_s] = partitions.map { |p| Partition.new(p, nil) }
|
57
|
+
@data[topic.to_s] = partitions.map { |p| Partition.new(p, nil, 0) }
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -71,7 +71,7 @@ module Rdkafka
|
|
71
71
|
|
72
72
|
# Return a `Hash` with the topics as keys and and an array of partition information as the value if present.
|
73
73
|
#
|
74
|
-
# @return [Hash
|
74
|
+
# @return [Hash{String => Array<Partition>,nil}]
|
75
75
|
def to_h
|
76
76
|
@data
|
77
77
|
end
|
@@ -88,7 +88,7 @@ module Rdkafka
|
|
88
88
|
|
89
89
|
# Create a new topic partition list based of a native one.
|
90
90
|
#
|
91
|
-
# @param pointer [FFI::Pointer] Optional pointer to an existing native list. Its contents will be copied
|
91
|
+
# @param pointer [FFI::Pointer] Optional pointer to an existing native list. Its contents will be copied.
|
92
92
|
#
|
93
93
|
# @return [TopicPartitionList]
|
94
94
|
#
|
@@ -106,12 +106,12 @@ module Rdkafka
|
|
106
106
|
data[elem[:topic]] = nil
|
107
107
|
else
|
108
108
|
partitions = data[elem[:topic]] || []
|
109
|
-
offset = if elem[:offset] ==
|
109
|
+
offset = if elem[:offset] == Rdkafka::Bindings::RD_KAFKA_OFFSET_INVALID
|
110
110
|
nil
|
111
111
|
else
|
112
112
|
elem[:offset]
|
113
113
|
end
|
114
|
-
partition = Partition.new(elem[:partition], offset)
|
114
|
+
partition = Partition.new(elem[:partition], offset, elem[:err])
|
115
115
|
partitions.push(partition)
|
116
116
|
data[elem[:topic]] = partitions
|
117
117
|
end
|
@@ -119,42 +119,45 @@ module Rdkafka
|
|
119
119
|
|
120
120
|
# Return the created object
|
121
121
|
TopicPartitionList.new(data)
|
122
|
-
ensure
|
123
|
-
# Destroy the tpl
|
124
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(pointer)
|
125
122
|
end
|
126
123
|
|
127
|
-
# Create a native tpl with the contents of this object added
|
124
|
+
# Create a native tpl with the contents of this object added.
|
128
125
|
#
|
126
|
+
# The pointer will be cleaned by `rd_kafka_topic_partition_list_destroy` when GC releases it.
|
127
|
+
#
|
128
|
+
# @return [FFI::Pointer]
|
129
129
|
# @private
|
130
130
|
def to_native_tpl
|
131
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_new(count)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
tpl,
|
137
|
-
topic,
|
138
|
-
p.partition
|
139
|
-
)
|
140
|
-
if p.offset
|
141
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(
|
142
|
-
tpl,
|
143
|
-
topic,
|
144
|
-
p.partition,
|
145
|
-
p.offset
|
146
|
-
)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
else
|
131
|
+
tpl = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(count)
|
132
|
+
|
133
|
+
@data.each do |topic, partitions|
|
134
|
+
if partitions
|
135
|
+
partitions.each do |p|
|
150
136
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
151
137
|
tpl,
|
152
138
|
topic,
|
153
|
-
|
139
|
+
p.partition
|
154
140
|
)
|
141
|
+
|
142
|
+
if p.offset
|
143
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(
|
144
|
+
tpl,
|
145
|
+
topic,
|
146
|
+
p.partition,
|
147
|
+
p.offset
|
148
|
+
)
|
149
|
+
end
|
155
150
|
end
|
151
|
+
else
|
152
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
153
|
+
tpl,
|
154
|
+
topic,
|
155
|
+
-1
|
156
|
+
)
|
156
157
|
end
|
157
158
|
end
|
159
|
+
|
160
|
+
tpl
|
158
161
|
end
|
159
162
|
end
|
160
163
|
end
|
data/lib/rdkafka/error.rb
CHANGED
@@ -39,5 +39,22 @@ module Rdkafka
|
|
39
39
|
def is_partition_eof?
|
40
40
|
code == :partition_eof
|
41
41
|
end
|
42
|
+
|
43
|
+
# Error comparison
|
44
|
+
def ==(another_error)
|
45
|
+
another_error.is_a?(self.class) && (self.to_s == another_error.to_s)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Error with topic partition list returned by the underlying rdkafka library.
|
50
|
+
class RdkafkaTopicPartitionListError < RdkafkaError
|
51
|
+
# @return [TopicPartitionList]
|
52
|
+
attr_reader :topic_partition_list
|
53
|
+
|
54
|
+
# @private
|
55
|
+
def initialize(response, topic_partition_list, message_prefix=nil)
|
56
|
+
super(response, message_prefix)
|
57
|
+
@topic_partition_list = topic_partition_list
|
58
|
+
end
|
42
59
|
end
|
43
60
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Rdkafka
|
2
|
+
class Metadata
|
3
|
+
attr_reader :brokers, :topics
|
4
|
+
|
5
|
+
def initialize(native_client, topic_name = nil)
|
6
|
+
native_topic = if topic_name
|
7
|
+
Rdkafka::Bindings.rd_kafka_topic_new(native_client, topic_name, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
ptr = FFI::MemoryPointer.new(:pointer)
|
11
|
+
|
12
|
+
# Retrieve metadata flag is 0/1 for single/multiple topics.
|
13
|
+
topic_flag = topic_name ? 1 : 0
|
14
|
+
|
15
|
+
# Retrieve the Metadata
|
16
|
+
result = Rdkafka::Bindings.rd_kafka_metadata(native_client, topic_flag, native_topic, ptr, 250)
|
17
|
+
|
18
|
+
# Error Handling
|
19
|
+
Rdkafka::Error.new(result) unless result.zero?
|
20
|
+
|
21
|
+
metadata_from_native(ptr.read_pointer)
|
22
|
+
ensure
|
23
|
+
Rdkafka::Bindings.rd_kafka_topic_destroy(native_topic) if topic_name
|
24
|
+
Rdkafka::Bindings.rd_kafka_metadata_destroy(ptr.read_pointer)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def metadata_from_native(ptr)
|
30
|
+
metadata = Metadata.new(ptr)
|
31
|
+
@brokers = Array.new(metadata[:brokers_count]) do |i|
|
32
|
+
BrokerMetadata.new(metadata[:brokers_metadata] + (i * BrokerMetadata.size)).to_h
|
33
|
+
end
|
34
|
+
|
35
|
+
@topics = Array.new(metadata[:topics_count]) do |i|
|
36
|
+
topic = TopicMetadata.new(metadata[:topics_metadata] + (i * TopicMetadata.size))
|
37
|
+
Rdkafka::Error.new(topic[:rd_kafka_resp_err]) unless topic[:rd_kafka_resp_err].zero?
|
38
|
+
|
39
|
+
partitions = Array.new(topic[:partition_count]) do |j|
|
40
|
+
partition = PartitionMetadata.new(topic[:partitions_metadata] + (j * PartitionMetadata.size))
|
41
|
+
Rdkafka::Error.new(partition[:rd_kafka_resp_err]) unless partition[:rd_kafka_resp_err].zero?
|
42
|
+
partition.to_h
|
43
|
+
end
|
44
|
+
topic.to_h.merge!(partitions: partitions)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class CustomFFIStruct < FFI::Struct
|
49
|
+
def to_h
|
50
|
+
members.each_with_object({}) do |mem, hsh|
|
51
|
+
val = self.[](mem)
|
52
|
+
next if val.is_a?(FFI::Pointer) || mem == :rd_kafka_resp_err
|
53
|
+
|
54
|
+
hsh[mem] = self.[](mem)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Metadata < CustomFFIStruct
|
60
|
+
layout :brokers_count, :int,
|
61
|
+
:brokers_metadata, :pointer,
|
62
|
+
:topics_count, :int,
|
63
|
+
:topics_metadata, :pointer,
|
64
|
+
:broker_id, :int32,
|
65
|
+
:broker_name, :string
|
66
|
+
end
|
67
|
+
|
68
|
+
class BrokerMetadata < CustomFFIStruct
|
69
|
+
layout :broker_id, :int32,
|
70
|
+
:broker_name, :string,
|
71
|
+
:broker_port, :int
|
72
|
+
end
|
73
|
+
|
74
|
+
class TopicMetadata < CustomFFIStruct
|
75
|
+
layout :topic_name, :string,
|
76
|
+
:partition_count, :int,
|
77
|
+
:partitions_metadata, :pointer,
|
78
|
+
:rd_kafka_resp_err, :int
|
79
|
+
end
|
80
|
+
|
81
|
+
class PartitionMetadata < CustomFFIStruct
|
82
|
+
layout :partition_id, :int32,
|
83
|
+
:rd_kafka_resp_err, :int,
|
84
|
+
:leader, :int32,
|
85
|
+
:replica_count, :int,
|
86
|
+
:replicas, :pointer,
|
87
|
+
:in_sync_replica_brokers, :int,
|
88
|
+
:isrs, :pointer
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -2,7 +2,10 @@ module Rdkafka
|
|
2
2
|
# A producer for Kafka messages. To create a producer set up a {Config} and call {Config#producer producer} on that.
|
3
3
|
class Producer
|
4
4
|
# @private
|
5
|
-
|
5
|
+
# Returns the current delivery callback, by default this is nil.
|
6
|
+
#
|
7
|
+
# @return [Proc, nil]
|
8
|
+
attr_reader :delivery_callback
|
6
9
|
|
7
10
|
# @private
|
8
11
|
def initialize(native_kafka)
|
@@ -32,36 +35,45 @@ module Rdkafka
|
|
32
35
|
@delivery_callback = callback
|
33
36
|
end
|
34
37
|
|
35
|
-
# Returns the current delivery callback, by default this is nil.
|
36
|
-
#
|
37
|
-
# @return [Proc, nil]
|
38
|
-
def delivery_callback
|
39
|
-
@delivery_callback
|
40
|
-
end
|
41
|
-
|
42
38
|
# Close this producer and wait for the internal poll queue to empty.
|
43
39
|
def close
|
40
|
+
return unless @native_kafka
|
41
|
+
|
44
42
|
# Indicate to polling thread that we're closing
|
45
43
|
@closing = true
|
46
44
|
# Wait for the polling thread to finish up
|
47
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)
|
48
59
|
end
|
49
60
|
|
50
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.
|
51
62
|
#
|
52
63
|
# When no partition is specified the underlying Kafka library picks a partition based on the key. If no key is specified, a random partition will be used.
|
53
|
-
# When a timestamp is provided this is used instead of the
|
64
|
+
# When a timestamp is provided this is used instead of the auto-generated timestamp.
|
54
65
|
#
|
55
66
|
# @param topic [String] The topic to produce to
|
56
67
|
# @param payload [String,nil] The message's payload
|
57
68
|
# @param key [String] The message's key
|
58
69
|
# @param partition [Integer,nil] Optional partition to produce to
|
59
70
|
# @param timestamp [Time,Integer,nil] Optional timestamp of this message. Integer timestamp is in milliseconds since Jan 1 1970.
|
71
|
+
# @param headers [Hash<String,String>] Optional message headers
|
60
72
|
#
|
61
73
|
# @raise [RdkafkaError] When adding the message to rdkafka's queue failed
|
62
74
|
#
|
63
75
|
# @return [DeliveryHandle] Delivery handle that can be used to wait for the result of producing this message
|
64
|
-
def produce(topic:, payload: nil, key: nil, partition: nil, timestamp: nil)
|
76
|
+
def produce(topic:, payload: nil, key: nil, partition: nil, partition_key: nil, timestamp: nil, headers: nil)
|
65
77
|
# Start by checking and converting the input
|
66
78
|
|
67
79
|
# Get payload length
|
@@ -78,9 +90,15 @@ module Rdkafka
|
|
78
90
|
key.bytesize
|
79
91
|
end
|
80
92
|
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
84
102
|
|
85
103
|
# If timestamp is nil use 0 and let Kafka set one. If an integer or time
|
86
104
|
# use it.
|
@@ -101,9 +119,7 @@ module Rdkafka
|
|
101
119
|
delivery_handle[:offset] = -1
|
102
120
|
DeliveryHandle.register(delivery_handle.to_ptr.address, delivery_handle)
|
103
121
|
|
104
|
-
|
105
|
-
response = Rdkafka::Bindings.rd_kafka_producev(
|
106
|
-
@native_kafka,
|
122
|
+
args = [
|
107
123
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_TOPIC, :string, topic,
|
108
124
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_MSGFLAGS, :int, Rdkafka::Bindings::RD_KAFKA_MSG_F_COPY,
|
109
125
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_VALUE, :buffer_in, payload, :size_t, payload_size,
|
@@ -111,10 +127,30 @@ module Rdkafka
|
|
111
127
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_PARTITION, :int32, partition,
|
112
128
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_TIMESTAMP, :int64, raw_timestamp,
|
113
129
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_OPAQUE, :pointer, delivery_handle,
|
114
|
-
|
130
|
+
]
|
131
|
+
|
132
|
+
if headers
|
133
|
+
headers.each do |key0, value0|
|
134
|
+
key = key0.to_s
|
135
|
+
value = value0.to_s
|
136
|
+
args += [
|
137
|
+
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_HEADER,
|
138
|
+
:string, key,
|
139
|
+
:pointer, value,
|
140
|
+
:size_t, value.bytes.size
|
141
|
+
]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
args += [:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_END]
|
146
|
+
|
147
|
+
# Produce the message
|
148
|
+
response = Rdkafka::Bindings.rd_kafka_producev(
|
149
|
+
@native_kafka,
|
150
|
+
*args
|
115
151
|
)
|
116
152
|
|
117
|
-
# Raise error if the produce call was not
|
153
|
+
# Raise error if the produce call was not successful
|
118
154
|
if response != 0
|
119
155
|
DeliveryHandle.remove(delivery_handle.to_ptr.address)
|
120
156
|
raise RdkafkaError.new(response)
|