karafka-rdkafka 0.12.2 → 0.13.0.beta1
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
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +26 -0
- data/Gemfile +2 -0
- data/README.md +26 -0
- data/Rakefile +2 -0
- data/ext/Rakefile +2 -0
- data/karafka-rdkafka.gemspec +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 +95 -73
- data/lib/rdkafka/bindings.rb +53 -37
- data/lib/rdkafka/callbacks.rb +7 -1
- data/lib/rdkafka/config.rb +13 -10
- 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 +100 -44
- data/lib/rdkafka/error.rb +9 -0
- data/lib/rdkafka/metadata.rb +25 -2
- data/lib/rdkafka/native_kafka.rb +83 -0
- data/lib/rdkafka/producer/delivery_handle.rb +5 -2
- data/lib/rdkafka/producer/delivery_report.rb +9 -2
- data/lib/rdkafka/producer.rb +75 -12
- data/lib/rdkafka/version.rb +3 -1
- data/lib/rdkafka.rb +3 -1
- 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 +17 -2
- data/spec/rdkafka/consumer/headers_spec.rb +62 -0
- data/spec/rdkafka/consumer/message_spec.rb +2 -0
- 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 +124 -22
- data/spec/rdkafka/error_spec.rb +2 -0
- data/spec/rdkafka/metadata_spec.rb +2 -0
- data/spec/rdkafka/{producer/client_spec.rb → native_kafka_spec.rb} +13 -34
- 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 +124 -19
- data/spec/spec_helper.rb +17 -1
- data.tar.gz.sig +0 -0
- metadata +10 -10
- metadata.gz.sig +0 -0
- data/bin/console +0 -11
- data/lib/rdkafka/producer/client.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 419dcef5e71a6578202fde7eacd628054ac77bae0c91c57845fd6dbd6ade6715
|
4
|
+
data.tar.gz: 05e7e1ef8e07c1b2dddf02f1e3f8e8e0da7dfcb75af41ccc2f9dcba2e30bba1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4643afd749af09b9bd2c8d16ae25b989eb03feb39b12c966059956cad47966a8a74e6d0c356bfdd4115a3a419aebbab1d8421410e0bef64bd2f1611d66ba2ab6
|
7
|
+
data.tar.gz: 7f526e3bb375126862a84b7824e60872454366cfa7a2b5abb8d6e09f978423dc1e56e1c2a488f36f28ff622f942834b7d576d6fe91e4263cb5864165597c881f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
# 0.13.0
|
2
|
+
* Support cooperative sticky partition assignment in the rebalance callback (methodmissing)
|
3
|
+
* Support both string and symbol header keys (ColinDKelley)
|
4
|
+
* Handle tombstone messages properly (kgalieva)
|
5
|
+
* Add topic name to delivery report (maeve)
|
6
|
+
* Allow string partitioner config (mollyegibson)
|
7
|
+
* Fix documented type for DeliveryReport#error (jimmydo)
|
8
|
+
* Bump librdkafka to 2.0.2 (lmaia)
|
9
|
+
* Use finalizers to cleanly exit producer and admin (thijsc)
|
10
|
+
* Lock access to the native kafka client (thijsc)
|
11
|
+
* Fix potential race condition in multi-threaded producer (mensfeld)
|
12
|
+
* Fix leaking FFI resources in specs (mensfeld)
|
13
|
+
* Improve specs stability (mensfeld)
|
14
|
+
* Make metadata request timeout configurable (mensfeld)
|
15
|
+
* call_on_partitions_assigned and call_on_partitions_revoked only get a tpl passed in (thijsc)
|
16
|
+
* Support `#assignment_lost?` on a consumer to check for involuntary assignment revocation (mensfeld)
|
17
|
+
* Expose `#name` on the consumer and producer (mensfeld)
|
18
|
+
* Introduce producer partitions count metadata cache (mensfeld)
|
19
|
+
* Retry metadta fetches on certain errors with a backoff (mensfeld)
|
20
|
+
|
21
|
+
# 0.12.3
|
22
|
+
- Include backtrace in non-raised binded errors.
|
23
|
+
- Include topic name in the delivery reports
|
24
|
+
|
1
25
|
# 0.12.2
|
2
26
|
* Increase the metadata default timeout from 250ms to 2 seconds. This should allow for working with remote clusters.
|
3
27
|
|
@@ -7,6 +31,8 @@
|
|
7
31
|
|
8
32
|
# 0.12.0
|
9
33
|
* Bumps librdkafka to 1.9.0
|
34
|
+
* Fix crash on empty partition key (mensfeld)
|
35
|
+
* Pass the delivery handle to the callback (gvisokinskas)
|
10
36
|
|
11
37
|
# 0.11.0
|
12
38
|
* Upgrade librdkafka to 1.8.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -23,6 +23,19 @@ The most important pieces of a Kafka client are implemented. We're
|
|
23
23
|
working towards feature completeness, you can track that here:
|
24
24
|
https://github.com/appsignal/rdkafka-ruby/milestone/1
|
25
25
|
|
26
|
+
## Table of content
|
27
|
+
|
28
|
+
- [Installation](#installation)
|
29
|
+
- [Usage](#usage)
|
30
|
+
* [Consuming messages](#consuming-messages)
|
31
|
+
* [Producing messages](#producing-messages)
|
32
|
+
- [Higher level libraries](#higher-level-libraries)
|
33
|
+
* [Message processing frameworks](#message-processing-frameworks)
|
34
|
+
* [Message publishing libraries](#message-publishing-libraries)
|
35
|
+
- [Development](#development)
|
36
|
+
- [Example](#example)
|
37
|
+
|
38
|
+
|
26
39
|
## Installation
|
27
40
|
|
28
41
|
This gem downloads and compiles librdkafka when it is installed. If you
|
@@ -77,6 +90,19 @@ Note that creating a producer consumes some resources that will not be
|
|
77
90
|
released until it `#close` is explicitly called, so be sure to call
|
78
91
|
`Config#producer` only as necessary.
|
79
92
|
|
93
|
+
## Higher level libraries
|
94
|
+
|
95
|
+
Currently, there are two actively developed frameworks based on rdkafka-ruby, that provide higher level API that can be used to work with Kafka messages and one library for publishing messages.
|
96
|
+
|
97
|
+
### Message processing frameworks
|
98
|
+
|
99
|
+
* [Karafka](https://github.com/karafka/karafka) - Ruby and Rails efficient Kafka processing framework.
|
100
|
+
* [Racecar](https://github.com/zendesk/racecar) - A simple framework for Kafka consumers in Ruby
|
101
|
+
|
102
|
+
### Message publishing libraries
|
103
|
+
|
104
|
+
* [WaterDrop](https://github.com/karafka/waterdrop) – Standalone Karafka library for producing Kafka messages.
|
105
|
+
|
80
106
|
## Development
|
81
107
|
|
82
108
|
A Docker Compose file is included to run Kafka and Zookeeper. To run
|
data/Rakefile
CHANGED
data/ext/Rakefile
CHANGED
data/karafka-rdkafka.gemspec
CHANGED
data/lib/rdkafka/admin.rb
CHANGED
@@ -1,33 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "objspace"
|
4
|
+
|
1
5
|
module Rdkafka
|
2
6
|
class Admin
|
3
7
|
# @private
|
4
8
|
def initialize(native_kafka)
|
5
9
|
@native_kafka = native_kafka
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
if @closing && Rdkafka::Bindings.rd_kafka_outq_len(@native_kafka) == 0
|
14
|
-
break
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
@polling_thread.abort_on_exception = true
|
10
|
+
|
11
|
+
# Makes sure, that native kafka gets closed before it gets GCed by Ruby
|
12
|
+
ObjectSpace.define_finalizer(self, native_kafka.finalizer)
|
13
|
+
end
|
14
|
+
|
15
|
+
def finalizer
|
16
|
+
->(_) { close }
|
19
17
|
end
|
20
18
|
|
21
19
|
# Close this admin instance
|
22
20
|
def close
|
23
|
-
return
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@native_kafka
|
21
|
+
return if closed?
|
22
|
+
ObjectSpace.undefine_finalizer(self)
|
23
|
+
@native_kafka.close
|
24
|
+
end
|
25
|
+
|
26
|
+
# Whether this admin has closed
|
27
|
+
def closed?
|
28
|
+
@native_kafka.closed?
|
31
29
|
end
|
32
30
|
|
33
31
|
# Create a topic with the given partition count and replication factor
|
@@ -38,6 +36,7 @@ module Rdkafka
|
|
38
36
|
#
|
39
37
|
# @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
|
40
38
|
def create_topic(topic_name, partition_count, replication_factor, topic_config={})
|
39
|
+
closed_admin_check(__method__)
|
41
40
|
|
42
41
|
# Create a rd_kafka_NewTopic_t representing the new topic
|
43
42
|
error_buffer = FFI::MemoryPointer.from_string(" " * 256)
|
@@ -68,7 +67,9 @@ module Rdkafka
|
|
68
67
|
topics_array_ptr.write_array_of_pointer(pointer_array)
|
69
68
|
|
70
69
|
# Get a pointer to the queue that our request will be enqueued on
|
71
|
-
queue_ptr =
|
70
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
71
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
72
|
+
end
|
72
73
|
if queue_ptr.null?
|
73
74
|
Rdkafka::Bindings.rd_kafka_NewTopic_destroy(new_topic_ptr)
|
74
75
|
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
@@ -79,17 +80,21 @@ module Rdkafka
|
|
79
80
|
create_topic_handle[:pending] = true
|
80
81
|
create_topic_handle[:response] = -1
|
81
82
|
CreateTopicHandle.register(create_topic_handle)
|
82
|
-
admin_options_ptr =
|
83
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
84
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATETOPICS)
|
85
|
+
end
|
83
86
|
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_topic_handle.to_ptr)
|
84
87
|
|
85
88
|
begin
|
86
|
-
|
87
|
-
|
89
|
+
@native_kafka.with_inner do |inner|
|
90
|
+
Rdkafka::Bindings.rd_kafka_CreateTopics(
|
91
|
+
inner,
|
88
92
|
topics_array_ptr,
|
89
93
|
1,
|
90
94
|
admin_options_ptr,
|
91
95
|
queue_ptr
|
92
|
-
|
96
|
+
)
|
97
|
+
end
|
93
98
|
rescue Exception
|
94
99
|
CreateTopicHandle.remove(create_topic_handle.to_ptr.address)
|
95
100
|
raise
|
@@ -108,6 +113,7 @@ module Rdkafka
|
|
108
113
|
#
|
109
114
|
# @return [DeleteTopicHandle] Delete topic handle that can be used to wait for the result of deleting the topic
|
110
115
|
def delete_topic(topic_name)
|
116
|
+
closed_admin_check(__method__)
|
111
117
|
|
112
118
|
# Create a rd_kafka_DeleteTopic_t representing the topic to be deleted
|
113
119
|
delete_topic_ptr = Rdkafka::Bindings.rd_kafka_DeleteTopic_new(FFI::MemoryPointer.from_string(topic_name))
|
@@ -118,7 +124,9 @@ module Rdkafka
|
|
118
124
|
topics_array_ptr.write_array_of_pointer(pointer_array)
|
119
125
|
|
120
126
|
# Get a pointer to the queue that our request will be enqueued on
|
121
|
-
queue_ptr =
|
127
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
128
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
129
|
+
end
|
122
130
|
if queue_ptr.null?
|
123
131
|
Rdkafka::Bindings.rd_kafka_DeleteTopic_destroy(delete_topic_ptr)
|
124
132
|
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
@@ -129,17 +137,21 @@ module Rdkafka
|
|
129
137
|
delete_topic_handle[:pending] = true
|
130
138
|
delete_topic_handle[:response] = -1
|
131
139
|
DeleteTopicHandle.register(delete_topic_handle)
|
132
|
-
admin_options_ptr =
|
140
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
141
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETETOPICS)
|
142
|
+
end
|
133
143
|
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_topic_handle.to_ptr)
|
134
144
|
|
135
145
|
begin
|
136
|
-
|
137
|
-
|
146
|
+
@native_kafka.with_inner do |inner|
|
147
|
+
Rdkafka::Bindings.rd_kafka_DeleteTopics(
|
148
|
+
inner,
|
138
149
|
topics_array_ptr,
|
139
150
|
1,
|
140
151
|
admin_options_ptr,
|
141
152
|
queue_ptr
|
142
|
-
|
153
|
+
)
|
154
|
+
end
|
143
155
|
rescue Exception
|
144
156
|
DeleteTopicHandle.remove(delete_topic_handle.to_ptr.address)
|
145
157
|
raise
|
@@ -163,54 +175,64 @@ module Rdkafka
|
|
163
175
|
#
|
164
176
|
# @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
|
165
177
|
def create_partitions(topic_name, partition_count)
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
178
|
+
closed_admin_check(__method__)
|
179
|
+
|
180
|
+
@native_kafka.with_inner do |inner|
|
181
|
+
error_buffer = FFI::MemoryPointer.from_string(" " * 256)
|
182
|
+
new_partitions_ptr = Rdkafka::Bindings.rd_kafka_NewPartitions_new(
|
183
|
+
FFI::MemoryPointer.from_string(topic_name),
|
184
|
+
partition_count,
|
185
|
+
error_buffer,
|
186
|
+
256
|
187
|
+
)
|
188
|
+
if new_partitions_ptr.null?
|
189
|
+
raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
|
190
|
+
end
|
176
191
|
|
177
|
-
|
178
|
-
|
179
|
-
|
192
|
+
pointer_array = [new_partitions_ptr]
|
193
|
+
topics_array_ptr = FFI::MemoryPointer.new(:pointer)
|
194
|
+
topics_array_ptr.write_array_of_pointer(pointer_array)
|
180
195
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
196
|
+
# Get a pointer to the queue that our request will be enqueued on
|
197
|
+
queue_ptr = Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
198
|
+
if queue_ptr.null?
|
199
|
+
Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
|
200
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
201
|
+
end
|
187
202
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
203
|
+
# Create and register the handle we will return to the caller
|
204
|
+
create_partitions_handle = CreatePartitionsHandle.new
|
205
|
+
create_partitions_handle[:pending] = true
|
206
|
+
create_partitions_handle[:response] = -1
|
207
|
+
CreatePartitionsHandle.register(create_partitions_handle)
|
208
|
+
admin_options_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS)
|
209
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_partitions_handle.to_ptr)
|
210
|
+
|
211
|
+
begin
|
212
|
+
Rdkafka::Bindings.rd_kafka_CreatePartitions(
|
213
|
+
inner,
|
214
|
+
topics_array_ptr,
|
215
|
+
1,
|
216
|
+
admin_options_ptr,
|
217
|
+
queue_ptr
|
218
|
+
)
|
219
|
+
rescue Exception
|
220
|
+
CreatePartitionsHandle.remove(create_partitions_handle.to_ptr.address)
|
221
|
+
raise
|
222
|
+
ensure
|
223
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
224
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
225
|
+
Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
|
226
|
+
end
|
195
227
|
|
196
|
-
|
197
|
-
Rdkafka::Bindings.rd_kafka_CreatePartitions(
|
198
|
-
@native_kafka,
|
199
|
-
topics_array_ptr,
|
200
|
-
1,
|
201
|
-
admin_options_ptr,
|
202
|
-
queue_ptr
|
203
|
-
)
|
204
|
-
rescue Exception
|
205
|
-
CreatePartitionsHandle.remove(create_partitions_handle.to_ptr.address)
|
206
|
-
raise
|
207
|
-
ensure
|
208
|
-
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
209
|
-
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
210
|
-
Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
|
228
|
+
create_partitions_handle
|
211
229
|
end
|
230
|
+
end
|
231
|
+
|
232
|
+
private
|
212
233
|
|
213
|
-
|
234
|
+
def closed_admin_check(method)
|
235
|
+
raise Rdkafka::ClosedAdminError.new(method) if closed?
|
214
236
|
end
|
215
237
|
end
|
216
238
|
end
|
data/lib/rdkafka/bindings.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "ffi"
|
2
4
|
require "json"
|
3
5
|
require "logger"
|
@@ -15,7 +17,7 @@ module Rdkafka
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
ffi_lib File.join(
|
20
|
+
ffi_lib File.join(__dir__, "../../ext/librdkafka.#{lib_extension}")
|
19
21
|
|
20
22
|
RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS = -175
|
21
23
|
RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS = -174
|
@@ -33,15 +35,17 @@ module Rdkafka
|
|
33
35
|
|
34
36
|
# Polling
|
35
37
|
|
38
|
+
attach_function :rd_kafka_flush, [:pointer, :int], :void, blocking: true
|
36
39
|
attach_function :rd_kafka_poll, [:pointer, :int], :void, blocking: true
|
37
40
|
attach_function :rd_kafka_outq_len, [:pointer], :int, blocking: true
|
38
41
|
|
39
42
|
# Metadata
|
40
43
|
|
41
|
-
attach_function :
|
42
|
-
attach_function :
|
43
|
-
attach_function :
|
44
|
-
attach_function :
|
44
|
+
attach_function :rd_kafka_name, [:pointer], :string, blocking: true
|
45
|
+
attach_function :rd_kafka_memberid, [:pointer], :string, blocking: true
|
46
|
+
attach_function :rd_kafka_clusterid, [:pointer], :string, blocking: true
|
47
|
+
attach_function :rd_kafka_metadata, [:pointer, :int, :pointer, :pointer, :int], :int, blocking: true
|
48
|
+
attach_function :rd_kafka_metadata_destroy, [:pointer], :void, blocking: true
|
45
49
|
|
46
50
|
# Message struct
|
47
51
|
|
@@ -110,6 +114,7 @@ module Rdkafka
|
|
110
114
|
attach_function :rd_kafka_conf_set_stats_cb, [:pointer, :stats_cb], :void
|
111
115
|
callback :error_cb, [:pointer, :int, :string, :pointer], :void
|
112
116
|
attach_function :rd_kafka_conf_set_error_cb, [:pointer, :error_cb], :void
|
117
|
+
attach_function :rd_kafka_rebalance_protocol, [:pointer], :string
|
113
118
|
|
114
119
|
# Log queue
|
115
120
|
attach_function :rd_kafka_set_log_queue, [:pointer, :pointer], :void
|
@@ -153,6 +158,7 @@ module Rdkafka
|
|
153
158
|
) do |_client_prr, err_code, reason, _opaque|
|
154
159
|
if Rdkafka::Config.error_callback
|
155
160
|
error = Rdkafka::RdkafkaError.new(err_code, broker_message: reason)
|
161
|
+
error.set_backtrace(caller)
|
156
162
|
Rdkafka::Config.error_callback.call(error)
|
157
163
|
end
|
158
164
|
end
|
@@ -165,24 +171,28 @@ module Rdkafka
|
|
165
171
|
]
|
166
172
|
|
167
173
|
attach_function :rd_kafka_new, [:kafka_type, :pointer, :pointer, :int], :pointer
|
174
|
+
|
168
175
|
attach_function :rd_kafka_destroy, [:pointer], :void
|
169
176
|
|
170
177
|
# Consumer
|
171
178
|
|
172
|
-
attach_function :rd_kafka_subscribe, [:pointer, :pointer], :int
|
173
|
-
attach_function :rd_kafka_unsubscribe, [:pointer], :int
|
174
|
-
attach_function :rd_kafka_subscription, [:pointer, :pointer], :int
|
175
|
-
attach_function :rd_kafka_assign, [:pointer, :pointer], :int
|
176
|
-
attach_function :
|
177
|
-
attach_function :
|
179
|
+
attach_function :rd_kafka_subscribe, [:pointer, :pointer], :int, blocking: true
|
180
|
+
attach_function :rd_kafka_unsubscribe, [:pointer], :int, blocking: true
|
181
|
+
attach_function :rd_kafka_subscription, [:pointer, :pointer], :int, blocking: true
|
182
|
+
attach_function :rd_kafka_assign, [:pointer, :pointer], :int, blocking: true
|
183
|
+
attach_function :rd_kafka_incremental_assign, [:pointer, :pointer], :int, blocking: true
|
184
|
+
attach_function :rd_kafka_incremental_unassign, [:pointer, :pointer], :int, blocking: true
|
185
|
+
attach_function :rd_kafka_assignment, [:pointer, :pointer], :int, blocking: true
|
186
|
+
attach_function :rd_kafka_assignment_lost, [:pointer], :int, blocking: true
|
187
|
+
attach_function :rd_kafka_committed, [:pointer, :pointer, :int], :int, blocking: true
|
178
188
|
attach_function :rd_kafka_commit, [:pointer, :pointer, :bool], :int, blocking: true
|
179
|
-
attach_function :rd_kafka_poll_set_consumer, [:pointer], :void
|
189
|
+
attach_function :rd_kafka_poll_set_consumer, [:pointer], :void, blocking: true
|
180
190
|
attach_function :rd_kafka_consumer_poll, [:pointer, :int], :pointer, blocking: true
|
181
191
|
attach_function :rd_kafka_consumer_close, [:pointer], :void, blocking: true
|
182
|
-
attach_function :rd_kafka_offset_store, [:pointer, :int32, :int64], :int
|
183
|
-
attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int
|
184
|
-
attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int
|
185
|
-
attach_function :rd_kafka_seek, [:pointer, :int32, :int64, :int], :int
|
192
|
+
attach_function :rd_kafka_offset_store, [:pointer, :int32, :int64], :int, blocking: true
|
193
|
+
attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int, blocking: true
|
194
|
+
attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int, blocking: true
|
195
|
+
attach_function :rd_kafka_seek, [:pointer, :int32, :int64, :int], :int, blocking: true
|
186
196
|
|
187
197
|
# Headers
|
188
198
|
attach_function :rd_kafka_header_get_all, [:pointer, :size_t, :pointer, :pointer, SizePtr], :int
|
@@ -191,30 +201,36 @@ module Rdkafka
|
|
191
201
|
# Rebalance
|
192
202
|
|
193
203
|
callback :rebalance_cb_function, [:pointer, :int, :pointer, :pointer], :void
|
194
|
-
attach_function :rd_kafka_conf_set_rebalance_cb, [:pointer, :rebalance_cb_function], :void
|
204
|
+
attach_function :rd_kafka_conf_set_rebalance_cb, [:pointer, :rebalance_cb_function], :void, blocking: true
|
195
205
|
|
196
206
|
RebalanceCallback = FFI::Function.new(
|
197
207
|
:void, [:pointer, :int, :pointer, :pointer]
|
198
208
|
) do |client_ptr, code, partitions_ptr, opaque_ptr|
|
199
209
|
case code
|
200
210
|
when RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS
|
201
|
-
Rdkafka::Bindings.
|
211
|
+
if Rdkafka::Bindings.rd_kafka_rebalance_protocol(client_ptr) == "COOPERATIVE"
|
212
|
+
Rdkafka::Bindings.rd_kafka_incremental_assign(client_ptr, partitions_ptr)
|
213
|
+
else
|
214
|
+
Rdkafka::Bindings.rd_kafka_assign(client_ptr, partitions_ptr)
|
215
|
+
end
|
202
216
|
else # RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS or errors
|
203
|
-
Rdkafka::Bindings.
|
217
|
+
if Rdkafka::Bindings.rd_kafka_rebalance_protocol(client_ptr) == "COOPERATIVE"
|
218
|
+
Rdkafka::Bindings.rd_kafka_incremental_unassign(client_ptr, partitions_ptr)
|
219
|
+
else
|
220
|
+
Rdkafka::Bindings.rd_kafka_assign(client_ptr, FFI::Pointer::NULL)
|
221
|
+
end
|
204
222
|
end
|
205
223
|
|
206
224
|
opaque = Rdkafka::Config.opaques[opaque_ptr.to_i]
|
207
225
|
return unless opaque
|
208
226
|
|
209
227
|
tpl = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(partitions_ptr).freeze
|
210
|
-
consumer = Rdkafka::Consumer.new(client_ptr)
|
211
|
-
|
212
228
|
begin
|
213
229
|
case code
|
214
230
|
when RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS
|
215
|
-
opaque.call_on_partitions_assigned(
|
231
|
+
opaque.call_on_partitions_assigned(tpl)
|
216
232
|
when RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS
|
217
|
-
opaque.call_on_partitions_revoked(
|
233
|
+
opaque.call_on_partitions_revoked(tpl)
|
218
234
|
end
|
219
235
|
rescue Exception => err
|
220
236
|
Rdkafka::Config.logger.error("Unhandled exception: #{err.class} - #{err.message}")
|
@@ -241,7 +257,7 @@ module Rdkafka
|
|
241
257
|
|
242
258
|
RD_KAFKA_MSG_F_COPY = 0x2
|
243
259
|
|
244
|
-
attach_function :rd_kafka_producev, [:pointer, :varargs], :int
|
260
|
+
attach_function :rd_kafka_producev, [:pointer, :varargs], :int, blocking: true
|
245
261
|
callback :delivery_cb, [:pointer, :pointer, :pointer], :void
|
246
262
|
attach_function :rd_kafka_conf_set_dr_msg_cb, [:pointer, :delivery_cb], :void
|
247
263
|
|
@@ -256,11 +272,11 @@ module Rdkafka
|
|
256
272
|
# Return RD_KAFKA_PARTITION_UA(unassigned partition) when partition count is nil/zero.
|
257
273
|
return -1 unless partition_count&.nonzero?
|
258
274
|
|
259
|
-
str_ptr = FFI::MemoryPointer.from_string(str)
|
275
|
+
str_ptr = str.empty? ? FFI::MemoryPointer::NULL : FFI::MemoryPointer.from_string(str)
|
260
276
|
method_name = PARTITIONERS.fetch(partitioner_name) do
|
261
277
|
raise Rdkafka::Config::ConfigError.new("Unknown partitioner: #{partitioner_name}")
|
262
278
|
end
|
263
|
-
public_send(method_name, nil, str_ptr, str.size, partition_count, nil, nil)
|
279
|
+
public_send(method_name, nil, str_ptr, str.size > 0 ? str.size : 1, partition_count, nil, nil)
|
264
280
|
end
|
265
281
|
|
266
282
|
# Create Topics
|
@@ -268,23 +284,23 @@ module Rdkafka
|
|
268
284
|
RD_KAFKA_ADMIN_OP_CREATETOPICS = 1 # rd_kafka_admin_op_t
|
269
285
|
RD_KAFKA_EVENT_CREATETOPICS_RESULT = 100 # rd_kafka_event_type_t
|
270
286
|
|
271
|
-
attach_function :rd_kafka_CreateTopics, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
|
272
|
-
attach_function :rd_kafka_NewTopic_new, [:pointer, :size_t, :size_t, :pointer, :size_t], :pointer
|
273
|
-
attach_function :rd_kafka_NewTopic_set_config, [:pointer, :string, :string], :int32
|
274
|
-
attach_function :rd_kafka_NewTopic_destroy, [:pointer], :void
|
275
|
-
attach_function :rd_kafka_event_CreateTopics_result, [:pointer], :pointer
|
276
|
-
attach_function :rd_kafka_CreateTopics_result_topics, [:pointer, :pointer], :pointer
|
287
|
+
attach_function :rd_kafka_CreateTopics, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
|
288
|
+
attach_function :rd_kafka_NewTopic_new, [:pointer, :size_t, :size_t, :pointer, :size_t], :pointer, blocking: true
|
289
|
+
attach_function :rd_kafka_NewTopic_set_config, [:pointer, :string, :string], :int32, blocking: true
|
290
|
+
attach_function :rd_kafka_NewTopic_destroy, [:pointer], :void, blocking: true
|
291
|
+
attach_function :rd_kafka_event_CreateTopics_result, [:pointer], :pointer, blocking: true
|
292
|
+
attach_function :rd_kafka_CreateTopics_result_topics, [:pointer, :pointer], :pointer, blocking: true
|
277
293
|
|
278
294
|
# Delete Topics
|
279
295
|
|
280
296
|
RD_KAFKA_ADMIN_OP_DELETETOPICS = 2 # rd_kafka_admin_op_t
|
281
297
|
RD_KAFKA_EVENT_DELETETOPICS_RESULT = 101 # rd_kafka_event_type_t
|
282
298
|
|
283
|
-
attach_function :rd_kafka_DeleteTopics, [:pointer, :pointer, :size_t, :pointer, :pointer], :int32
|
284
|
-
attach_function :rd_kafka_DeleteTopic_new, [:pointer], :pointer
|
285
|
-
attach_function :rd_kafka_DeleteTopic_destroy, [:pointer], :void
|
286
|
-
attach_function :rd_kafka_event_DeleteTopics_result, [:pointer], :pointer
|
287
|
-
attach_function :rd_kafka_DeleteTopics_result_topics, [:pointer, :pointer], :pointer
|
299
|
+
attach_function :rd_kafka_DeleteTopics, [:pointer, :pointer, :size_t, :pointer, :pointer], :int32, blocking: true
|
300
|
+
attach_function :rd_kafka_DeleteTopic_new, [:pointer], :pointer, blocking: true
|
301
|
+
attach_function :rd_kafka_DeleteTopic_destroy, [:pointer], :void, blocking: true
|
302
|
+
attach_function :rd_kafka_event_DeleteTopics_result, [:pointer], :pointer, blocking: true
|
303
|
+
attach_function :rd_kafka_DeleteTopics_result_topics, [:pointer, :pointer], :pointer, blocking: true
|
288
304
|
|
289
305
|
# Create partitions
|
290
306
|
RD_KAFKA_ADMIN_OP_CREATEPARTITIONS = 3
|
data/lib/rdkafka/callbacks.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rdkafka
|
2
4
|
module Callbacks
|
3
5
|
|
@@ -109,14 +111,18 @@ module Rdkafka
|
|
109
111
|
message = Rdkafka::Bindings::Message.new(message_ptr)
|
110
112
|
delivery_handle_ptr_address = message[:_private].address
|
111
113
|
if delivery_handle = Rdkafka::Producer::DeliveryHandle.remove(delivery_handle_ptr_address)
|
114
|
+
topic_name = Rdkafka::Bindings.rd_kafka_topic_name(message[:rkt])
|
115
|
+
|
112
116
|
# Update delivery handle
|
113
117
|
delivery_handle[:response] = message[:err]
|
114
118
|
delivery_handle[:partition] = message[:partition]
|
115
119
|
delivery_handle[:offset] = message[:offset]
|
120
|
+
delivery_handle[:topic_name] = FFI::MemoryPointer.from_string(topic_name)
|
116
121
|
delivery_handle[:pending] = false
|
122
|
+
|
117
123
|
# Call delivery callback on opaque
|
118
124
|
if opaque = Rdkafka::Config.opaques[opaque_ptr.to_i]
|
119
|
-
opaque.call_delivery_callback(Rdkafka::Producer::DeliveryReport.new(message[:partition], message[:offset], message[:err]), delivery_handle)
|
125
|
+
opaque.call_delivery_callback(Rdkafka::Producer::DeliveryReport.new(message[:partition], message[:offset], topic_name, message[:err]), delivery_handle)
|
120
126
|
end
|
121
127
|
end
|
122
128
|
end
|