karafka-rdkafka 0.20.0.rc5-arm64-darwin → 0.21.0.rc1-arm64-darwin
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/.github/workflows/ci_linux_x86_64_gnu.yml +66 -44
- data/.github/workflows/ci_linux_x86_64_musl.yml +51 -62
- data/.github/workflows/ci_macos_arm64.yml +23 -45
- data/.github/workflows/push_linux_x86_64_gnu.yml +2 -1
- data/.github/workflows/push_linux_x86_64_musl.yml +3 -1
- data/.github/workflows/push_macos_arm64.yml +1 -1
- data/.github/workflows/push_ruby.yml +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +12 -2
- data/README.md +15 -14
- data/ext/build_common.sh +2 -2
- data/ext/build_linux_x86_64_gnu.sh +5 -5
- data/ext/librdkafka.dylib +0 -0
- data/karafka-rdkafka.gemspec +1 -1
- data/lib/rdkafka/bindings.rb +6 -7
- data/lib/rdkafka/config.rb +1 -4
- data/lib/rdkafka/producer.rb +11 -6
- data/lib/rdkafka/version.rb +3 -3
- data/spec/rdkafka/admin_spec.rb +203 -2
- data/spec/rdkafka/bindings_spec.rb +0 -24
- data/spec/rdkafka/config_spec.rb +1 -1
- data/spec/rdkafka/consumer_spec.rb +0 -3
- data/spec/rdkafka/producer_spec.rb +295 -3
- data/spec/spec_helper.rb +21 -9
- metadata +12 -13
- data/spec/rdkafka/producer/partitions_count_spec.rb +0 -359
data/lib/rdkafka/bindings.rb
CHANGED
@@ -403,18 +403,16 @@ module Rdkafka
|
|
403
403
|
hsh[name] = method_name
|
404
404
|
end
|
405
405
|
|
406
|
-
def self.partitioner(str, partition_count,
|
406
|
+
def self.partitioner(topic_ptr, str, partition_count, partitioner = "consistent_random")
|
407
407
|
# Return RD_KAFKA_PARTITION_UA(unassigned partition) when partition count is nil/zero.
|
408
408
|
return -1 unless partition_count&.nonzero?
|
409
|
-
# musl architecture crashes with empty string
|
410
|
-
return 0 if str.empty?
|
411
409
|
|
412
|
-
str_ptr = FFI::MemoryPointer.from_string(str)
|
413
|
-
method_name = PARTITIONERS.fetch(
|
414
|
-
raise Rdkafka::Config::ConfigError.new("Unknown partitioner: #{
|
410
|
+
str_ptr = str.empty? ? FFI::MemoryPointer::NULL : FFI::MemoryPointer.from_string(str)
|
411
|
+
method_name = PARTITIONERS.fetch(partitioner) do
|
412
|
+
raise Rdkafka::Config::ConfigError.new("Unknown partitioner: #{partitioner}")
|
415
413
|
end
|
416
414
|
|
417
|
-
public_send(method_name,
|
415
|
+
public_send(method_name, topic_ptr, str_ptr, str.size, partition_count, nil, nil)
|
418
416
|
end
|
419
417
|
|
420
418
|
# Create Topics
|
@@ -532,6 +530,7 @@ module Rdkafka
|
|
532
530
|
RD_KAFKA_RESOURCE_TOPIC = 2
|
533
531
|
RD_KAFKA_RESOURCE_GROUP = 3
|
534
532
|
RD_KAFKA_RESOURCE_BROKER = 4
|
533
|
+
RD_KAFKA_RESOURCE_TRANSACTIONAL_ID = 5
|
535
534
|
|
536
535
|
# rd_kafka_ResourcePatternType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
|
537
536
|
|
data/lib/rdkafka/config.rb
CHANGED
@@ -129,10 +129,7 @@ module Rdkafka
|
|
129
129
|
end
|
130
130
|
|
131
131
|
# Default config that can be overwritten.
|
132
|
-
DEFAULT_CONFIG = {
|
133
|
-
# Request api version so advanced features work
|
134
|
-
:"api.version.request" => true
|
135
|
-
}.freeze
|
132
|
+
DEFAULT_CONFIG = {}.freeze
|
136
133
|
|
137
134
|
# Required config that cannot be overwritten.
|
138
135
|
REQUIRED_CONFIG = {
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -51,13 +51,13 @@ module Rdkafka
|
|
51
51
|
|
52
52
|
# @private
|
53
53
|
# @param native_kafka [NativeKafka]
|
54
|
-
# @param
|
54
|
+
# @param partitioner [String, nil] name of the partitioner we want to use or nil to use
|
55
55
|
# the "consistent_random" default
|
56
|
-
def initialize(native_kafka,
|
56
|
+
def initialize(native_kafka, partitioner)
|
57
57
|
@topics_refs_map = {}
|
58
58
|
@topics_configs = {}
|
59
59
|
@native_kafka = native_kafka
|
60
|
-
@
|
60
|
+
@partitioner = partitioner || "consistent_random"
|
61
61
|
|
62
62
|
# Makes sure, that native kafka gets closed before it gets GCed by Ruby
|
63
63
|
ObjectSpace.define_finalizer(self, native_kafka.finalizer)
|
@@ -337,7 +337,8 @@ module Rdkafka
|
|
337
337
|
timestamp: nil,
|
338
338
|
headers: nil,
|
339
339
|
label: nil,
|
340
|
-
topic_config: EMPTY_HASH
|
340
|
+
topic_config: EMPTY_HASH,
|
341
|
+
partitioner: @partitioner
|
341
342
|
)
|
342
343
|
closed_producer_check(__method__)
|
343
344
|
|
@@ -369,10 +370,14 @@ module Rdkafka
|
|
369
370
|
|
370
371
|
# Check if there are no overrides for the partitioner and use the default one only when
|
371
372
|
# no per-topic is present.
|
372
|
-
|
373
|
+
selected_partitioner = @topics_configs.dig(topic, topic_config_hash, :partitioner) || partitioner
|
373
374
|
|
374
375
|
# If the topic is not present, set to -1
|
375
|
-
partition = Rdkafka::Bindings.partitioner(
|
376
|
+
partition = Rdkafka::Bindings.partitioner(
|
377
|
+
topic_ref,
|
378
|
+
partition_key,
|
379
|
+
partition_count,
|
380
|
+
selected_partitioner) if partition_count.positive?
|
376
381
|
end
|
377
382
|
|
378
383
|
# If partition is nil, use -1 to let librdafka set the partition randomly or
|
data/lib/rdkafka/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Rdkafka
|
4
|
-
VERSION = "0.
|
5
|
-
LIBRDKAFKA_VERSION = "2.
|
6
|
-
LIBRDKAFKA_SOURCE_SHA256 = "
|
4
|
+
VERSION = "0.21.0.rc1"
|
5
|
+
LIBRDKAFKA_VERSION = "2.11.0"
|
6
|
+
LIBRDKAFKA_SOURCE_SHA256 = "592a823dc7c09ad4ded1bc8f700da6d4e0c88ffaf267815c6f25e7450b9395ca"
|
7
7
|
end
|
data/spec/rdkafka/admin_spec.rb
CHANGED
@@ -34,7 +34,7 @@ describe Rdkafka::Admin do
|
|
34
34
|
describe '#describe_errors' do
|
35
35
|
let(:errors) { admin.class.describe_errors }
|
36
36
|
|
37
|
-
it { expect(errors.size).to eq(
|
37
|
+
it { expect(errors.size).to eq(172) }
|
38
38
|
it { expect(errors[-184]).to eq(code: -184, description: 'Local: Queue full', name: '_QUEUE_FULL') }
|
39
39
|
it { expect(errors[21]).to eq(code: 21, description: 'Broker: Invalid required acks value', name: 'INVALID_REQUIRED_ACKS') }
|
40
40
|
end
|
@@ -513,7 +513,7 @@ describe Rdkafka::Admin do
|
|
513
513
|
end
|
514
514
|
end
|
515
515
|
|
516
|
-
describe "#ACL tests" do
|
516
|
+
describe "#ACL tests for topic resource" do
|
517
517
|
let(:non_existing_resource_name) {"non-existing-topic"}
|
518
518
|
before do
|
519
519
|
#create topic for testing acl
|
@@ -615,6 +615,207 @@ describe Rdkafka::Admin do
|
|
615
615
|
end
|
616
616
|
end
|
617
617
|
|
618
|
+
describe "#ACL tests for transactional_id" do
|
619
|
+
let(:transactional_id_resource_name) {"test-transactional-id"}
|
620
|
+
let(:non_existing_transactional_id) {"non-existing-transactional-id"}
|
621
|
+
let(:transactional_id_resource_type) { Rdkafka::Bindings::RD_KAFKA_RESOURCE_TRANSACTIONAL_ID }
|
622
|
+
let(:transactional_id_resource_pattern_type) { Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL }
|
623
|
+
let(:transactional_id_principal) { "User:test-user" }
|
624
|
+
let(:transactional_id_host) { "*" }
|
625
|
+
let(:transactional_id_operation) { Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_WRITE }
|
626
|
+
let(:transactional_id_permission_type) { Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW }
|
627
|
+
|
628
|
+
after do
|
629
|
+
# Clean up any ACLs that might have been created during tests
|
630
|
+
begin
|
631
|
+
delete_acl_handle = admin.delete_acl(
|
632
|
+
resource_type: transactional_id_resource_type,
|
633
|
+
resource_name: nil,
|
634
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
635
|
+
principal: transactional_id_principal,
|
636
|
+
host: transactional_id_host,
|
637
|
+
operation: transactional_id_operation,
|
638
|
+
permission_type: transactional_id_permission_type
|
639
|
+
)
|
640
|
+
delete_acl_handle.wait(max_wait_timeout: 15.0)
|
641
|
+
rescue
|
642
|
+
# Ignore cleanup errors
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
describe "#create_acl" do
|
647
|
+
it "creates acl for a transactional_id" do
|
648
|
+
create_acl_handle = admin.create_acl(
|
649
|
+
resource_type: transactional_id_resource_type,
|
650
|
+
resource_name: transactional_id_resource_name,
|
651
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
652
|
+
principal: transactional_id_principal,
|
653
|
+
host: transactional_id_host,
|
654
|
+
operation: transactional_id_operation,
|
655
|
+
permission_type: transactional_id_permission_type
|
656
|
+
)
|
657
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
658
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
659
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
660
|
+
end
|
661
|
+
|
662
|
+
it "creates acl for a non-existing transactional_id" do
|
663
|
+
# ACL creation for transactional_ids that don't exist will still get created successfully
|
664
|
+
create_acl_handle = admin.create_acl(
|
665
|
+
resource_type: transactional_id_resource_type,
|
666
|
+
resource_name: non_existing_transactional_id,
|
667
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
668
|
+
principal: transactional_id_principal,
|
669
|
+
host: transactional_id_host,
|
670
|
+
operation: transactional_id_operation,
|
671
|
+
permission_type: transactional_id_permission_type
|
672
|
+
)
|
673
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
674
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
675
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
676
|
+
|
677
|
+
# Clean up the ACL that was created for the non-existing transactional_id
|
678
|
+
delete_acl_handle = admin.delete_acl(
|
679
|
+
resource_type: transactional_id_resource_type,
|
680
|
+
resource_name: non_existing_transactional_id,
|
681
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
682
|
+
principal: transactional_id_principal,
|
683
|
+
host: transactional_id_host,
|
684
|
+
operation: transactional_id_operation,
|
685
|
+
permission_type: transactional_id_permission_type
|
686
|
+
)
|
687
|
+
delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
|
688
|
+
expect(delete_acl_handle[:response]).to eq(0)
|
689
|
+
expect(delete_acl_report.deleted_acls.size).to eq(1)
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
describe "#describe_acl" do
|
694
|
+
it "describes acl of a transactional_id that does not exist" do
|
695
|
+
describe_acl_handle = admin.describe_acl(
|
696
|
+
resource_type: transactional_id_resource_type,
|
697
|
+
resource_name: non_existing_transactional_id,
|
698
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
699
|
+
principal: transactional_id_principal,
|
700
|
+
host: transactional_id_host,
|
701
|
+
operation: transactional_id_operation,
|
702
|
+
permission_type: transactional_id_permission_type
|
703
|
+
)
|
704
|
+
describe_acl_report = describe_acl_handle.wait(max_wait_timeout: 15.0)
|
705
|
+
expect(describe_acl_handle[:response]).to eq(0)
|
706
|
+
expect(describe_acl_report.acls.size).to eq(0)
|
707
|
+
end
|
708
|
+
|
709
|
+
it "creates acls and describes the newly created transactional_id acls" do
|
710
|
+
# Create first ACL
|
711
|
+
create_acl_handle = admin.create_acl(
|
712
|
+
resource_type: transactional_id_resource_type,
|
713
|
+
resource_name: "test_transactional_id_1",
|
714
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
715
|
+
principal: transactional_id_principal,
|
716
|
+
host: transactional_id_host,
|
717
|
+
operation: transactional_id_operation,
|
718
|
+
permission_type: transactional_id_permission_type
|
719
|
+
)
|
720
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
721
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
722
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
723
|
+
|
724
|
+
# Create second ACL
|
725
|
+
create_acl_handle = admin.create_acl(
|
726
|
+
resource_type: transactional_id_resource_type,
|
727
|
+
resource_name: "test_transactional_id_2",
|
728
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
729
|
+
principal: transactional_id_principal,
|
730
|
+
host: transactional_id_host,
|
731
|
+
operation: transactional_id_operation,
|
732
|
+
permission_type: transactional_id_permission_type
|
733
|
+
)
|
734
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
735
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
736
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
737
|
+
|
738
|
+
# Since we create and immediately check, this is slow on loaded CIs, hence we wait
|
739
|
+
sleep(2)
|
740
|
+
|
741
|
+
# Describe ACLs - filter by transactional_id resource type
|
742
|
+
describe_acl_handle = admin.describe_acl(
|
743
|
+
resource_type: transactional_id_resource_type,
|
744
|
+
resource_name: nil,
|
745
|
+
resource_pattern_type: Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_ANY,
|
746
|
+
principal: transactional_id_principal,
|
747
|
+
host: transactional_id_host,
|
748
|
+
operation: transactional_id_operation,
|
749
|
+
permission_type: transactional_id_permission_type
|
750
|
+
)
|
751
|
+
describe_acl_report = describe_acl_handle.wait(max_wait_timeout: 15.0)
|
752
|
+
expect(describe_acl_handle[:response]).to eq(0)
|
753
|
+
expect(describe_acl_report.acls.length).to eq(2)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
describe "#delete_acl" do
|
758
|
+
it "deletes acl of a transactional_id that does not exist" do
|
759
|
+
delete_acl_handle = admin.delete_acl(
|
760
|
+
resource_type: transactional_id_resource_type,
|
761
|
+
resource_name: non_existing_transactional_id,
|
762
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
763
|
+
principal: transactional_id_principal,
|
764
|
+
host: transactional_id_host,
|
765
|
+
operation: transactional_id_operation,
|
766
|
+
permission_type: transactional_id_permission_type
|
767
|
+
)
|
768
|
+
delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
|
769
|
+
expect(delete_acl_handle[:response]).to eq(0)
|
770
|
+
expect(delete_acl_report.deleted_acls.size).to eq(0)
|
771
|
+
end
|
772
|
+
|
773
|
+
it "creates transactional_id acls and deletes the newly created acls" do
|
774
|
+
# Create first ACL
|
775
|
+
create_acl_handle = admin.create_acl(
|
776
|
+
resource_type: transactional_id_resource_type,
|
777
|
+
resource_name: "test_transactional_id_1",
|
778
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
779
|
+
principal: transactional_id_principal,
|
780
|
+
host: transactional_id_host,
|
781
|
+
operation: transactional_id_operation,
|
782
|
+
permission_type: transactional_id_permission_type
|
783
|
+
)
|
784
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
785
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
786
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
787
|
+
|
788
|
+
# Create second ACL
|
789
|
+
create_acl_handle = admin.create_acl(
|
790
|
+
resource_type: transactional_id_resource_type,
|
791
|
+
resource_name: "test_transactional_id_2",
|
792
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
793
|
+
principal: transactional_id_principal,
|
794
|
+
host: transactional_id_host,
|
795
|
+
operation: transactional_id_operation,
|
796
|
+
permission_type: transactional_id_permission_type
|
797
|
+
)
|
798
|
+
create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
|
799
|
+
expect(create_acl_report.rdkafka_response).to eq(0)
|
800
|
+
expect(create_acl_report.rdkafka_response_string).to eq("")
|
801
|
+
|
802
|
+
# Delete ACLs - resource_name nil to delete all ACLs with any resource name and matching all other filters
|
803
|
+
delete_acl_handle = admin.delete_acl(
|
804
|
+
resource_type: transactional_id_resource_type,
|
805
|
+
resource_name: nil,
|
806
|
+
resource_pattern_type: transactional_id_resource_pattern_type,
|
807
|
+
principal: transactional_id_principal,
|
808
|
+
host: transactional_id_host,
|
809
|
+
operation: transactional_id_operation,
|
810
|
+
permission_type: transactional_id_permission_type
|
811
|
+
)
|
812
|
+
delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
|
813
|
+
expect(delete_acl_handle[:response]).to eq(0)
|
814
|
+
expect(delete_acl_report.deleted_acls.length).to eq(2)
|
815
|
+
end
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
618
819
|
describe('Group tests') do
|
619
820
|
describe "#delete_group" do
|
620
821
|
describe("with an existing group") do
|
@@ -77,30 +77,6 @@ describe Rdkafka::Bindings do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
describe "partitioner" do
|
81
|
-
let(:partition_key) { ('a'..'z').to_a.shuffle.take(15).join('') }
|
82
|
-
let(:partition_count) { rand(50) + 1 }
|
83
|
-
|
84
|
-
it "should return the same partition for a similar string and the same partition count" do
|
85
|
-
result_1 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
86
|
-
result_2 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
87
|
-
expect(result_1).to eq(result_2)
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should match the old partitioner" do
|
91
|
-
result_1 = Rdkafka::Bindings.partitioner(partition_key, partition_count)
|
92
|
-
result_2 = (Zlib.crc32(partition_key) % partition_count)
|
93
|
-
expect(result_1).to eq(result_2)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should return the partition calculated by the specified partitioner" do
|
97
|
-
result_1 = Rdkafka::Bindings.partitioner(partition_key, partition_count, "murmur2")
|
98
|
-
ptr = FFI::MemoryPointer.from_string(partition_key)
|
99
|
-
result_2 = Rdkafka::Bindings.rd_kafka_msg_partitioner_murmur2(nil, ptr, partition_key.size, partition_count, nil, nil)
|
100
|
-
expect(result_1).to eq(result_2)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
80
|
describe "stats callback" do
|
105
81
|
context "without a stats callback" do
|
106
82
|
it "should do nothing" do
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -159,7 +159,7 @@ describe Rdkafka::Config do
|
|
159
159
|
|
160
160
|
it "should use default configuration" do
|
161
161
|
config = Rdkafka::Config.new
|
162
|
-
expect(config[:"api.version.request"]).to eq
|
162
|
+
expect(config[:"api.version.request"]).to eq nil
|
163
163
|
end
|
164
164
|
|
165
165
|
it "should create a consumer with valid config" do
|
@@ -1291,9 +1291,6 @@ describe Rdkafka::Consumer do
|
|
1291
1291
|
end
|
1292
1292
|
|
1293
1293
|
expect(eof_error.code).to eq(:partition_eof)
|
1294
|
-
expect(eof_error.details[:topic]).to eq('consume_test_topic')
|
1295
|
-
expect(eof_error.details[:partition]).to be_a(Integer)
|
1296
|
-
expect(eof_error.details[:offset]).to be_a(Integer)
|
1297
1294
|
end
|
1298
1295
|
end
|
1299
1296
|
end
|