rdkafka 0.29.0-aarch64-linux-gnu → 0.29.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 +4 -4
- data/CHANGELOG.md +33 -24
- data/README.md +2 -2
- data/bin/verify_kafka_warnings +5 -0
- data/docker-compose-ssl.yml +3 -0
- data/docker-compose.yml +3 -0
- data/ext/librdkafka.so +0 -0
- data/lib/rdkafka/admin/create_acl_report.rb +2 -1
- data/lib/rdkafka/admin/delete_records_handle.rb +31 -0
- data/lib/rdkafka/admin/delete_records_report.rb +25 -0
- data/lib/rdkafka/admin/describe_acl_report.rb +2 -1
- data/lib/rdkafka/admin/list_consumer_groups_handle.rb +31 -0
- data/lib/rdkafka/admin/list_consumer_groups_report.rb +83 -0
- data/lib/rdkafka/admin/list_offsets_report.rb +5 -2
- data/lib/rdkafka/admin.rb +178 -117
- data/lib/rdkafka/bindings.rb +52 -12
- data/lib/rdkafka/callbacks/delete_records_handler.rb +38 -0
- data/lib/rdkafka/callbacks/list_consumer_groups_handler.rb +39 -0
- data/lib/rdkafka/callbacks.rb +4 -2
- data/lib/rdkafka/config.rb +24 -17
- data/lib/rdkafka/consumer/topic_partition_list.rb +14 -8
- data/lib/rdkafka/consumer.rb +103 -34
- data/lib/rdkafka/defaults.rb +5 -7
- data/lib/rdkafka/helpers/list_offsets.rb +127 -0
- data/lib/rdkafka/helpers/oauth.rb +10 -5
- data/lib/rdkafka/native_kafka.rb +20 -7
- data/lib/rdkafka/producer/delivery_handle.rb +1 -2
- data/lib/rdkafka/producer.rb +25 -17
- data/lib/rdkafka/version.rb +1 -1
- data/lib/rdkafka.rb +7 -0
- data/package-lock.json +3 -3
- metadata +9 -2
data/lib/rdkafka/admin.rb
CHANGED
|
@@ -5,6 +5,7 @@ module Rdkafka
|
|
|
5
5
|
class Admin
|
|
6
6
|
include Helpers::OAuth
|
|
7
7
|
include Helpers::Metadata
|
|
8
|
+
include Helpers::ListOffsets
|
|
8
9
|
|
|
9
10
|
class << self
|
|
10
11
|
# Allows us to retrieve librdkafka errors with descriptions
|
|
@@ -107,10 +108,6 @@ module Rdkafka
|
|
|
107
108
|
# @return [nil]
|
|
108
109
|
# @raise [Rdkafka::ClosedAdminError] if called on a closed admin client
|
|
109
110
|
#
|
|
110
|
-
# @note This method holds the inner lock until the queue is empty or `:stop` is returned.
|
|
111
|
-
# Other admin operations will wait until this method returns.
|
|
112
|
-
# @note This method is thread-safe as it uses @native_kafka.with_inner synchronization
|
|
113
|
-
#
|
|
114
111
|
# @example Drain all pending events
|
|
115
112
|
# admin.events_poll_nb_each { |_count| }
|
|
116
113
|
#
|
|
@@ -119,6 +116,9 @@ module Rdkafka
|
|
|
119
116
|
# admin.events_poll_nb_each do |_count|
|
|
120
117
|
# :stop if monotonic_now >= deadline
|
|
121
118
|
# end
|
|
119
|
+
# @note This method holds the inner lock until the queue is empty or `:stop` is returned.
|
|
120
|
+
# Other admin operations will wait until this method returns.
|
|
121
|
+
# @note This method is thread-safe as it uses @native_kafka.with_inner synchronization
|
|
122
122
|
def events_poll_nb_each
|
|
123
123
|
closed_admin_check(__method__)
|
|
124
124
|
|
|
@@ -282,6 +282,172 @@ module Rdkafka
|
|
|
282
282
|
delete_groups_handle
|
|
283
283
|
end
|
|
284
284
|
|
|
285
|
+
# Deletes all messages in the given partitions up to (but not including) the given offset.
|
|
286
|
+
#
|
|
287
|
+
# The programmatic equivalent of `kafka-delete-records.sh`. Useful for GDPR/right-to-erasure
|
|
288
|
+
# compliance, clearing out poison messages, or retention cleanup outside of the configured
|
|
289
|
+
# time/size-based retention policy.
|
|
290
|
+
#
|
|
291
|
+
# @param topic_partition_offsets [Hash{String => Array<Hash>}] hash mapping topic names to
|
|
292
|
+
# arrays of partition delete specifications. Each specification is a hash with:
|
|
293
|
+
# - `:partition` [Integer] partition number
|
|
294
|
+
# - `:offset` [Symbol, Integer] delete all messages before this offset (exclusive) - an
|
|
295
|
+
# integer offset, or `:end` to delete all data currently in the partition
|
|
296
|
+
#
|
|
297
|
+
# @return [DeleteRecordsHandle] handle that can be used to wait for the result
|
|
298
|
+
# @raise [RdkafkaError] when deleting records fails
|
|
299
|
+
#
|
|
300
|
+
# @example Delete all messages before offset 100 in one partition, and all data in another
|
|
301
|
+
# report = admin.delete_records(
|
|
302
|
+
# "my_topic" => [
|
|
303
|
+
# { partition: 0, offset: 100 },
|
|
304
|
+
# { partition: 1, offset: :end }
|
|
305
|
+
# ]
|
|
306
|
+
# ).wait(max_wait_timeout_ms: 15_000)
|
|
307
|
+
#
|
|
308
|
+
# report.offsets.to_h
|
|
309
|
+
# # => { "my_topic" => [#<Partition @partition=0, @offset=100, @err=0>, ...] }
|
|
310
|
+
def delete_records(topic_partition_offsets)
|
|
311
|
+
closed_admin_check(__method__)
|
|
312
|
+
|
|
313
|
+
parsed = topic_partition_offsets.flat_map do |topic, partitions|
|
|
314
|
+
partitions.map do |spec|
|
|
315
|
+
offset = spec.fetch(:offset)
|
|
316
|
+
|
|
317
|
+
native_offset = case offset
|
|
318
|
+
when :end then Rdkafka::Bindings::RD_KAFKA_OFFSET_END
|
|
319
|
+
when Integer then offset
|
|
320
|
+
else
|
|
321
|
+
raise ArgumentError, "Unknown offset specification: #{offset.inspect}"
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
[topic, spec.fetch(:partition), native_offset]
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
tpl = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(parsed.size)
|
|
329
|
+
|
|
330
|
+
parsed.each do |topic, partition, native_offset|
|
|
331
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(tpl, topic, partition)
|
|
332
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(tpl, topic, partition, native_offset)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# rd_kafka_DeleteRecords_new copies the tpl it is given, so it does not need to (and must
|
|
336
|
+
# not) outlive this call - it is destroyed below, independently of the wrapping
|
|
337
|
+
# DeleteRecords_t object.
|
|
338
|
+
delete_records_ptr = Rdkafka::Bindings.rd_kafka_DeleteRecords_new(tpl)
|
|
339
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
|
340
|
+
|
|
341
|
+
pointer_array = [delete_records_ptr]
|
|
342
|
+
records_array_ptr = FFI::MemoryPointer.new(:pointer)
|
|
343
|
+
records_array_ptr.write_array_of_pointer(pointer_array)
|
|
344
|
+
|
|
345
|
+
# Get a pointer to the queue that our request will be enqueued on
|
|
346
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
347
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
348
|
+
end
|
|
349
|
+
if queue_ptr.null?
|
|
350
|
+
Rdkafka::Bindings.rd_kafka_DeleteRecords_destroy(delete_records_ptr)
|
|
351
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Create and register the handle we will return to the caller
|
|
355
|
+
handle = DeleteRecordsHandle.new
|
|
356
|
+
handle[:pending] = true
|
|
357
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
358
|
+
DeleteRecordsHandle.register(handle)
|
|
359
|
+
|
|
360
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
361
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETERECORDS)
|
|
362
|
+
end
|
|
363
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
364
|
+
|
|
365
|
+
begin
|
|
366
|
+
@native_kafka.with_inner do |inner|
|
|
367
|
+
Rdkafka::Bindings.rd_kafka_DeleteRecords(
|
|
368
|
+
inner,
|
|
369
|
+
records_array_ptr,
|
|
370
|
+
1,
|
|
371
|
+
admin_options_ptr,
|
|
372
|
+
queue_ptr
|
|
373
|
+
)
|
|
374
|
+
end
|
|
375
|
+
rescue Exception
|
|
376
|
+
DeleteRecordsHandle.remove(handle.to_ptr.address)
|
|
377
|
+
raise
|
|
378
|
+
ensure
|
|
379
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
380
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
381
|
+
Rdkafka::Bindings.rd_kafka_DeleteRecords_destroy(delete_records_ptr)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
handle
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Lists consumer groups cluster-wide.
|
|
388
|
+
#
|
|
389
|
+
# librdkafka issues a single `ListConsumerGroups` request that is fanned out to every broker
|
|
390
|
+
# internally, so the result covers all consumer groups in the cluster, not only those
|
|
391
|
+
# coordinated by the connected broker.
|
|
392
|
+
#
|
|
393
|
+
# @return [ListConsumerGroupsHandle] handle that can be used to wait for the result
|
|
394
|
+
# @raise [RdkafkaError] when listing the consumer groups fails
|
|
395
|
+
#
|
|
396
|
+
# @example List every consumer group in the cluster and print its name and attributes
|
|
397
|
+
# report = admin.list_consumer_groups.wait(max_wait_timeout_ms: 15_000)
|
|
398
|
+
#
|
|
399
|
+
# report.groups.each do |group|
|
|
400
|
+
# puts "#{group[:group_id]} - #{group[:state_name]} " \
|
|
401
|
+
# "(simple: #{group[:is_simple_consumer_group]})"
|
|
402
|
+
# end
|
|
403
|
+
#
|
|
404
|
+
# # Any brokers that could not be reached are reported separately
|
|
405
|
+
# report.errors.each { |error| warn "partial listing error: #{error.message}" }
|
|
406
|
+
def list_consumer_groups
|
|
407
|
+
closed_admin_check(__method__)
|
|
408
|
+
|
|
409
|
+
# Get a pointer to the queue that our request will be enqueued on
|
|
410
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
411
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
if queue_ptr.null?
|
|
415
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Create and register the handle we will return to the caller
|
|
419
|
+
handle = ListConsumerGroupsHandle.new
|
|
420
|
+
handle[:pending] = true
|
|
421
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
422
|
+
ListConsumerGroupsHandle.register(handle)
|
|
423
|
+
|
|
424
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
425
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
|
|
426
|
+
inner,
|
|
427
|
+
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_LISTCONSUMERGROUPS
|
|
428
|
+
)
|
|
429
|
+
end
|
|
430
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
431
|
+
|
|
432
|
+
begin
|
|
433
|
+
@native_kafka.with_inner do |inner|
|
|
434
|
+
Rdkafka::Bindings.rd_kafka_ListConsumerGroups(
|
|
435
|
+
inner,
|
|
436
|
+
admin_options_ptr,
|
|
437
|
+
queue_ptr
|
|
438
|
+
)
|
|
439
|
+
end
|
|
440
|
+
rescue Exception
|
|
441
|
+
ListConsumerGroupsHandle.remove(handle.to_ptr.address)
|
|
442
|
+
raise
|
|
443
|
+
ensure
|
|
444
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
445
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
handle
|
|
449
|
+
end
|
|
450
|
+
|
|
285
451
|
# Deletes the named topic
|
|
286
452
|
#
|
|
287
453
|
# @param topic_name [String] name of the topic to delete
|
|
@@ -344,7 +510,8 @@ module Rdkafka
|
|
|
344
510
|
#
|
|
345
511
|
# @param topic_name [String] name of the topic
|
|
346
512
|
# @param partition_count [Integer] how many partitions we want to end up with for given topic
|
|
347
|
-
# @return [CreatePartitionsHandle] Create partitions handle that can be used to wait for the
|
|
513
|
+
# @return [CreatePartitionsHandle] Create partitions handle that can be used to wait for the
|
|
514
|
+
# result
|
|
348
515
|
# @raise [ConfigError] When the partition count or replication factor are out of valid range
|
|
349
516
|
# @raise [RdkafkaError] When the topic name is invalid or the topic already exists
|
|
350
517
|
# @raise [RdkafkaError] When the topic configuration is invalid
|
|
@@ -433,7 +600,8 @@ module Rdkafka
|
|
|
433
600
|
# @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
|
|
434
601
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
|
|
435
602
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
|
|
436
|
-
# @return [CreateAclHandle] Create acl handle that can be used to wait for the result of
|
|
603
|
+
# @return [CreateAclHandle] Create acl handle that can be used to wait for the result of
|
|
604
|
+
# creating the acl
|
|
437
605
|
# @raise [RdkafkaError]
|
|
438
606
|
def create_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
|
|
439
607
|
closed_admin_check(__method__)
|
|
@@ -534,7 +702,8 @@ module Rdkafka
|
|
|
534
702
|
# @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
|
|
535
703
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
|
|
536
704
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
|
|
537
|
-
# @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of
|
|
705
|
+
# @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of
|
|
706
|
+
# deleting the acl
|
|
538
707
|
# @raise [RdkafkaError]
|
|
539
708
|
def delete_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
|
|
540
709
|
closed_admin_check(__method__)
|
|
@@ -637,7 +806,8 @@ module Rdkafka
|
|
|
637
806
|
# @param permission_type [Integer] rd_kafka_AclPermissionType_t value:
|
|
638
807
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
|
|
639
808
|
# - RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
|
|
640
|
-
# @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of
|
|
809
|
+
# @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of
|
|
810
|
+
# fetching acls
|
|
641
811
|
# @raise [RdkafkaError]
|
|
642
812
|
def describe_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
|
|
643
813
|
closed_admin_check(__method__)
|
|
@@ -909,115 +1079,6 @@ module Rdkafka
|
|
|
909
1079
|
handle
|
|
910
1080
|
end
|
|
911
1081
|
|
|
912
|
-
# Queries partition offsets by specification (earliest, latest, max_timestamp, or by
|
|
913
|
-
# timestamp) without requiring a consumer group.
|
|
914
|
-
#
|
|
915
|
-
# @param topic_partition_offsets [Hash{String => Array<Hash>}] hash mapping topic names to
|
|
916
|
-
# arrays of partition offset specifications. Each specification is a hash with:
|
|
917
|
-
# - `:partition` [Integer] partition number
|
|
918
|
-
# - `:offset` [Symbol, Integer] offset specification - `:earliest`, `:latest`,
|
|
919
|
-
# `:max_timestamp`, or an integer timestamp in milliseconds
|
|
920
|
-
# @param isolation_level [Integer, nil] optional isolation level:
|
|
921
|
-
# - `RD_KAFKA_ISOLATION_LEVEL_READ_UNCOMMITTED` (0) - default
|
|
922
|
-
# - `RD_KAFKA_ISOLATION_LEVEL_READ_COMMITTED` (1)
|
|
923
|
-
#
|
|
924
|
-
# @return [ListOffsetsHandle] handle that can be used to wait for the result
|
|
925
|
-
#
|
|
926
|
-
# @raise [ClosedAdminError] when the admin is closed
|
|
927
|
-
# @raise [ConfigError] when the background queue is unavailable
|
|
928
|
-
#
|
|
929
|
-
# @example Query earliest and latest offsets
|
|
930
|
-
# handle = admin.list_offsets(
|
|
931
|
-
# { "my_topic" => [
|
|
932
|
-
# { partition: 0, offset: :earliest },
|
|
933
|
-
# { partition: 1, offset: :latest }
|
|
934
|
-
# ] }
|
|
935
|
-
# )
|
|
936
|
-
# report = handle.wait(max_wait_timeout_ms: 15_000)
|
|
937
|
-
# report.offsets
|
|
938
|
-
# # => [{ topic: "my_topic", partition: 0, offset: 0, ... }, ...]
|
|
939
|
-
def list_offsets(topic_partition_offsets, isolation_level: nil)
|
|
940
|
-
closed_admin_check(__method__)
|
|
941
|
-
|
|
942
|
-
# Parse and validate every offset spec before allocating the native list, so a missing key or
|
|
943
|
-
# an unknown offset specification raises with nothing to clean up. Previously the
|
|
944
|
-
# ArgumentError (or KeyError) was raised after `rd_kafka_topic_partition_list_new`, leaking
|
|
945
|
-
# the native list.
|
|
946
|
-
parsed = topic_partition_offsets.flat_map do |topic, partitions|
|
|
947
|
-
partitions.map do |spec|
|
|
948
|
-
offset = spec.fetch(:offset)
|
|
949
|
-
|
|
950
|
-
native_offset = case offset
|
|
951
|
-
when :earliest then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_EARLIEST
|
|
952
|
-
when :latest then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_LATEST
|
|
953
|
-
when :max_timestamp then Rdkafka::Bindings::RD_KAFKA_OFFSET_SPEC_MAX_TIMESTAMP
|
|
954
|
-
when Integer then offset
|
|
955
|
-
else
|
|
956
|
-
raise ArgumentError, "Unknown offset specification: #{offset.inspect}"
|
|
957
|
-
end
|
|
958
|
-
|
|
959
|
-
[topic, spec.fetch(:partition), native_offset]
|
|
960
|
-
end
|
|
961
|
-
end
|
|
962
|
-
|
|
963
|
-
# Build native topic partition list
|
|
964
|
-
tpl = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(parsed.size)
|
|
965
|
-
|
|
966
|
-
parsed.each do |topic, partition, native_offset|
|
|
967
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(tpl, topic, partition)
|
|
968
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(tpl, topic, partition, native_offset)
|
|
969
|
-
end
|
|
970
|
-
|
|
971
|
-
# Get a pointer to the queue that our request will be enqueued on
|
|
972
|
-
queue_ptr = @native_kafka.with_inner do |inner|
|
|
973
|
-
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
974
|
-
end
|
|
975
|
-
|
|
976
|
-
if queue_ptr.null?
|
|
977
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
|
978
|
-
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
979
|
-
end
|
|
980
|
-
|
|
981
|
-
# Create and register the handle we will return to the caller
|
|
982
|
-
handle = ListOffsetsHandle.new
|
|
983
|
-
handle[:pending] = true
|
|
984
|
-
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
985
|
-
|
|
986
|
-
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
987
|
-
Rdkafka::Bindings.rd_kafka_AdminOptions_new(
|
|
988
|
-
inner,
|
|
989
|
-
Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_LISTOFFSETS
|
|
990
|
-
)
|
|
991
|
-
end
|
|
992
|
-
|
|
993
|
-
if isolation_level
|
|
994
|
-
Rdkafka::Bindings.rd_kafka_AdminOptions_set_isolation_level(admin_options_ptr, isolation_level)
|
|
995
|
-
end
|
|
996
|
-
|
|
997
|
-
ListOffsetsHandle.register(handle)
|
|
998
|
-
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
999
|
-
|
|
1000
|
-
begin
|
|
1001
|
-
@native_kafka.with_inner do |inner|
|
|
1002
|
-
Rdkafka::Bindings.rd_kafka_ListOffsets(
|
|
1003
|
-
inner,
|
|
1004
|
-
tpl,
|
|
1005
|
-
admin_options_ptr,
|
|
1006
|
-
queue_ptr
|
|
1007
|
-
)
|
|
1008
|
-
end
|
|
1009
|
-
rescue Exception
|
|
1010
|
-
ListOffsetsHandle.remove(handle.to_ptr.address)
|
|
1011
|
-
raise
|
|
1012
|
-
ensure
|
|
1013
|
-
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
1014
|
-
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
1015
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
|
1016
|
-
end
|
|
1017
|
-
|
|
1018
|
-
handle
|
|
1019
|
-
end
|
|
1020
|
-
|
|
1021
1082
|
private
|
|
1022
1083
|
|
|
1023
1084
|
# Checks if the admin is closed and raises an error if so
|
data/lib/rdkafka/bindings.rb
CHANGED
|
@@ -58,6 +58,7 @@ module Rdkafka
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
RD_KAFKA_RESP_ERR__TIMED_OUT = -185
|
|
61
62
|
RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS = -175
|
|
62
63
|
RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS = -174
|
|
63
64
|
RD_KAFKA_RESP_ERR__STATE = -172
|
|
@@ -81,7 +82,7 @@ module Rdkafka
|
|
|
81
82
|
|
|
82
83
|
# This function comes from our patch on top of librdkafka. It allows os to load all the
|
|
83
84
|
# librdkafka components without initializing the client
|
|
84
|
-
#
|
|
85
|
+
# See: https://github.com/confluentinc/librdkafka/issues/4590
|
|
85
86
|
attach_function :rd_kafka_global_init, [], :void
|
|
86
87
|
|
|
87
88
|
# Polling
|
|
@@ -235,6 +236,8 @@ module Rdkafka
|
|
|
235
236
|
|
|
236
237
|
attach_function :rd_kafka_conf_new, [], :pointer
|
|
237
238
|
attach_function :rd_kafka_conf_set, [:pointer, :string, :string, :pointer, :int], :kafka_config_response
|
|
239
|
+
attach_function :rd_kafka_conf_get, [:pointer, :string, :pointer, :pointer], :kafka_config_response
|
|
240
|
+
attach_function :rd_kafka_conf, [:pointer], :pointer
|
|
238
241
|
attach_function :rd_kafka_conf_dump, [:pointer, :pointer], :pointer
|
|
239
242
|
attach_function :rd_kafka_conf_dump_free, [:pointer, :size_t], :void
|
|
240
243
|
attach_function :rd_kafka_conf_destroy, [:pointer], :void
|
|
@@ -257,10 +260,11 @@ module Rdkafka
|
|
|
257
260
|
|
|
258
261
|
# Queue IO Event Support - for fiber scheduler integration
|
|
259
262
|
# Enables notifications to a custom FD when queue transitions from empty to non-empty
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
#
|
|
263
|
+
# Arguments:
|
|
264
|
+
# - queue (rd_kafka_queue_t*) - the queue to monitor
|
|
265
|
+
# - fd (int) - file descriptor to write to (provide your own pipe/eventfd)
|
|
266
|
+
# - payload (const void*) - data to write to fd
|
|
267
|
+
# - size (size_t) - size of payload
|
|
264
268
|
attach_function :rd_kafka_queue_io_event_enable, [:pointer, :int, :pointer, :size_t], :void
|
|
265
269
|
# Per topic configs
|
|
266
270
|
attach_function :rd_kafka_topic_conf_new, [], :pointer
|
|
@@ -335,9 +339,10 @@ module Rdkafka
|
|
|
335
339
|
end
|
|
336
340
|
end
|
|
337
341
|
|
|
338
|
-
# The OAuth callback is currently global and contextless.
|
|
339
|
-
#
|
|
340
|
-
# The instance name will be provided in the callback, allowing the callback to
|
|
342
|
+
# The OAuth callback is currently global and contextless. This means that the callback will be
|
|
343
|
+
# called for all instances, and the callback must be able to determine to which instance it is
|
|
344
|
+
# associated. The instance name will be provided in the callback, allowing the callback to
|
|
345
|
+
# reference the correct instance.
|
|
341
346
|
#
|
|
342
347
|
# An example of how to use the instance name in the callback is given below.
|
|
343
348
|
# The `refresh_token` is configured as the `oauthbearer_token_refresh_callback`.
|
|
@@ -541,6 +546,37 @@ module Rdkafka
|
|
|
541
546
|
attach_function :rd_kafka_event_DeleteGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteGroups_result_t*
|
|
542
547
|
attach_function :rd_kafka_DeleteGroups_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_DeleteGroups_result_t*, size_t* => rd_kafka_group_result_t**
|
|
543
548
|
|
|
549
|
+
# Delete Records
|
|
550
|
+
RD_KAFKA_ADMIN_OP_DELETERECORDS = 6 # rd_kafka_admin_op_t
|
|
551
|
+
RD_KAFKA_EVENT_DELETERECORDS_RESULT = 105 # rd_kafka_event_type_t
|
|
552
|
+
|
|
553
|
+
attach_function :rd_kafka_DeleteRecords, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
|
|
554
|
+
attach_function :rd_kafka_DeleteRecords_new, [:pointer], :pointer, blocking: true
|
|
555
|
+
attach_function :rd_kafka_DeleteRecords_destroy, [:pointer], :void, blocking: true
|
|
556
|
+
attach_function :rd_kafka_event_DeleteRecords_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteRecords_result_t*
|
|
557
|
+
attach_function :rd_kafka_DeleteRecords_result_offsets, [:pointer], :pointer, blocking: true # rd_kafka_DeleteRecords_result_t* => rd_kafka_topic_partition_list_t*
|
|
558
|
+
|
|
559
|
+
# List Consumer Groups
|
|
560
|
+
RD_KAFKA_ADMIN_OP_LISTCONSUMERGROUPS = 12 # rd_kafka_admin_op_t
|
|
561
|
+
RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT = 0x2000 # rd_kafka_event_type_t
|
|
562
|
+
|
|
563
|
+
# Consumer group states (rd_kafka_consumer_group_state_t)
|
|
564
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_UNKNOWN = 0
|
|
565
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_PREPARING_REBALANCE = 1
|
|
566
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_COMPLETING_REBALANCE = 2
|
|
567
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_STABLE = 3
|
|
568
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_DEAD = 4
|
|
569
|
+
RD_KAFKA_CONSUMER_GROUP_STATE_EMPTY = 5
|
|
570
|
+
|
|
571
|
+
attach_function :rd_kafka_ListConsumerGroups, [:pointer, :pointer, :pointer], :void, blocking: true
|
|
572
|
+
attach_function :rd_kafka_event_ListConsumerGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_ListConsumerGroups_result_t*
|
|
573
|
+
attach_function :rd_kafka_ListConsumerGroups_result_valid, [:pointer, :pointer], :pointer, blocking: true # result*, size_t* => rd_kafka_ConsumerGroupListing_t**
|
|
574
|
+
attach_function :rd_kafka_ListConsumerGroups_result_errors, [:pointer, :pointer], :pointer, blocking: true # result*, size_t* => rd_kafka_error_t**
|
|
575
|
+
attach_function :rd_kafka_ConsumerGroupListing_group_id, [:pointer], :pointer, blocking: true # => const char*
|
|
576
|
+
attach_function :rd_kafka_ConsumerGroupListing_is_simple_consumer_group, [:pointer], :int, blocking: true
|
|
577
|
+
attach_function :rd_kafka_ConsumerGroupListing_state, [:pointer], :int, blocking: true
|
|
578
|
+
attach_function :rd_kafka_consumer_group_state_name, [:int], :pointer, blocking: true # => const char*
|
|
579
|
+
|
|
544
580
|
# Background Queue and Callback
|
|
545
581
|
|
|
546
582
|
attach_function :rd_kafka_conf_set_background_event_cb, [:pointer, :pointer], :void
|
|
@@ -603,21 +639,24 @@ module Rdkafka
|
|
|
603
639
|
attach_function :rd_kafka_AclBindingFilter_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t], :pointer
|
|
604
640
|
attach_function :rd_kafka_AclBinding_destroy, [:pointer], :void
|
|
605
641
|
|
|
606
|
-
# rd_kafka_ResourceType_t -
|
|
642
|
+
# rd_kafka_ResourceType_t -
|
|
643
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7307
|
|
607
644
|
RD_KAFKA_RESOURCE_ANY = 1
|
|
608
645
|
RD_KAFKA_RESOURCE_TOPIC = 2
|
|
609
646
|
RD_KAFKA_RESOURCE_GROUP = 3
|
|
610
647
|
RD_KAFKA_RESOURCE_BROKER = 4
|
|
611
648
|
RD_KAFKA_RESOURCE_TRANSACTIONAL_ID = 5
|
|
612
649
|
|
|
613
|
-
# rd_kafka_ResourcePatternType_t -
|
|
650
|
+
# rd_kafka_ResourcePatternType_t -
|
|
651
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L7320
|
|
614
652
|
RD_KAFKA_RESOURCE_PATTERN_UNKNOWN = 0
|
|
615
653
|
RD_KAFKA_RESOURCE_PATTERN_ANY = 1
|
|
616
654
|
RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
|
|
617
655
|
RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
|
|
618
656
|
RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
|
|
619
657
|
|
|
620
|
-
# rd_kafka_AclOperation_t -
|
|
658
|
+
# rd_kafka_AclOperation_t -
|
|
659
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8403
|
|
621
660
|
RD_KAFKA_ACL_OPERATION_ANY = 1
|
|
622
661
|
RD_KAFKA_ACL_OPERATION_ALL = 2
|
|
623
662
|
RD_KAFKA_ACL_OPERATION_READ = 3
|
|
@@ -631,7 +670,8 @@ module Rdkafka
|
|
|
631
670
|
RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
|
|
632
671
|
RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
|
|
633
672
|
|
|
634
|
-
# rd_kafka_AclPermissionType_t -
|
|
673
|
+
# rd_kafka_AclPermissionType_t -
|
|
674
|
+
# https://github.com/confluentinc/librdkafka/blob/292d2a66b992/src/rdkafka.h#L8435
|
|
635
675
|
RD_KAFKA_ACL_PERMISSION_TYPE_ANY = 1
|
|
636
676
|
RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
|
|
637
677
|
RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
module Callbacks
|
|
5
|
+
# Handles `RD_KAFKA_EVENT_DELETERECORDS_RESULT` events
|
|
6
|
+
# @private
|
|
7
|
+
class DeleteRecordsHandler < BaseHandler
|
|
8
|
+
class << self
|
|
9
|
+
# Resolves the delete-records handle from its result event
|
|
10
|
+
# @param event_ptr [FFI::Pointer] pointer to the event
|
|
11
|
+
# @return [void]
|
|
12
|
+
def call(event_ptr)
|
|
13
|
+
result_ptr = Rdkafka::Bindings.rd_kafka_event_DeleteRecords_result(event_ptr)
|
|
14
|
+
handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
|
|
15
|
+
|
|
16
|
+
return unless (handle = Rdkafka::Admin::DeleteRecordsHandle.remove(handle_ptr.address))
|
|
17
|
+
|
|
18
|
+
# An operation-level error (e.g. timeout or a closed client) is delivered on the event
|
|
19
|
+
# itself, with no per-partition result to parse.
|
|
20
|
+
return if resolve_operation_error(event_ptr, handle)
|
|
21
|
+
|
|
22
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
|
23
|
+
|
|
24
|
+
# Parsing must copy everything out of event-owned memory before the event is destroyed.
|
|
25
|
+
# An exception here is captured and re-raised on the waiting thread, since it cannot
|
|
26
|
+
# unwind through librdkafka native frames.
|
|
27
|
+
handle.result = begin
|
|
28
|
+
Rdkafka::Admin::DeleteRecordsReport.new(result_ptr)
|
|
29
|
+
rescue => e
|
|
30
|
+
e
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
handle.unlock
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rdkafka
|
|
4
|
+
module Callbacks
|
|
5
|
+
# Handles `RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT` events
|
|
6
|
+
# @private
|
|
7
|
+
class ListConsumerGroupsHandler < BaseHandler
|
|
8
|
+
class << self
|
|
9
|
+
# Resolves the list-consumer-groups handle from its result event
|
|
10
|
+
# @param event_ptr [FFI::Pointer] pointer to the event
|
|
11
|
+
# @return [void]
|
|
12
|
+
def call(event_ptr)
|
|
13
|
+
result_ptr = Rdkafka::Bindings.rd_kafka_event_ListConsumerGroups_result(event_ptr)
|
|
14
|
+
handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
|
|
15
|
+
|
|
16
|
+
return unless (handle = Rdkafka::Admin::ListConsumerGroupsHandle.remove(handle_ptr.address))
|
|
17
|
+
|
|
18
|
+
# An operation-level error (e.g. timeout or a closed client) is delivered on the event
|
|
19
|
+
# itself; per the source feature's all-or-nothing contract we surface it as the result
|
|
20
|
+
# rather than returning a partial listing.
|
|
21
|
+
return if resolve_operation_error(event_ptr, handle)
|
|
22
|
+
|
|
23
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
|
|
24
|
+
|
|
25
|
+
# Parsing must copy everything out of event-owned memory before the event is destroyed.
|
|
26
|
+
# An exception here is captured and re-raised on the waiting thread, since it cannot
|
|
27
|
+
# unwind through librdkafka native frames.
|
|
28
|
+
handle.result = begin
|
|
29
|
+
Rdkafka::Admin::ListConsumerGroupsReport.new(result_ptr)
|
|
30
|
+
rescue => e
|
|
31
|
+
e
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
handle.unlock
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/rdkafka/callbacks.rb
CHANGED
|
@@ -213,12 +213,14 @@ module Rdkafka
|
|
|
213
213
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETETOPICS_RESULT then DeleteTopicHandler
|
|
214
214
|
when Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS_RESULT then CreatePartitionsHandler
|
|
215
215
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEGROUPS_RESULT then DeleteGroupsHandler
|
|
216
|
+
when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETERECORDS_RESULT then DeleteRecordsHandler
|
|
216
217
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_CREATEACLS_RESULT then CreateAclHandler
|
|
217
218
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEACLS_RESULT then DeleteAclHandler
|
|
218
219
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_DESCRIBEACLS_RESULT then DescribeAclHandler
|
|
219
220
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_DESCRIBECONFIGS_RESULT then DescribeConfigsHandler
|
|
220
221
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_INCREMENTALALTERCONFIGS_RESULT then IncrementalAlterConfigsHandler
|
|
221
222
|
when Rdkafka::Bindings::RD_KAFKA_EVENT_LISTOFFSETS_RESULT then ListOffsetsHandler
|
|
223
|
+
when Rdkafka::Bindings::RD_KAFKA_EVENT_LISTCONSUMERGROUPS_RESULT then ListConsumerGroupsHandler
|
|
222
224
|
end
|
|
223
225
|
|
|
224
226
|
handler&.call(event_ptr)
|
|
@@ -280,9 +282,9 @@ module Rdkafka
|
|
|
280
282
|
end
|
|
281
283
|
end
|
|
282
284
|
|
|
283
|
-
#
|
|
285
|
+
# @!visibility private
|
|
284
286
|
@@mutex = Mutex.new
|
|
285
|
-
#
|
|
287
|
+
# @!visibility private
|
|
286
288
|
@@current_pid = nil
|
|
287
289
|
|
|
288
290
|
class << self
|