karafka-rdkafka 0.14.2 → 0.14.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88083ab7dfa50e2dc5b29ea72d2d846f1e2db77871b86e76057b9b49cbf0440a
4
- data.tar.gz: 39f2b241c4786caa4829f73270446adcd9ef744e84c583dfbefaa09b0dc669eb
3
+ metadata.gz: d22e33d93f77f138063f03111b25386c08e1667012b6ab4c8449fef61754ad44
4
+ data.tar.gz: b8cc0557cbb945e5d7b7e025198a292a7cf601ce9decef97cb5102fd25af742b
5
5
  SHA512:
6
- metadata.gz: 83165b051816f6145eb89f20481ae15eb849aff39d69431c2382b00a101b58117a558e13ac5065970868a1e4d64ac829787b02a7918fc12b6f77f01e82c8f19c
7
- data.tar.gz: 5546e37c51c0da66d3226805534f16e8f6211f4dc748869f41afa8abcbf0c09e367ef9279c838aee71684606eaebca2347b7f20c763a5116d2143b762eedfbc9
6
+ metadata.gz: cfc9af0e70030f513c4c34b00f9b94b6b3b9c828add2ac6cd742ebe2eb308a1e1a5489bf4c4280c34a98d2f0118d741608918314fa8f267b7cf98b22b3d8782d
7
+ data.tar.gz: 315b552a77691b62e5a30fd5eaec1bf89efd8ec5789f9f0deeadf3997eeca9dc83bb6466ee8365e40e53d2e09707d3d68a57278b3637b170ad027b5080838519
checksums.yaml.gz.sig CHANGED
Binary file
@@ -22,7 +22,7 @@ jobs:
22
22
  fail-fast: false
23
23
  matrix:
24
24
  ruby:
25
- - '3.3.0-preview2'
25
+ - '3.3.0-rc1'
26
26
  - '3.2'
27
27
  - '3.1'
28
28
  - '3.1.0'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Rdkafka Changelog
2
2
 
3
+ ## 0.14.4 (2023-12-19)
4
+ - [Enhancement] Add ability to store offsets in a transaction (mensfeld)
5
+
6
+ ## 0.14.3 (2023-12-17)
7
+ - [Enhancement] Replace `rd_kafka_offset_store` with `rd_kafka_offsets_store` (mensfeld)
8
+ - [Fix] Missing ACL `RD_KAFKA_RESOURCE_BROKER` constant reference (mensfeld)
9
+ - [Change] Rename `matching_acl_pattern_type` to `matching_acl_resource_pattern_type` to align the whole API (mensfeld)
10
+
3
11
  ## 0.14.2 (2023-12-11)
4
12
  - [Enhancement] Alias `topic_name` as `topic` in the delivery report (mensfeld)
5
13
  - [Fix] Fix return type on `#rd_kafka_poll` (mensfeld)
@@ -2,36 +2,50 @@
2
2
 
3
3
  module Rdkafka
4
4
  class Admin
5
-
6
5
  # Extracts attributes of rd_kafka_AclBinding_t
7
6
  #
8
7
  class AclBindingResult
9
- attr_reader :result_error, :error_string, :matching_acl_resource_type, :matching_acl_resource_name, :matching_acl_pattern_type, :matching_acl_principal, :matching_acl_host, :matching_acl_operation, :matching_acl_permission_type
8
+ attr_reader :result_error, :error_string, :matching_acl_resource_type,
9
+ :matching_acl_resource_name, :matching_acl_resource_pattern_type,
10
+ :matching_acl_principal, :matching_acl_host, :matching_acl_operation,
11
+ :matching_acl_permission_type
12
+
13
+ # This attribute was initially released under the name that is now an alias
14
+ # We keep it for backwards compatibility but it was changed for the consistency
15
+ alias matching_acl_pattern_type matching_acl_resource_pattern_type
10
16
 
11
17
  def initialize(matching_acl)
12
- rd_kafka_error_pointer = Rdkafka::Bindings.rd_kafka_AclBinding_error(matching_acl)
13
- @result_error = Rdkafka::Bindings.rd_kafka_error_code(rd_kafka_error_pointer)
14
- error_string = Rdkafka::Bindings.rd_kafka_error_string(rd_kafka_error_pointer)
15
- if error_string != FFI::Pointer::NULL
16
- @error_string = error_string.read_string
17
- end
18
- @matching_acl_resource_type = Rdkafka::Bindings.rd_kafka_AclBinding_restype(matching_acl)
19
- matching_acl_resource_name = Rdkafka::Bindings.rd_kafka_AclBinding_name(matching_acl)
20
- if matching_acl_resource_name != FFI::Pointer::NULL
21
- @matching_acl_resource_name = matching_acl_resource_name.read_string
22
- end
23
- @matching_acl_pattern_type = Rdkafka::Bindings.rd_kafka_AclBinding_resource_pattern_type(matching_acl)
24
- matching_acl_principal = Rdkafka::Bindings.rd_kafka_AclBinding_principal(matching_acl)
25
- if matching_acl_principal != FFI::Pointer::NULL
26
- @matching_acl_principal = matching_acl_principal.read_string
27
- end
28
- matching_acl_host = Rdkafka::Bindings.rd_kafka_AclBinding_host(matching_acl)
29
- if matching_acl_host != FFI::Pointer::NULL
30
- @matching_acl_host = matching_acl_host.read_string
31
- end
32
- @matching_acl_operation = Rdkafka::Bindings.rd_kafka_AclBinding_operation(matching_acl)
33
- @matching_acl_permission_type = Rdkafka::Bindings.rd_kafka_AclBinding_permission_type(matching_acl)
18
+ rd_kafka_error_pointer = Rdkafka::Bindings.rd_kafka_AclBinding_error(matching_acl)
19
+ @result_error = Rdkafka::Bindings.rd_kafka_error_code(rd_kafka_error_pointer)
20
+ error_string = Rdkafka::Bindings.rd_kafka_error_string(rd_kafka_error_pointer)
21
+
22
+ if error_string != FFI::Pointer::NULL
23
+ @error_string = error_string.read_string
34
24
  end
25
+
26
+ @matching_acl_resource_type = Rdkafka::Bindings.rd_kafka_AclBinding_restype(matching_acl)
27
+ matching_acl_resource_name = Rdkafka::Bindings.rd_kafka_AclBinding_name(matching_acl)
28
+
29
+ if matching_acl_resource_name != FFI::Pointer::NULL
30
+ @matching_acl_resource_name = matching_acl_resource_name.read_string
31
+ end
32
+
33
+ @matching_acl_resource_pattern_type = Rdkafka::Bindings.rd_kafka_AclBinding_resource_pattern_type(matching_acl)
34
+ matching_acl_principal = Rdkafka::Bindings.rd_kafka_AclBinding_principal(matching_acl)
35
+
36
+ if matching_acl_principal != FFI::Pointer::NULL
37
+ @matching_acl_principal = matching_acl_principal.read_string
38
+ end
39
+
40
+ matching_acl_host = Rdkafka::Bindings.rd_kafka_AclBinding_host(matching_acl)
41
+
42
+ if matching_acl_host != FFI::Pointer::NULL
43
+ @matching_acl_host = matching_acl_host.read_string
44
+ end
45
+
46
+ @matching_acl_operation = Rdkafka::Bindings.rd_kafka_AclBinding_operation(matching_acl)
47
+ @matching_acl_permission_type = Rdkafka::Bindings.rd_kafka_AclBinding_permission_type(matching_acl)
35
48
  end
49
+ end
36
50
  end
37
51
  end
@@ -199,12 +199,15 @@ module Rdkafka
199
199
  attach_function :rd_kafka_poll_set_consumer, [:pointer], :void, blocking: true
200
200
  attach_function :rd_kafka_consumer_poll, [:pointer, :int], :pointer, blocking: true
201
201
  attach_function :rd_kafka_consumer_close, [:pointer], :void, blocking: true
202
- attach_function :rd_kafka_offset_store, [:pointer, :int32, :int64], :int, blocking: true
202
+ attach_function :rd_kafka_offsets_store, [:pointer, :pointer], :int, blocking: true
203
203
  attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int, blocking: true
204
204
  attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int, blocking: true
205
205
  attach_function :rd_kafka_seek, [:pointer, :int32, :int64, :int], :int, blocking: true
206
206
  attach_function :rd_kafka_offsets_for_times, [:pointer, :pointer, :int], :int, blocking: true
207
207
  attach_function :rd_kafka_position, [:pointer, :pointer], :int, blocking: true
208
+ # those two are used for eos support
209
+ attach_function :rd_kafka_consumer_group_metadata, [:pointer], :pointer, blocking: true
210
+ attach_function :rd_kafka_consumer_group_metadata_destroy, [:pointer], :void, blocking: true
208
211
 
209
212
  # Headers
210
213
  attach_function :rd_kafka_header_get_all, [:pointer, :size_t, :pointer, :pointer, SizePtr], :int
@@ -276,6 +279,7 @@ module Rdkafka
276
279
  callback :delivery_cb, [:pointer, :pointer, :pointer], :void
277
280
  attach_function :rd_kafka_conf_set_dr_msg_cb, [:pointer, :delivery_cb], :void
278
281
  attach_function :rd_kafka_init_transactions, [:pointer, :int], :pointer, blocking: true
282
+ attach_function :rd_kafka_send_offsets_to_transaction, [:pointer, :pointer, :pointer, :int], :pointer, blocking: true
279
283
  attach_function :rd_kafka_begin_transaction, [:pointer], :pointer, blocking: true
280
284
  attach_function :rd_kafka_abort_transaction, [:pointer, :int], :pointer, blocking: true
281
285
  attach_function :rd_kafka_commit_transaction, [:pointer, :int], :pointer, blocking: true
@@ -412,6 +416,7 @@ module Rdkafka
412
416
  RD_KAFKA_RESOURCE_ANY = 1
413
417
  RD_KAFKA_RESOURCE_TOPIC = 2
414
418
  RD_KAFKA_RESOURCE_GROUP = 3
419
+ RD_KAFKA_RESOURCE_BROKER = 4
415
420
 
416
421
  # rd_kafka_ResourcePatternType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
417
422
 
@@ -388,28 +388,26 @@ module Rdkafka
388
388
  def store_offset(message)
389
389
  closed_consumer_check(__method__)
390
390
 
391
- # rd_kafka_offset_store is one of the few calls that does not support
392
- # a string as the topic, so create a native topic for it.
393
- native_topic = @native_kafka.with_inner do |inner|
394
- Rdkafka::Bindings.rd_kafka_topic_new(
391
+ list = TopicPartitionList.new
392
+ list.add_topic_and_partitions_with_offsets(
393
+ message.topic,
394
+ message.partition => message.offset + 1
395
+ )
396
+
397
+ tpl = list.to_native_tpl
398
+
399
+ response = @native_kafka.with_inner do |inner|
400
+ Rdkafka::Bindings.rd_kafka_offsets_store(
395
401
  inner,
396
- message.topic,
397
- nil
402
+ tpl
398
403
  )
399
404
  end
400
- response = Rdkafka::Bindings.rd_kafka_offset_store(
401
- native_topic,
402
- message.partition,
403
- message.offset
404
- )
405
405
 
406
406
  Rdkafka::RdkafkaError.validate!(response)
407
407
 
408
408
  nil
409
409
  ensure
410
- if native_topic && !native_topic.null?
411
- Rdkafka::Bindings.rd_kafka_topic_destroy(native_topic)
412
- end
410
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl) if tpl
413
411
  end
414
412
 
415
413
  # Seek to a particular message. The next poll on the topic/partition will return the
@@ -673,6 +671,22 @@ module Rdkafka
673
671
  end
674
672
  end
675
673
 
674
+ # Returns pointer to the consumer group metadata. It is used only in the context of
675
+ # exactly-once-semantics in transactions, this is why it is never remapped to Ruby
676
+ #
677
+ # This API is **not** usable by itself from Ruby
678
+ #
679
+ # @note This pointer **needs** to be removed with `#rd_kafka_consumer_group_metadata_destroy`
680
+ #
681
+ # @private
682
+ def consumer_group_metadata_pointer
683
+ closed_consumer_check(__method__)
684
+
685
+ @native_kafka.with_inner do |inner|
686
+ Bindings.rd_kafka_consumer_group_metadata(inner)
687
+ end
688
+ end
689
+
676
690
  private
677
691
 
678
692
  def closed_consumer_check(method)
@@ -81,7 +81,7 @@ module Rdkafka
81
81
  @native_kafka.with_inner do |inner|
82
82
  response_ptr = Rdkafka::Bindings.rd_kafka_begin_transaction(inner)
83
83
 
84
- Rdkafka::RdkafkaError.validate!(response_ptr)
84
+ Rdkafka::RdkafkaError.validate!(response_ptr) || true
85
85
  end
86
86
  end
87
87
 
@@ -91,7 +91,7 @@ module Rdkafka
91
91
  @native_kafka.with_inner do |inner|
92
92
  response_ptr = Rdkafka::Bindings.rd_kafka_commit_transaction(inner, timeout_ms)
93
93
 
94
- Rdkafka::RdkafkaError.validate!(response_ptr)
94
+ Rdkafka::RdkafkaError.validate!(response_ptr) || true
95
95
  end
96
96
  end
97
97
 
@@ -100,8 +100,35 @@ module Rdkafka
100
100
 
101
101
  @native_kafka.with_inner do |inner|
102
102
  response_ptr = Rdkafka::Bindings.rd_kafka_abort_transaction(inner, timeout_ms)
103
+ Rdkafka::RdkafkaError.validate!(response_ptr) || true
104
+ end
105
+ end
106
+
107
+ # Sends provided offsets of a consumer to the transaction for collective commit
108
+ #
109
+ # @param consumer [Consumer] consumer that owns the given tpls
110
+ # @param tpl [Consumer::TopicPartitionList]
111
+ # @param timeout_ms [Integer] offsets send timeout
112
+ # @note Use **only** in the context of an active transaction
113
+ def send_offsets_to_transaction(consumer, tpl, timeout_ms = 5_000)
114
+ closed_producer_check(__method__)
115
+
116
+ return if tpl.empty?
117
+
118
+ cgmetadata = consumer.consumer_group_metadata_pointer
119
+ native_tpl = tpl.to_native_tpl
120
+
121
+ @native_kafka.with_inner do |inner|
122
+ response_ptr = Bindings.rd_kafka_send_offsets_to_transaction(inner, native_tpl, cgmetadata, timeout_ms)
123
+
103
124
  Rdkafka::RdkafkaError.validate!(response_ptr)
104
125
  end
126
+ ensure
127
+ if cgmetadata && !cgmetadata.null?
128
+ Bindings.rd_kafka_consumer_group_metadata_destroy(cgmetadata)
129
+ end
130
+
131
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl) unless native_tpl.nil?
105
132
  end
106
133
 
107
134
  # Close this producer and wait for the internal poll queue to empty.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rdkafka
4
- VERSION = "0.14.2"
4
+ VERSION = "0.14.4"
5
5
  LIBRDKAFKA_VERSION = "2.3.0"
6
6
  LIBRDKAFKA_SOURCE_SHA256 = "2d49c35c77eeb3d42fa61c43757fcbb6a206daa560247154e60642bcdcc14d12"
7
7
  end
@@ -50,6 +50,7 @@ describe Rdkafka::Admin::DeleteAclReport do
50
50
  end
51
51
 
52
52
  it "should get deleted acl resource pattern type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL" do
53
+ expect(subject.deleted_acls[0].matching_acl_resource_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
53
54
  expect(subject.deleted_acls[0].matching_acl_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
54
55
  end
55
56
 
@@ -51,6 +51,7 @@ describe Rdkafka::Admin::DescribeAclReport do
51
51
  end
52
52
 
53
53
  it "should get matching acl resource pattern type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL" do
54
+ expect(subject.acls[0].matching_acl_resource_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
54
55
  expect(subject.acls[0].matching_acl_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
55
56
  end
56
57
 
@@ -360,7 +360,6 @@ describe Rdkafka::Consumer do
360
360
  end
361
361
  end
362
362
 
363
-
364
363
  describe "#position, #commit, #committed and #store_offset" do
365
364
  # Make sure there are messages to work with
366
365
  let!(:report) do
@@ -480,6 +479,8 @@ describe Rdkafka::Consumer do
480
479
  end
481
480
 
482
481
  describe "#store_offset" do
482
+ let(:consumer) { rdkafka_consumer_config('enable.auto.offset.store': false).consumer }
483
+
483
484
  before do
484
485
  config = {}
485
486
  config[:'enable.auto.offset.store'] = false
@@ -542,6 +543,14 @@ describe Rdkafka::Consumer do
542
543
  }.to raise_error(Rdkafka::RdkafkaError)
543
544
  end
544
545
  end
546
+
547
+ context "when trying to use with enable.auto.offset.store set to true" do
548
+ let(:consumer) { rdkafka_consumer_config('enable.auto.offset.store': true).consumer }
549
+
550
+ it "expect to raise invalid configuration error" do
551
+ expect { consumer.store_offset(message) }.to raise_error(Rdkafka::RdkafkaError, /invalid_arg/)
552
+ end
553
+ end
545
554
  end
546
555
  end
547
556
  end
@@ -1132,6 +1141,14 @@ describe Rdkafka::Consumer do
1132
1141
  end
1133
1142
  end
1134
1143
 
1144
+ describe '#consumer_group_metadata_pointer' do
1145
+ it 'expect to yield pointer' do
1146
+ consumer.consumer_group_metadata_pointer do |pointer|
1147
+ expect(pointer).to be_a(FFI::Pointer)
1148
+ end
1149
+ end
1150
+ end
1151
+
1135
1152
  describe "a rebalance listener" do
1136
1153
  let(:consumer) do
1137
1154
  config = rdkafka_consumer_config
@@ -883,5 +883,30 @@ describe Rdkafka::Producer do
883
883
  expect { producer2.commit_transaction }.not_to raise_error
884
884
  end
885
885
  end
886
+
887
+ context 'when having a consumer with tpls for exactly once semantics' do
888
+ let(:tpl) do
889
+ producer.produce(topic: 'consume_test_topic', payload: 'data1', partition: 0).wait
890
+ result = producer.produce(topic: 'consume_test_topic', payload: 'data1', partition: 0).wait
891
+
892
+ Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
893
+ list.add_topic_and_partitions_with_offsets("consume_test_topic", 0 => result.offset + 1)
894
+ end
895
+ end
896
+
897
+ before do
898
+ consumer.subscribe("consume_test_topic")
899
+ wait_for_assignment(consumer)
900
+ producer.init_transactions
901
+ producer.begin_transaction
902
+ end
903
+
904
+ after { consumer.unsubscribe }
905
+
906
+ it 'expect to store offsets and not crash' do
907
+ producer.send_offsets_to_transaction(consumer, tpl)
908
+ producer.commit_transaction
909
+ end
910
+ end
886
911
  end
887
912
  end
data/spec/spec_helper.rb CHANGED
@@ -107,10 +107,6 @@ def wait_for_unassignment(consumer)
107
107
  end
108
108
  end
109
109
 
110
- def objects_of_type_count(type)
111
- ObjectSpace.each_object(type).count
112
- end
113
-
114
110
  def notify_listener(listener, &block)
115
111
  # 1. subscribe and poll
116
112
  consumer.subscribe("consume_test_topic")
data.tar.gz.sig CHANGED
Binary file
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.14.2
4
+ version: 0.14.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
@@ -35,7 +35,7 @@ cert_chain:
35
35
  AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
36
36
  msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
37
37
  -----END CERTIFICATE-----
38
- date: 2023-12-11 00:00:00.000000000 Z
38
+ date: 2023-12-19 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: ffi
metadata.gz.sig CHANGED
Binary file