karafka-rdkafka 0.26.1-aarch64-linux-gnu → 0.27.1-aarch64-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a435733d9fee98c645fb787d72bf367708827b890d00858c247fb1f56e3b9a7e
4
- data.tar.gz: a297c932f096bb9b86f756eed38cd57872857b3964d9fb35ea531c80cb076a9f
3
+ metadata.gz: 12b06b0bf242efee035b255f8242474a3c6a77f04264e7662cd99fdd6dcc3e72
4
+ data.tar.gz: 1a790bba85c674d104ede2e279fb606226f344efdedb432cdf2fde5525fc898d
5
5
  SHA512:
6
- metadata.gz: 6119ccf54d991f536f73d95aecb0c96849f724500696ba30657f7338c6a39705cc1c5bedfa6a7b2fd692fd2dec0aa0c3910d13917d82152c43bf75895bd91424
7
- data.tar.gz: c73a1eb6a70d059927ae6fdbf1a35f7f3c2a3be719d8301b7f0e15ea39e9185cead70cb966b5cea742953103c7861c0c66ce3949aa2c9b91d03fa22c519fa5e2
6
+ metadata.gz: accf33ab4a8f651e291b0ca336be8984fa04acac6b6c2c90b71784baac70f0253da67a8a859e299a5266b7d75a044d42843ab546304a387e42f75d3cd9f12a1d
7
+ data.tar.gz: 3e2d6560d7829a1ca4c5654389709ec94e721cf694b693a4ae4f4dd2200931c5f8f5005446ceeb74dc519ce98ed8a9c8beb3087806d4ecdf2fbf8cd35070915f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Rdkafka Changelog
2
2
 
3
+ ## 0.27.1 (2026-05-14)
4
+ - [Fix] `poll_nb`, `poll_nb_each`, `poll_batch`, and `poll_batch_nb` now raise `RdkafkaError` with `details` populated (`{topic:, partition:, offset:}`) when a message contains an error (e.g. `:partition_eof`). Previously these methods raised via `RdkafkaError.new(code)`, discarding the native message struct context. They now use `RdkafkaError.validate!(native_message, client_ptr: inner)`, consistent with `poll`.
5
+
6
+ ## 0.27.0 (2026-05-08)
7
+ - [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` (from upstream).
8
+ - [Enhancement] Bump librdkafka to `2.14.1`.
9
+ - [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 (from upstream).
10
+ - [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` (from upstream).
11
+ - [Fix] Fix native topic partition list leak in `Consumer#position` where `tpl` was never destroyed (from upstream).
12
+
3
13
  ## 0.26.1 (2026-04-13)
4
14
  - [Feature] Add `Config#describe_properties` to dump all librdkafka configuration properties (including defaults and hidden properties) as a Hash via `rd_kafka_conf_dump` (from upstream).
5
15
 
data/README.md CHANGED
@@ -63,8 +63,9 @@ Contributions should generally be made to the upstream [rdkafka-ruby repository]
63
63
 
64
64
  | rdkafka-ruby | librdkafka | patches |
65
65
  |-|-|-|
66
+ | 0.27.x (2026-05-08) | 2.14.1 (2026-04-15) | yes |
66
67
  | 0.26.x (2026-04-11) | 2.14.0 (2026-04-01) | yes |
67
- | 0.25.x (2026-04-02) | 2.13.2 (2026-03-30) | yes |
68
+ | 0.25.x (2026-04-02) | 2.13.2 (2026-03-02) | yes |
68
69
  | 0.24.x (2026-02-25) | 2.13.0 (2026-01-05) | yes |
69
70
  | 0.23.x (2025-11-01) | 2.12.1 (2025-10-16) | yes |
70
71
  | 0.22.x (2025-09-26) | 2.11.1 (2025-08-18) | 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,
@@ -435,6 +435,9 @@ module Rdkafka
435
435
  # More efficient for poll(0) calls in fiber schedulers.
436
436
  attach_function :rd_kafka_consumer_poll_nb, :rd_kafka_consumer_poll, [:pointer, :int], :pointer, blocking: false
437
437
  attach_function :rd_kafka_consumer_close, [:pointer], :void, blocking: true
438
+ attach_function :rd_kafka_queue_get_consumer, [:pointer], :pointer
439
+ attach_function :rd_kafka_consume_batch_queue, [:pointer, :int, :pointer, :size_t], :ssize_t, blocking: true
440
+ attach_function :rd_kafka_consume_batch_queue_nb, :rd_kafka_consume_batch_queue, [:pointer, :int, :pointer, :size_t], :ssize_t, blocking: false
438
441
  attach_function :rd_kafka_offsets_store, [:pointer, :pointer], :int, blocking: true
439
442
  attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int, blocking: true
440
443
  attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int, blocking: true
@@ -404,10 +404,9 @@ module Rdkafka
404
404
  end
405
405
 
406
406
  # Redirect log to handle's queue
407
- Rdkafka::Bindings.rd_kafka_set_log_queue(
408
- handle,
409
- Rdkafka::Bindings.rd_kafka_queue_get_main(handle)
410
- )
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)
411
410
 
412
411
  # Return handle which should be closed using rd_kafka_destroy after usage.
413
412
  handle
@@ -163,7 +163,7 @@ module Rdkafka
163
163
  native_message = Rdkafka::Bindings::Message.new(message_ptr)
164
164
 
165
165
  if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
166
- raise Rdkafka::RdkafkaError.new(native_message[:err])
166
+ Rdkafka::RdkafkaError.validate!(native_message, client_ptr: inner)
167
167
  end
168
168
 
169
169
  result = yield Consumer::Message.new(native_message)
@@ -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
@@ -421,6 +426,8 @@ module Rdkafka
421
426
  end
422
427
 
423
428
  TopicPartitionList.from_native_tpl(tpl)
429
+ ensure
430
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl) if tpl
424
431
  end
425
432
 
426
433
  # Query broker for low (oldest/beginning) and high (newest/end) offsets for a partition.
@@ -729,7 +736,9 @@ module Rdkafka
729
736
  native_message = Rdkafka::Bindings::Message.new(message_ptr)
730
737
  # Raise error if needed
731
738
  if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
732
- raise Rdkafka::RdkafkaError.new(native_message[:err])
739
+ @native_kafka.with_inner do |inner|
740
+ Rdkafka::RdkafkaError.validate!(native_message, client_ptr: inner)
741
+ end
733
742
  end
734
743
  # Create a message to pass out
735
744
  Rdkafka::Consumer::Message.new(native_message)
@@ -783,6 +792,134 @@ module Rdkafka
783
792
  end
784
793
  end
785
794
 
795
+ # Poll for a batch of messages from the consumer queue in a single FFI call.
796
+ #
797
+ # This is more efficient than calling {#poll} in a loop because it crosses the FFI
798
+ # boundary only once to fetch up to `max_items` messages.
799
+ #
800
+ # The timeout controls how long to wait for the **first** message. Once any message
801
+ # is available, librdkafka fills the buffer with whatever is immediately ready and
802
+ # returns without further waiting.
803
+ #
804
+ # @param timeout_ms [Integer] Timeout waiting for the first message (-1 for infinite)
805
+ # @param max_items [Integer] Maximum number of messages to return per call
806
+ # @return [Array<Message>] Array of messages (empty if none available within timeout)
807
+ # @raise [RdkafkaError] When a consumed message contains an error
808
+ # @raise [ClosedConsumerError] When called on a closed consumer
809
+ def poll_batch(timeout_ms, max_items: 100)
810
+ closed_consumer_check(__method__)
811
+
812
+ buffer = batch_buffer(max_items)
813
+ messages = []
814
+
815
+ count = @native_kafka.with_inner do |_inner|
816
+ Rdkafka::Bindings.rd_kafka_consume_batch_queue(
817
+ consumer_queue,
818
+ timeout_ms,
819
+ buffer,
820
+ max_items
821
+ )
822
+ end
823
+
824
+ return messages if count <= 0
825
+
826
+ i = 0
827
+ begin
828
+ while i < count
829
+ ptr = buffer.get_pointer(i * FFI::Pointer.size)
830
+
831
+ if ptr.null?
832
+ i += 1
833
+ next
834
+ end
835
+
836
+ native_message = Rdkafka::Bindings::Message.new(ptr)
837
+
838
+ if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
839
+ @native_kafka.with_inner do |inner|
840
+ Rdkafka::RdkafkaError.validate!(native_message, client_ptr: inner)
841
+ end
842
+ end
843
+
844
+ messages << Rdkafka::Consumer::Message.new(native_message)
845
+ Rdkafka::Bindings.rd_kafka_message_destroy(ptr)
846
+ i += 1
847
+ end
848
+ ensure
849
+ while i < count
850
+ ptr = buffer.get_pointer(i * FFI::Pointer.size)
851
+ Rdkafka::Bindings.rd_kafka_message_destroy(ptr) unless ptr.null?
852
+ i += 1
853
+ end
854
+ end
855
+
856
+ messages
857
+ end
858
+
859
+ # Poll for a batch of messages without releasing the GVL (Global VM Lock).
860
+ #
861
+ # This is more efficient than {#poll_batch} for non-blocking poll(0) calls,
862
+ # particularly useful in fiber scheduler contexts where GVL release/reacquire
863
+ # overhead is wasteful since we don't expect to wait.
864
+ #
865
+ # @note Since the GVL is not released, a non-zero timeout_ms will block all Ruby
866
+ # threads/fibers for the duration. Use {#poll_batch} if you need a blocking wait.
867
+ #
868
+ # @param timeout_ms [Integer] Timeout waiting for the first message (default: 0 for non-blocking)
869
+ # @param max_items [Integer] Maximum number of messages to return per call
870
+ # @return [Array<Message>] Array of messages (empty if none available within timeout)
871
+ # @raise [RdkafkaError] When a consumed message contains an error
872
+ # @raise [ClosedConsumerError] When called on a closed consumer
873
+ def poll_batch_nb(timeout_ms = 0, max_items: 100)
874
+ closed_consumer_check(__method__)
875
+
876
+ buffer = batch_buffer(max_items)
877
+ messages = []
878
+
879
+ count = @native_kafka.with_inner do |_inner|
880
+ Rdkafka::Bindings.rd_kafka_consume_batch_queue_nb(
881
+ consumer_queue,
882
+ timeout_ms,
883
+ buffer,
884
+ max_items
885
+ )
886
+ end
887
+
888
+ return messages if count <= 0
889
+
890
+ i = 0
891
+ begin
892
+ while i < count
893
+ ptr = buffer.get_pointer(i * FFI::Pointer.size)
894
+
895
+ if ptr.null?
896
+ i += 1
897
+ next
898
+ end
899
+
900
+ native_message = Rdkafka::Bindings::Message.new(ptr)
901
+
902
+ if native_message[:err] != Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
903
+ @native_kafka.with_inner do |inner|
904
+ Rdkafka::RdkafkaError.validate!(native_message, client_ptr: inner)
905
+ end
906
+ end
907
+
908
+ messages << Rdkafka::Consumer::Message.new(native_message)
909
+ Rdkafka::Bindings.rd_kafka_message_destroy(ptr)
910
+ i += 1
911
+ end
912
+ ensure
913
+ while i < count
914
+ ptr = buffer.get_pointer(i * FFI::Pointer.size)
915
+ Rdkafka::Bindings.rd_kafka_message_destroy(ptr) unless ptr.null?
916
+ i += 1
917
+ end
918
+ end
919
+
920
+ messages
921
+ end
922
+
786
923
  # Poll for new messages and yield for each received one. Iteration
787
924
  # will end when the consumer is closed.
788
925
  #
@@ -855,5 +992,24 @@ module Rdkafka
855
992
  def closed_consumer_check(method)
856
993
  raise Rdkafka::ClosedConsumerError.new(method) if closed?
857
994
  end
995
+
996
+ # Returns the consumer queue pointer, lazily initialized
997
+ # @return [FFI::Pointer] consumer queue handle
998
+ def consumer_queue
999
+ @consumer_queue ||= @native_kafka.with_inner do |inner|
1000
+ Rdkafka::Bindings.rd_kafka_queue_get_consumer(inner)
1001
+ end
1002
+ end
1003
+
1004
+ # Returns a reusable FFI buffer for batch polling, growing if needed
1005
+ # @param max_items [Integer] minimum buffer capacity
1006
+ # @return [FFI::MemoryPointer] pointer buffer
1007
+ def batch_buffer(max_items)
1008
+ if @batch_buffer.nil? || @batch_buffer_size < max_items
1009
+ @batch_buffer = FFI::MemoryPointer.new(:pointer, max_items)
1010
+ @batch_buffer_size = max_items
1011
+ end
1012
+ @batch_buffer
1013
+ end
858
1014
  end
859
1015
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Rdkafka
4
4
  # Current rdkafka-ruby gem version
5
- VERSION = "0.26.1"
5
+ VERSION = "0.27.1"
6
6
  # Target librdkafka version to be used
7
- LIBRDKAFKA_VERSION = "2.14.0"
7
+ LIBRDKAFKA_VERSION = "2.14.1"
8
8
  # SHA256 hash of the librdkafka source tarball for verification
9
- LIBRDKAFKA_SOURCE_SHA256 = "c05c03ef00a13a8463fac3e8918c04843c416f11ced58c889d806a88ca92cf99"
9
+ LIBRDKAFKA_SOURCE_SHA256 = "bb246e754dee3560e9b42bf4e844dc05de4b146a3cae937e36301ffacdc456e7"
10
10
  end
data/renovate.json CHANGED
@@ -90,5 +90,8 @@
90
90
  ],
91
91
  "labels": [
92
92
  "dependencies"
93
- ]
93
+ ],
94
+ "lockFileMaintenance": {
95
+ "enabled": true
96
+ }
94
97
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka-rdkafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.1
4
+ version: 0.27.1
5
5
  platform: aarch64-linux-gnu
6
6
  authors:
7
7
  - Thijs Cadier