rdkafka 0.26.0-x86_64-linux-gnu → 0.27.0-x86_64-linux-gnu
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/CHANGELOG.md +8 -0
- data/README.md +2 -1
- data/ext/librdkafka.so +0 -0
- data/lib/rdkafka/admin.rb +6 -0
- data/lib/rdkafka/bindings.rb +6 -0
- data/lib/rdkafka/config.rb +43 -4
- data/lib/rdkafka/consumer.rb +150 -0
- data/lib/rdkafka/version.rb +3 -3
- data/renovate.json +4 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0c56d579e4d1a59b3d55fda47b2685249d5eeaf4bfaf4c9b12155d6d37ab7dd
|
|
4
|
+
data.tar.gz: baaeb33d9c536e8974b97800f8918693b946a93f7ef84e239905845c31a74e77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70aaae7594ec3f565e0d8e8af3b45c67232a1e57719c9e8c779da32789cb0eb8362c568af67bc263d6428815afcb531df4fb44add4f36fdf5edfa1d432514c34
|
|
7
|
+
data.tar.gz: 308256385ba96717ad97a8f8c609629fa513f161bba63b5d22d5cc4295921094712a22f1632ac63d692e78d18d6d9e3a8e0068ff2d655073f049eb3ccac945fd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Rdkafka Changelog
|
|
2
2
|
|
|
3
|
+
## 0.27.0 (2026-05-07)
|
|
4
|
+
- [Feature] Add `Consumer#poll_batch(timeout_ms, max_items:)` and `Consumer#poll_batch_nb(timeout_ms, max_items:)` for batch message polling via `rd_kafka_consume_batch_queue`.
|
|
5
|
+
- [Feature] Add `Config#describe_properties` to dump all librdkafka configuration properties (including defaults and hidden properties) as a Hash via `rd_kafka_conf_dump`.
|
|
6
|
+
- [Enhancement] Bump librdkafka to `2.14.0`
|
|
7
|
+
- [Fix] Fix resource leak in `Admin#describe_configs` and `Admin#incremental_alter_configs` where `admin_options_ptr` and `queue_ptr` were not destroyed in the ensure block.
|
|
8
|
+
- [Fix] Fix leaked queue reference in `Config#native_kafka` where `rd_kafka_queue_get_main` return value was not destroyed after passing to `rd_kafka_set_log_queue`.
|
|
9
|
+
- [Fix] Fix native topic partition list leak in `Consumer#position` where `tpl` was never destroyed.
|
|
10
|
+
|
|
3
11
|
## 0.26.0 (2026-04-02)
|
|
4
12
|
- [Enhancement] Bump librdkafka to `2.13.2`
|
|
5
13
|
- [Enhancement] Embed a per-file SPEC_HASH in test topic and consumer group names for tracing Kafka warnings back to specific spec files.
|
data/README.md
CHANGED
|
@@ -163,7 +163,8 @@ bundle exec rake produce_messages
|
|
|
163
163
|
|
|
164
164
|
| rdkafka-ruby | librdkafka | patches |
|
|
165
165
|
|-|-|-|
|
|
166
|
-
| 0.
|
|
166
|
+
| 0.27.x (2026-05-07) | 2.14.0 (2026-04-01) | yes |
|
|
167
|
+
| 0.26.x (2026-03-30) | 2.13.2 (2026-03-02) | yes |
|
|
167
168
|
| 0.25.x (2026-01-21) | 2.12.1 (2025-10-21) | yes |
|
|
168
169
|
| 0.24.x (2025-10-10) | 2.11.1 (2025-08-18) | yes |
|
|
169
170
|
| 0.23.x (2025-09-04) | 2.11.0 (2025-07-03) | yes |
|
data/ext/librdkafka.so
CHANGED
|
Binary file
|
data/lib/rdkafka/admin.rb
CHANGED
|
@@ -777,6 +777,9 @@ module Rdkafka
|
|
|
777
777
|
|
|
778
778
|
raise
|
|
779
779
|
ensure
|
|
780
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
781
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
782
|
+
|
|
780
783
|
if configs_array_ptr
|
|
781
784
|
Rdkafka::Bindings.rd_kafka_ConfigResource_destroy_array(
|
|
782
785
|
configs_array_ptr,
|
|
@@ -865,6 +868,9 @@ module Rdkafka
|
|
|
865
868
|
|
|
866
869
|
raise
|
|
867
870
|
ensure
|
|
871
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
872
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
873
|
+
|
|
868
874
|
if configs_array_ptr
|
|
869
875
|
Rdkafka::Bindings.rd_kafka_ConfigResource_destroy_array(
|
|
870
876
|
configs_array_ptr,
|
data/lib/rdkafka/bindings.rb
CHANGED
|
@@ -234,6 +234,9 @@ module Rdkafka
|
|
|
234
234
|
|
|
235
235
|
attach_function :rd_kafka_conf_new, [], :pointer
|
|
236
236
|
attach_function :rd_kafka_conf_set, [:pointer, :string, :string, :pointer, :int], :kafka_config_response
|
|
237
|
+
attach_function :rd_kafka_conf_dump, [:pointer, :pointer], :pointer
|
|
238
|
+
attach_function :rd_kafka_conf_dump_free, [:pointer, :size_t], :void
|
|
239
|
+
attach_function :rd_kafka_conf_destroy, [:pointer], :void
|
|
237
240
|
callback :log_cb, [:pointer, :int, :string, :string], :void
|
|
238
241
|
attach_function :rd_kafka_conf_set_log_cb, [:pointer, :log_cb], :void
|
|
239
242
|
attach_function :rd_kafka_conf_set_opaque, [:pointer, :pointer], :void
|
|
@@ -383,6 +386,9 @@ module Rdkafka
|
|
|
383
386
|
# More efficient for poll(0) calls in fiber schedulers.
|
|
384
387
|
attach_function :rd_kafka_consumer_poll_nb, :rd_kafka_consumer_poll, [:pointer, :int], :pointer, blocking: false
|
|
385
388
|
attach_function :rd_kafka_consumer_close, [:pointer], :void, blocking: true
|
|
389
|
+
attach_function :rd_kafka_queue_get_consumer, [:pointer], :pointer
|
|
390
|
+
attach_function :rd_kafka_consume_batch_queue, [:pointer, :int, :pointer, :size_t], :ssize_t, blocking: true
|
|
391
|
+
attach_function :rd_kafka_consume_batch_queue_nb, :rd_kafka_consume_batch_queue, [:pointer, :int, :pointer, :size_t], :ssize_t, blocking: false
|
|
386
392
|
attach_function :rd_kafka_offsets_store, [:pointer, :pointer], :int, blocking: true
|
|
387
393
|
attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int, blocking: true
|
|
388
394
|
attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int, blocking: true
|
data/lib/rdkafka/config.rb
CHANGED
|
@@ -285,6 +285,46 @@ module Rdkafka
|
|
|
285
285
|
)
|
|
286
286
|
end
|
|
287
287
|
|
|
288
|
+
# Returns all configuration properties and their current values for this config.
|
|
289
|
+
#
|
|
290
|
+
# Uses `rd_kafka_conf_dump` to retrieve every property (including defaults and
|
|
291
|
+
# internal properties like `client.software.name`) as a flat Hash.
|
|
292
|
+
#
|
|
293
|
+
# @note The librdkafka C API does not distinguish between producer-only, consumer-only,
|
|
294
|
+
# and global properties at the configuration level. All properties are returned
|
|
295
|
+
# regardless of the intended client type.
|
|
296
|
+
#
|
|
297
|
+
# @note The returned Hash may include sensitive values such as authentication
|
|
298
|
+
# credentials and key passwords. Do not log or serialize the returned data
|
|
299
|
+
# unless you have explicitly redacted secret entries.
|
|
300
|
+
#
|
|
301
|
+
# @return [Hash{Symbol => String}] property names mapped to their current values
|
|
302
|
+
#
|
|
303
|
+
# @raise [ConfigError] When the configuration contains invalid options
|
|
304
|
+
def describe_properties
|
|
305
|
+
config = nil
|
|
306
|
+
dump_ptr = nil
|
|
307
|
+
count = 0
|
|
308
|
+
|
|
309
|
+
config = native_config
|
|
310
|
+
count_ptr = Rdkafka::Bindings::SizePtr.new
|
|
311
|
+
dump_ptr = Rdkafka::Bindings.rd_kafka_conf_dump(config, count_ptr)
|
|
312
|
+
|
|
313
|
+
count = count_ptr[:value]
|
|
314
|
+
result = {}
|
|
315
|
+
|
|
316
|
+
(0...count).step(2) do |i|
|
|
317
|
+
key = dump_ptr.get_pointer(i * FFI::Pointer.size).read_string
|
|
318
|
+
value = dump_ptr.get_pointer((i + 1) * FFI::Pointer.size).read_string
|
|
319
|
+
result[key.to_sym] = value
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
result
|
|
323
|
+
ensure
|
|
324
|
+
Rdkafka::Bindings.rd_kafka_conf_dump_free(dump_ptr, count) if dump_ptr
|
|
325
|
+
Rdkafka::Bindings.rd_kafka_conf_destroy(config) if config
|
|
326
|
+
end
|
|
327
|
+
|
|
288
328
|
# Error that is returned by the underlying rdkafka error if an invalid configuration option is present.
|
|
289
329
|
class ConfigError < RuntimeError; end
|
|
290
330
|
|
|
@@ -364,10 +404,9 @@ module Rdkafka
|
|
|
364
404
|
end
|
|
365
405
|
|
|
366
406
|
# Redirect log to handle's queue
|
|
367
|
-
Rdkafka::Bindings.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
)
|
|
407
|
+
main_queue = Rdkafka::Bindings.rd_kafka_queue_get_main(handle)
|
|
408
|
+
Rdkafka::Bindings.rd_kafka_set_log_queue(handle, main_queue)
|
|
409
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(main_queue)
|
|
371
410
|
|
|
372
411
|
# Return handle which should be closed using rd_kafka_destroy after usage.
|
|
373
412
|
handle
|
data/lib/rdkafka/consumer.rb
CHANGED
|
@@ -183,6 +183,11 @@ module Rdkafka
|
|
|
183
183
|
|
|
184
184
|
@native_kafka.synchronize do |inner|
|
|
185
185
|
Rdkafka::Bindings.rd_kafka_consumer_close(inner)
|
|
186
|
+
|
|
187
|
+
if @consumer_queue
|
|
188
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(@consumer_queue)
|
|
189
|
+
@consumer_queue = nil
|
|
190
|
+
end
|
|
186
191
|
end
|
|
187
192
|
|
|
188
193
|
@native_kafka.close
|
|
@@ -434,6 +439,8 @@ module Rdkafka
|
|
|
434
439
|
end
|
|
435
440
|
|
|
436
441
|
TopicPartitionList.from_native_tpl(tpl)
|
|
442
|
+
ensure
|
|
443
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl) if tpl
|
|
437
444
|
end
|
|
438
445
|
|
|
439
446
|
# Query broker for low (oldest/beginning) and high (newest/end) offsets for a partition.
|
|
@@ -779,6 +786,130 @@ module Rdkafka
|
|
|
779
786
|
end
|
|
780
787
|
end
|
|
781
788
|
|
|
789
|
+
# Poll for a batch of messages from the consumer queue in a single FFI call.
|
|
790
|
+
#
|
|
791
|
+
# This is more efficient than calling {#poll} in a loop because it crosses the FFI
|
|
792
|
+
# boundary only once to fetch up to `max_items` messages.
|
|
793
|
+
#
|
|
794
|
+
# The timeout controls how long to wait for the **first** message. Once any message
|
|
795
|
+
# is available, librdkafka fills the buffer with whatever is immediately ready and
|
|
796
|
+
# returns without further waiting.
|
|
797
|
+
#
|
|
798
|
+
# @param timeout_ms [Integer] Timeout waiting for the first message (-1 for infinite)
|
|
799
|
+
# @param max_items [Integer] Maximum number of messages to return per call
|
|
800
|
+
# @return [Array<Message>] Array of messages (empty if none available within timeout)
|
|
801
|
+
# @raise [RdkafkaError] When a consumed message contains an error
|
|
802
|
+
# @raise [ClosedConsumerError] When called on a closed consumer
|
|
803
|
+
def poll_batch(timeout_ms, max_items: 100)
|
|
804
|
+
closed_consumer_check(__method__)
|
|
805
|
+
|
|
806
|
+
buffer = batch_buffer(max_items)
|
|
807
|
+
messages = []
|
|
808
|
+
|
|
809
|
+
count = @native_kafka.with_inner do |_inner|
|
|
810
|
+
Rdkafka::Bindings.rd_kafka_consume_batch_queue(
|
|
811
|
+
consumer_queue,
|
|
812
|
+
timeout_ms,
|
|
813
|
+
buffer,
|
|
814
|
+
max_items
|
|
815
|
+
)
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
return messages if count <= 0
|
|
819
|
+
|
|
820
|
+
i = 0
|
|
821
|
+
begin
|
|
822
|
+
while i < count
|
|
823
|
+
ptr = buffer.get_pointer(i * FFI::Pointer.size)
|
|
824
|
+
|
|
825
|
+
if ptr.null?
|
|
826
|
+
i += 1
|
|
827
|
+
next
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
native_message = Rdkafka::Bindings::Message.new(ptr)
|
|
831
|
+
|
|
832
|
+
if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
|
833
|
+
raise Rdkafka::RdkafkaError.new(native_message[:err])
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
messages << Rdkafka::Consumer::Message.new(native_message)
|
|
837
|
+
Rdkafka::Bindings.rd_kafka_message_destroy(ptr)
|
|
838
|
+
i += 1
|
|
839
|
+
end
|
|
840
|
+
ensure
|
|
841
|
+
while i < count
|
|
842
|
+
ptr = buffer.get_pointer(i * FFI::Pointer.size)
|
|
843
|
+
Rdkafka::Bindings.rd_kafka_message_destroy(ptr) unless ptr.null?
|
|
844
|
+
i += 1
|
|
845
|
+
end
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
messages
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
# Poll for a batch of messages without releasing the GVL (Global VM Lock).
|
|
852
|
+
#
|
|
853
|
+
# This is more efficient than {#poll_batch} for non-blocking poll(0) calls,
|
|
854
|
+
# particularly useful in fiber scheduler contexts where GVL release/reacquire
|
|
855
|
+
# overhead is wasteful since we don't expect to wait.
|
|
856
|
+
#
|
|
857
|
+
# @note Since the GVL is not released, a non-zero timeout_ms will block all Ruby
|
|
858
|
+
# threads/fibers for the duration. Use {#poll_batch} if you need a blocking wait.
|
|
859
|
+
#
|
|
860
|
+
# @param timeout_ms [Integer] Timeout waiting for the first message (default: 0 for non-blocking)
|
|
861
|
+
# @param max_items [Integer] Maximum number of messages to return per call
|
|
862
|
+
# @return [Array<Message>] Array of messages (empty if none available within timeout)
|
|
863
|
+
# @raise [RdkafkaError] When a consumed message contains an error
|
|
864
|
+
# @raise [ClosedConsumerError] When called on a closed consumer
|
|
865
|
+
def poll_batch_nb(timeout_ms = 0, max_items: 100)
|
|
866
|
+
closed_consumer_check(__method__)
|
|
867
|
+
|
|
868
|
+
buffer = batch_buffer(max_items)
|
|
869
|
+
messages = []
|
|
870
|
+
|
|
871
|
+
count = @native_kafka.with_inner do |_inner|
|
|
872
|
+
Rdkafka::Bindings.rd_kafka_consume_batch_queue_nb(
|
|
873
|
+
consumer_queue,
|
|
874
|
+
timeout_ms,
|
|
875
|
+
buffer,
|
|
876
|
+
max_items
|
|
877
|
+
)
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
return messages if count <= 0
|
|
881
|
+
|
|
882
|
+
i = 0
|
|
883
|
+
begin
|
|
884
|
+
while i < count
|
|
885
|
+
ptr = buffer.get_pointer(i * FFI::Pointer.size)
|
|
886
|
+
|
|
887
|
+
if ptr.null?
|
|
888
|
+
i += 1
|
|
889
|
+
next
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
native_message = Rdkafka::Bindings::Message.new(ptr)
|
|
893
|
+
|
|
894
|
+
if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
|
895
|
+
raise Rdkafka::RdkafkaError.new(native_message[:err])
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
messages << Rdkafka::Consumer::Message.new(native_message)
|
|
899
|
+
Rdkafka::Bindings.rd_kafka_message_destroy(ptr)
|
|
900
|
+
i += 1
|
|
901
|
+
end
|
|
902
|
+
ensure
|
|
903
|
+
while i < count
|
|
904
|
+
ptr = buffer.get_pointer(i * FFI::Pointer.size)
|
|
905
|
+
Rdkafka::Bindings.rd_kafka_message_destroy(ptr) unless ptr.null?
|
|
906
|
+
i += 1
|
|
907
|
+
end
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
messages
|
|
911
|
+
end
|
|
912
|
+
|
|
782
913
|
# Poll for new messages and yield for each received one. Iteration
|
|
783
914
|
# will end when the consumer is closed.
|
|
784
915
|
#
|
|
@@ -851,5 +982,24 @@ module Rdkafka
|
|
|
851
982
|
def closed_consumer_check(method)
|
|
852
983
|
raise Rdkafka::ClosedConsumerError.new(method) if closed?
|
|
853
984
|
end
|
|
985
|
+
|
|
986
|
+
# Returns the consumer queue pointer, lazily initialized
|
|
987
|
+
# @return [FFI::Pointer] consumer queue handle
|
|
988
|
+
def consumer_queue
|
|
989
|
+
@consumer_queue ||= @native_kafka.with_inner do |inner|
|
|
990
|
+
Rdkafka::Bindings.rd_kafka_queue_get_consumer(inner)
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
# Returns a reusable FFI buffer for batch polling, growing if needed
|
|
995
|
+
# @param max_items [Integer] minimum buffer capacity
|
|
996
|
+
# @return [FFI::MemoryPointer] pointer buffer
|
|
997
|
+
def batch_buffer(max_items)
|
|
998
|
+
if @batch_buffer.nil? || @batch_buffer_size < max_items
|
|
999
|
+
@batch_buffer = FFI::MemoryPointer.new(:pointer, max_items)
|
|
1000
|
+
@batch_buffer_size = max_items
|
|
1001
|
+
end
|
|
1002
|
+
@batch_buffer
|
|
1003
|
+
end
|
|
854
1004
|
end
|
|
855
1005
|
end
|
data/lib/rdkafka/version.rb
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Rdkafka
|
|
4
4
|
# Current rdkafka-ruby gem version
|
|
5
|
-
VERSION = "0.
|
|
5
|
+
VERSION = "0.27.0"
|
|
6
6
|
# Target librdkafka version to be used
|
|
7
|
-
LIBRDKAFKA_VERSION = "2.
|
|
7
|
+
LIBRDKAFKA_VERSION = "2.14.0"
|
|
8
8
|
# SHA256 hash of the librdkafka source tarball for verification
|
|
9
|
-
LIBRDKAFKA_SOURCE_SHA256 = "
|
|
9
|
+
LIBRDKAFKA_SOURCE_SHA256 = "c05c03ef00a13a8463fac3e8918c04843c416f11ced58c889d806a88ca92cf99"
|
|
10
10
|
end
|
data/renovate.json
CHANGED