rdkafka 0.29.2 → 0.30.0

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: f2acf73116281ea22d96af51b56fecc615cb32616d25834a5a990fae1213a1ba
4
- data.tar.gz: 04c06f93561b22719261fab54fc0191f1a6edba01926596124f430adcc11d7d5
3
+ metadata.gz: 9a5ff1b8b0535c2a9781c7a629907b034e372fd69707895be94867aacdf70c69
4
+ data.tar.gz: 8594c653516b17b414ff6c1e02709d1f00e776caa497980c699cb2ac8ea131d0
5
5
  SHA512:
6
- metadata.gz: 7ea74276532d8cd48ee913a46166497ace6426bd8859eb41d72f5407bc5a1eb4273bbe2d82a793618e3420a956b95a86919e416c46e0ac657d8b8056167dcdc0
7
- data.tar.gz: 20e3c8ac1bb1113673f5af90e977dc3e59e6e6b9f9b0b550e1f6b1a9796bd19b1915d8ba8e345e5cfb0e574d61e8fe354788e0f3445ee0333a8634c7f81e4d97
6
+ metadata.gz: 88d5515df49496899ecbb474ed379b2405b4aacbf8a7cd2c10b9356276bdeb862091a450b87713dca495d4101e585717b459a96b2a1bdffb55ef80caf948165e
7
+ data.tar.gz: 17743522771d227ad2f729a87a6c6976322908221cbebb74b5af7a46d7218cf7e2775bda7b031ace347ceccad1f20d7035c486b23cc6158c1d5ed29e2ecee56e
data/CHANGELOG.md CHANGED
@@ -1,11 +1,25 @@
1
1
  # Rdkafka Changelog
2
2
 
3
+ ## 0.30.0 (2026-09-25)
4
+ - [Feature] Add `Admin#alter_consumer_group_offsets` and `Admin#delete_consumer_group_offsets` to set or clear a consumer group's committed offsets from the admin client.
5
+ - [Enhancement] Bump the bundled zlib to `1.3.2`.
6
+ - [Enhancement] Bump librdkafka to `2.15.0`.
7
+ - [Enhancement] Bump the bundled MIT Kerberos (krb5) to `1.22.2`.
8
+ - [Enhancement] Add `Rdkafka::Config.partitioner_key_uses_bytesize` to hash partition keys by byte length, matching other Kafka clients for multibyte keys. Defaults to `false`.
9
+ - [Maintenance] Derive the zlib `CHECKSUMS` entry from `ZLIB_VERSION`.
10
+ - [Maintenance] Drop the unused `dist/openssl-3.0.16.tar.gz` build cache.
11
+ - [Fix] Honor the `isolation_level:` argument to `Admin#list_offsets`, which was silently ignored.
12
+ - [Fix] Return correct results for every item of a multi-item topic, partition, group or ACL admin request, not just the first.
13
+ - [Maintenance] Fix a use-after-free in the multi-item admin integration test that read result-name pointers after librdkafka had destroyed the background event, which made it flaky on newer glibc (e.g. Debian trixie).
14
+ - [Maintenance] Stabilize consumer specs on slow CI runners: wait longer for a partition assignment, raise the `TestTopics.create` admin timeout (a timeout there also tripped the leaked-handle guard), and let the long-running consumption spec drain its backlog instead of stopping at a fixed 60s.
15
+ - [Maintenance] Raise the `TestTopics.create` admin timeout to 30s so a loaded CI runner no longer hits `create topic timed out` (which also tripped the leaked-handle guard).
16
+
3
17
  ## 0.29.2 (2026-09-11)
4
18
  - [Fix] Close live clients from an `at_exit` hook before Ruby's shutdown finalization, so librdkafka is no longer `dlclose`d while its native threads are still running (which could segfault on exit).
5
19
  - [Fix] Make client construction exception-safe and destroy the native handle when setup fails after `rd_kafka_new`, so a later error no longer orphans the native client.
6
- - [Fix] Destroy each polled message exactly once in `Consumer#poll_batch`/`#poll_batch_nb` when building a message raises a non-`RdkafkaError`, fixing a double-free that could abort the process and closing the matching leak window.
7
- - [Fix] Free the background queue, `AdminOptions` and any already-built `ConfigResource`s (and remove the handle) when `Admin#describe_configs`/`#incremental_alter_configs` raise while building native resources (e.g. a non-String resource name).
8
- - [Fix] Raise a clear `ConfigError` instead of segfaulting when `Admin#describe_configs`/`#incremental_alter_configs` are given an empty resource name or a negative resource type (`rd_kafka_ConfigResource_new` returns NULL), or when `rd_kafka_AdminOptions_new` returns NULL.
20
+ - [Fix] Fix a double-free in `Consumer#poll_batch`/`#poll_batch_nb` that could abort the process when building a message raised a non-`RdkafkaError`.
21
+ - [Fix] Free native resources when `Admin#describe_configs`/`#incremental_alter_configs` raise while building their request (e.g. a non-String resource name).
22
+ - [Fix] Raise `ConfigError` instead of segfaulting when `Admin#describe_configs`/`#incremental_alter_configs` get an empty resource name or a negative resource type.
9
23
 
10
24
  ## 0.29.1 (2026-09-04)
11
25
  - [Enhancement] Add `Admin#delete_records` to delete all messages in a partition up to a given offset.
@@ -19,8 +33,8 @@
19
33
 
20
34
  ## 0.29.0 (2026-07-10)
21
35
  - [Enhancement] Bump librdkafka to `2.14.2`
22
- - [Enhancement] Add `Consumer#metadata` and `Producer#metadata`, mirroring `Admin#metadata`, so cluster/topic metadata can be fetched from an existing consumer or producer handle without opening a dedicated admin connection.
23
- - [Enhancement] Support offset-commit metadata: `Consumer#store_offset(message, metadata)` stores an optional metadata string alongside the offset, `Consumer::Partition#metadata` exposes it, and `TopicPartitionList` marshals it to and from the native list (read back via `Consumer#committed`).
36
+ - [Enhancement] Add `Consumer#metadata` and `Producer#metadata`, mirroring `Admin#metadata`, to fetch cluster metadata without a separate admin connection.
37
+ - [Enhancement] Support offset-commit metadata via `Consumer#store_offset(message, metadata)`, readable through `Consumer::Partition#metadata` and `Consumer#committed`.
24
38
  - [Enhancement] Expose `replicas` and `isrs` (in-sync replica broker ids) on each partition in topic metadata; both were previously dropped from the `Metadata#topics` partition hashes.
25
39
  - [Enhancement] Extract the admin background-event result handlers into one class per operation under `lib/rdkafka/callbacks/`. Internal reorganization with no API or behavior change.
26
40
  - [Enhancement] Reuse per-thread scratch pointers in `Consumer::Headers.from_native`, removing the per-message native allocations from the consumer hot path.
@@ -28,32 +42,32 @@
28
42
  - [Fix] Cache the partition count for a missing topic, so `produce` with a `partition_key` to a missing topic no longer re-runs a blocking metadata query on every message.
29
43
  - [Fix] Let `PartitionsCountCache` adopt a lower partition count once the cached entry has expired, so a topic recreated with fewer partitions no longer fails `produce` until process restart.
30
44
  - [Fix] Surface per-message build errors inline in `Consumer#poll_batch`/`#poll_batch_nb` instead of discarding the batch, preserving the messages that built successfully.
31
- - [Fix] Bound the `Metadata` retry loop by a ~5s wall-clock budget with a floor of 3 attempts, cap the backoff at 1s, and stop overwriting the request timeout with the backoff value, which could block a synchronous fetch for minutes.
45
+ - [Fix] Bound the `Metadata` retry loop to about 5 seconds, so a synchronous metadata fetch can no longer block for minutes.
32
46
  - [Fix] Synchronize `AbstractHandle::REGISTRY` mutations with a mutex, which could otherwise lose a write on JRuby and leave a handle unregistered or leaked.
33
- - [Fix] Fix the NULL background-queue cleanup branches in `Admin#delete_group`, `Admin#delete_acl` and `Admin#describe_acl`, which raised a `NameError` and leaked the native request object instead of raising `ConfigError`.
47
+ - [Fix] Raise `ConfigError` instead of `NameError` in `Admin#delete_group`, `#delete_acl` and `#describe_acl` when the background queue is unavailable.
34
48
  - [Fix] Actually populate `ConfigBindingResult#synonyms`. The synonym loop built the synonym binding objects and discarded them, so `#synonyms` was always an empty array; they are now appended.
35
49
  - [Fix] Stop leaking the native `rd_kafka_topic_conf_t` in `Producer#set_topic_config` when a per-topic config value is rejected.
36
- - [Fix] Add the missing `closed_consumer_check` to `Consumer#position`, the only public consumer method without one; calling it on a closed consumer now raises a consistent `ClosedConsumerError` instead of failing deeper in the call.
50
+ - [Fix] Raise `ClosedConsumerError` from `Consumer#position` on a closed consumer, like the other consumer methods.
37
51
  - [Fix] Guard the OAuthBearer token refresh callback against a NULL client pointer before calling `rd_kafka_name` on it.
38
- - [Fix] Make the `Consumer` GC finalizer close the consumer and destroy its consumer queue, not just the native client, preventing a hang or leak when a consumer is collected without an explicit `close`.
52
+ - [Fix] Fully close a consumer collected without an explicit `close`, preventing a hang or leak.
39
53
  - [Fix] Free the librdkafka-allocated string in `Consumer#cluster_id` and `Consumer#member_id`, and fix the `rd_kafka_clusterid` arity. `Consumer#cluster_id` now accepts a `timeout_ms`.
40
54
  - [Fix] Attach `rd_kafka_query_watermark_offsets` with `blocking: true` so it releases the GVL; it previously froze every other Ruby thread for up to `timeout_ms`.
41
55
  - [Fix] Stop leaking the native `rd_kafka_conf_t` when client creation fails, a multi-KB leak per failed attempt for supervisors retrying on transient SASL/SSL misconfiguration.
42
56
  - [Fix] Stop `Metadata` from leaking the native metadata struct on every retried fetch; each attempt now frees its own native resources.
43
57
  - [Fix] Stop `Producer#produce` from orphaning the delivery handle in the process-global registry when it fails after registering it.
44
58
  - [Fix] Guard the message delivery callback so a raising user `delivery_callback` can no longer leave the handle locked or crash the producer; exceptions are now logged and swallowed.
45
- - [Fix] Stop `describe_configs`, `incremental_alter_configs` and `list_offsets` from leaking handles and native resources when their arguments are rejected; all three now validate input before allocating.
46
- - [Fix] Destroy the native topic-partition list in `TopicPartitionList#to_native_tpl` when population fails partway (e.g. an invalid partition). The caller-owned list was leaked on any exception mid-build; it is now destroyed before the error propagates.
59
+ - [Fix] Stop `describe_configs`, `incremental_alter_configs` and `list_offsets` from leaking native resources when their arguments are rejected.
60
+ - [Fix] Stop `TopicPartitionList#to_native_tpl` from leaking the native list when building it fails partway.
47
61
  - [Fix] Raise instead of silently dropping a rejected `incremental_alter_configs` entry, which previously left the alter request reporting success.
48
62
  - [Fix] Allocate the admin result-count out-parameter as `:size_t` instead of `:int32`, fixing a 4-byte overflow on every admin result parse.
49
63
  - [Fix] Stabilize the flaky `Consumer#lag` "calculates the consumer lag" spec on overloaded CI.
50
- - [Fix] Resolve admin operation handles from the event error when an operation fails at the operation level (e.g. brokers unreachable), instead of blocking until `wait` timed out and discarding the real error.
51
- - [Fix] Destroy admin API background events after processing; they were never destroyed, so every admin operation leaked its whole result event. The internal FFI struct fields on admin handles were removed as part of this - use `handle.wait` and the returned report objects, whose interfaces are unchanged.
64
+ - [Fix] Return the real error from an admin operation that fails at the operation level (e.g. brokers unreachable) instead of blocking until `wait` times out.
65
+ - [Fix] Stop every admin operation from leaking its result event. The internal FFI struct fields on admin handles are removed; use `handle.wait` and the returned report objects, which are unchanged.
52
66
 
53
67
  ## 0.28.0 (2026-06-03)
54
68
  - [Enhancement] Bump librdkafka to `2.14.1`
55
69
  - [Enhancement] Replace version-gated `Warning[:performance]` with dynamic `Warning.categories` opt-in in spec helper so new Ruby warning categories are automatically enabled without manual updates.
56
- - [Enhancement] `poll_batch` and `poll_batch_nb` now return error events inline as `RdkafkaError` objects rather than raising on the first error. The return type is `Array<Message, RdkafkaError>` and callers are responsible for handling errors in the result.
70
+ - [Enhancement] `poll_batch` and `poll_batch_nb` now return errors inline as `RdkafkaError` objects instead of raising on the first one. The return type is `Array<Message, RdkafkaError>`, so callers must handle errors in the result.
57
71
 
58
72
  ## 0.27.0 (2026-05-07)
59
73
  - [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`.
data/README.md CHANGED
@@ -163,6 +163,7 @@ bundle exec rake produce_messages
163
163
 
164
164
  | rdkafka-ruby | librdkafka | patches |
165
165
  |-|-|-|
166
+ | 0.30.x (2026-09-25) | 2.15.0 (2026-06-30) | yes |
166
167
  | 0.29.x (2026-07-10) | 2.14.2 (2026-06-03) | yes |
167
168
  | 0.28.x (2026-06-03) | 2.14.1 (2026-04-15) | yes |
168
169
  | 0.27.x (2026-05-07) | 2.14.0 (2026-04-01) | yes |
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ class Admin
5
+ # Handle for alter consumer group offsets operation
6
+ class AlterConsumerGroupOffsetsHandle < AbstractHandle
7
+ layout :pending, :bool,
8
+ :response, :int
9
+
10
+ # @return [String] the name of the operation
11
+ def operation_name
12
+ "alter consumer group offsets"
13
+ end
14
+
15
+ # Creates the result report
16
+ # @return [AlterConsumerGroupOffsetsReport]
17
+ def create_result
18
+ prepared_result
19
+ end
20
+
21
+ # Raises an error if the operation failed
22
+ # @raise [RdkafkaError]
23
+ def raise_error
24
+ raise RdkafkaError.new(
25
+ self[:response],
26
+ broker_message: broker_message
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ class Admin
5
+ # Report for alter consumer group offsets operation result
6
+ class AlterConsumerGroupOffsetsReport
7
+ # @return [String, nil] the group the operation ran against
8
+ attr_reader :group_name
9
+
10
+ # @return [String, nil] group level error message, if any
11
+ attr_reader :error_string
12
+
13
+ # Per partition outcomes, each with `:topic`, `:partition`, `:offset` and `:error`
14
+ # (an `RdkafkaError` or nil). Partitions are reported individually because Kafka can
15
+ # fail some and accept others within a single request.
16
+ # @return [Array<Hash>]
17
+ attr_reader :partitions
18
+
19
+ # @param error_string [FFI::Pointer] pointer to the group level error string
20
+ # @param result_name [FFI::Pointer] pointer to the group name
21
+ # @param partitions_ptr [FFI::Pointer] pointer to the per partition result list
22
+ def initialize(error_string, result_name, partitions_ptr = FFI::Pointer::NULL)
23
+ @error_string = error_string.read_string if error_string != FFI::Pointer::NULL
24
+ @group_name = result_name.read_string if result_name != FFI::Pointer::NULL
25
+ @partitions = extract_partitions(partitions_ptr)
26
+ end
27
+
28
+ private
29
+
30
+ # @param partitions_ptr [FFI::Pointer] pointer to a native topic partition list
31
+ # @return [Array<Hash>]
32
+ def extract_partitions(partitions_ptr)
33
+ return [] if partitions_ptr.nil? || partitions_ptr.null?
34
+
35
+ native = Bindings::TopicPartitionList.new(partitions_ptr)
36
+
37
+ Array.new(native[:cnt]) do |i|
38
+ tp = Bindings::TopicPartition.new(native[:elems] + (i * Bindings::TopicPartition.size))
39
+
40
+ {
41
+ topic: tp[:topic],
42
+ partition: tp[:partition],
43
+ offset: tp[:offset],
44
+ error: tp[:err].zero? ? nil : RdkafkaError.new(tp[:err])
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ class Admin
5
+ # Handle for delete consumer group offsets operation
6
+ class DeleteConsumerGroupOffsetsHandle < AbstractHandle
7
+ layout :pending, :bool,
8
+ :response, :int
9
+
10
+ # @return [String] the name of the operation
11
+ def operation_name
12
+ "delete consumer group offsets"
13
+ end
14
+
15
+ # Creates the result report
16
+ # @return [DeleteConsumerGroupOffsetsReport]
17
+ def create_result
18
+ prepared_result
19
+ end
20
+
21
+ # Raises an error if the operation failed
22
+ # @raise [RdkafkaError]
23
+ def raise_error
24
+ raise RdkafkaError.new(
25
+ self[:response],
26
+ broker_message: broker_message
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ class Admin
5
+ # Report for delete consumer group offsets operation result
6
+ class DeleteConsumerGroupOffsetsReport
7
+ # @return [String, nil] the group the operation ran against
8
+ attr_reader :group_name
9
+
10
+ # @return [String, nil] group level error message, if any
11
+ attr_reader :error_string
12
+
13
+ # Per partition outcomes, each with `:topic`, `:partition`, `:offset` and `:error`
14
+ # (an `RdkafkaError` or nil). Partitions are reported individually because Kafka can
15
+ # fail some and accept others within a single request.
16
+ # @return [Array<Hash>]
17
+ attr_reader :partitions
18
+
19
+ # @param error_string [FFI::Pointer] pointer to the group level error string
20
+ # @param result_name [FFI::Pointer] pointer to the group name
21
+ # @param partitions_ptr [FFI::Pointer] pointer to the per partition result list
22
+ def initialize(error_string, result_name, partitions_ptr = FFI::Pointer::NULL)
23
+ @error_string = error_string.read_string if error_string != FFI::Pointer::NULL
24
+ @group_name = result_name.read_string if result_name != FFI::Pointer::NULL
25
+ @partitions = extract_partitions(partitions_ptr)
26
+ end
27
+
28
+ private
29
+
30
+ # @param partitions_ptr [FFI::Pointer] pointer to a native topic partition list
31
+ # @return [Array<Hash>]
32
+ def extract_partitions(partitions_ptr)
33
+ return [] if partitions_ptr.nil? || partitions_ptr.null?
34
+
35
+ native = Bindings::TopicPartitionList.new(partitions_ptr)
36
+
37
+ Array.new(native[:cnt]) do |i|
38
+ tp = Bindings::TopicPartition.new(native[:elems] + (i * Bindings::TopicPartition.size))
39
+
40
+ {
41
+ topic: tp[:topic],
42
+ partition: tp[:partition],
43
+ offset: tp[:offset],
44
+ error: tp[:err].zero? ? nil : RdkafkaError.new(tp[:err])
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
data/lib/rdkafka/admin.rb CHANGED
@@ -224,6 +224,78 @@ module Rdkafka
224
224
  create_topic_handle
225
225
  end
226
226
 
227
+ # Sets the committed offsets of a consumer group from outside the group.
228
+ #
229
+ # Kafka requires the group to be empty (no active members) for this to be accepted; when it
230
+ # is not, the broker rejects the request and the handle raises with `group_not_empty` rather
231
+ # than reporting success.
232
+ #
233
+ # @param group_id [String] the group whose offsets we want to set
234
+ # @param topic_partition_list [TopicPartitionList] partitions with the offsets to commit
235
+ # @return [AlterConsumerGroupOffsetsHandle] handle that can be used to wait for the result
236
+ # @raise [RdkafkaError] when altering the offsets fails
237
+ def alter_consumer_group_offsets(group_id, topic_partition_list)
238
+ closed_admin_check(__method__)
239
+
240
+ native_tpl = topic_partition_list.to_native_tpl
241
+
242
+ begin
243
+ alter_ptr = Rdkafka::Bindings.rd_kafka_AlterConsumerGroupOffsets_new(
244
+ FFI::MemoryPointer.from_string(group_id),
245
+ native_tpl
246
+ )
247
+ rescue Exception
248
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
249
+ raise
250
+ end
251
+
252
+ # librdkafka copies the list into the request object, so ours is no longer needed
253
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
254
+
255
+ enqueue_group_offsets_op(
256
+ request_ptr: alter_ptr,
257
+ handle: AlterConsumerGroupOffsetsHandle.new,
258
+ admin_op: Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_ALTERCONSUMERGROUPOFFSETS,
259
+ destroy: Rdkafka::Bindings.method(:rd_kafka_AlterConsumerGroupOffsets_destroy),
260
+ enqueue: Rdkafka::Bindings.method(:rd_kafka_AlterConsumerGroupOffsets)
261
+ )
262
+ end
263
+
264
+ # Deletes the committed offsets of specific partitions of a consumer group, leaving the
265
+ # group and its remaining offsets in place.
266
+ #
267
+ # This is the partition scoped counterpart of {#delete_group}, which removes the whole group.
268
+ #
269
+ # @param group_id [String] the group whose offsets we want to delete
270
+ # @param topic_partition_list [TopicPartitionList] partitions whose offsets to delete
271
+ # @return [DeleteConsumerGroupOffsetsHandle] handle that can be used to wait for the result
272
+ # @raise [RdkafkaError] when deleting the offsets fails
273
+ def delete_consumer_group_offsets(group_id, topic_partition_list)
274
+ closed_admin_check(__method__)
275
+
276
+ native_tpl = topic_partition_list.to_native_tpl
277
+
278
+ begin
279
+ delete_ptr = Rdkafka::Bindings.rd_kafka_DeleteConsumerGroupOffsets_new(
280
+ FFI::MemoryPointer.from_string(group_id),
281
+ native_tpl
282
+ )
283
+ rescue Exception
284
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
285
+ raise
286
+ end
287
+
288
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(native_tpl)
289
+
290
+ enqueue_group_offsets_op(
291
+ request_ptr: delete_ptr,
292
+ handle: DeleteConsumerGroupOffsetsHandle.new,
293
+ admin_op: Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETECONSUMERGROUPOFFSETS,
294
+ destroy: Rdkafka::Bindings.method(:rd_kafka_DeleteConsumerGroupOffsets_destroy),
295
+ enqueue: Rdkafka::Bindings.method(:rd_kafka_DeleteConsumerGroupOffsets)
296
+ )
297
+ end
298
+
227
299
  # Deletes a consumer group
228
300
  #
229
301
  # @param group_id [String] the group id to delete
@@ -1139,6 +1211,54 @@ module Rdkafka
1139
1211
 
1140
1212
  private
1141
1213
 
1214
+ # Shared enqueue path for the two consumer group offset admin operations. They differ only
1215
+ # in their C entry points, so keeping one body avoids two near identical copies of the
1216
+ # queue/handle/options dance and its cleanup.
1217
+ #
1218
+ # @param request_ptr [FFI::Pointer] the op specific request object
1219
+ # @param handle [AbstractHandle] the handle to register and return
1220
+ # @param admin_op [Integer] the RD_KAFKA_ADMIN_OP_* constant for this operation
1221
+ # @param destroy [Method] bound function used to free the request object
1222
+ # @param enqueue [Method] bound function used to enqueue the request
1223
+ # @return [AbstractHandle] the registered handle
1224
+ def enqueue_group_offsets_op(request_ptr:, handle:, admin_op:, destroy:, enqueue:)
1225
+ array_ptr = FFI::MemoryPointer.new(:pointer)
1226
+ array_ptr.write_array_of_pointer([request_ptr])
1227
+
1228
+ queue_ptr = @native_kafka.with_inner do |inner|
1229
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
1230
+ end
1231
+
1232
+ if queue_ptr.null?
1233
+ destroy.call(request_ptr)
1234
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
1235
+ end
1236
+
1237
+ handle[:pending] = true
1238
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
1239
+ handle.class.register(handle)
1240
+
1241
+ admin_options_ptr = @native_kafka.with_inner do |inner|
1242
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, admin_op)
1243
+ end
1244
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
1245
+
1246
+ begin
1247
+ @native_kafka.with_inner do |inner|
1248
+ enqueue.call(inner, array_ptr, 1, admin_options_ptr, queue_ptr)
1249
+ end
1250
+ rescue Exception
1251
+ handle.class.remove(handle.to_ptr.address)
1252
+ raise
1253
+ ensure
1254
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
1255
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
1256
+ destroy.call(request_ptr)
1257
+ end
1258
+
1259
+ handle
1260
+ end
1261
+
1142
1262
  # Checks if the admin is closed and raises an error if so
1143
1263
  # @param method [Symbol] name of the calling method for error context
1144
1264
  # @raise [ClosedAdminError] when the admin is closed
@@ -192,7 +192,7 @@ module Rdkafka
192
192
  RD_KAFKA_ALTER_CONFIG_OP_TYPE_SUBTRACT = 3
193
193
 
194
194
  # List Offsets
195
- RD_KAFKA_ADMIN_OP_LISTOFFSETS = 20
195
+ RD_KAFKA_ADMIN_OP_LISTOFFSETS = 21
196
196
  RD_KAFKA_EVENT_LISTOFFSETS_RESULT = 0x400000
197
197
 
198
198
  # rd_kafka_IsolationLevel_t
@@ -503,9 +503,31 @@ module Rdkafka
503
503
  raise Rdkafka::Config::ConfigError.new("Unknown partitioner: #{partitioner}")
504
504
  end
505
505
 
506
- public_send(method_name, topic_ptr, str_ptr, str.size, partition_count, nil, nil)
506
+ public_send(method_name, topic_ptr, str_ptr, partition_key_length(str), partition_count, nil, nil)
507
507
  end
508
508
 
509
+ # Partition key length as the character count (legacy default).
510
+ #
511
+ # @param str [String] the partition key string
512
+ # @return [Integer]
513
+ def self.partition_key_size(str)
514
+ str.size
515
+ end
516
+
517
+ # Partition key length as the byte count, which is what librdkafka hashes (UTF-8 bytes copied
518
+ # into the key pointer) and what other Kafka clients use.
519
+ #
520
+ # @param str [String] the partition key string
521
+ # @return [Integer]
522
+ def self.partition_key_bytesize(str)
523
+ str.bytesize
524
+ end
525
+
526
+ # Length of the partition key passed to librdkafka. Aliased to one of the methods above by
527
+ # `Rdkafka::Config.partitioner_key_uses_bytesize=`, so the per-message path does not check the
528
+ # setting on every call.
529
+ singleton_class.alias_method :partition_key_length, :partition_key_size
530
+
509
531
  # Create Topics
510
532
  RD_KAFKA_ADMIN_OP_CREATETOPICS = 1 # rd_kafka_admin_op_t
511
533
  RD_KAFKA_EVENT_CREATETOPICS_RESULT = 100 # rd_kafka_event_type_t
@@ -547,6 +569,26 @@ module Rdkafka
547
569
  attach_function :rd_kafka_event_DeleteGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteGroups_result_t*
548
570
  attach_function :rd_kafka_DeleteGroups_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_DeleteGroups_result_t*, size_t* => rd_kafka_group_result_t**
549
571
 
572
+ # Alter Consumer Group Offsets
573
+ RD_KAFKA_ADMIN_OP_ALTERCONSUMERGROUPOFFSETS = 15 # rd_kafka_admin_op_t
574
+ RD_KAFKA_EVENT_ALTERCONSUMERGROUPOFFSETS_RESULT = 0x10000 # rd_kafka_event_type_t
575
+
576
+ attach_function :rd_kafka_AlterConsumerGroupOffsets, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
577
+ attach_function :rd_kafka_AlterConsumerGroupOffsets_new, [:pointer, :pointer], :pointer, blocking: true # const char*, const rd_kafka_topic_partition_list_t* => rd_kafka_AlterConsumerGroupOffsets_t*
578
+ attach_function :rd_kafka_AlterConsumerGroupOffsets_destroy, [:pointer], :void, blocking: true
579
+ attach_function :rd_kafka_event_AlterConsumerGroupOffsets_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_AlterConsumerGroupOffsets_result_t*
580
+ attach_function :rd_kafka_AlterConsumerGroupOffsets_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_AlterConsumerGroupOffsets_result_t*, size_t* => rd_kafka_group_result_t**
581
+
582
+ # Delete Consumer Group Offsets
583
+ RD_KAFKA_ADMIN_OP_DELETECONSUMERGROUPOFFSETS = 8 # rd_kafka_admin_op_t
584
+ RD_KAFKA_EVENT_DELETECONSUMERGROUPOFFSETS_RESULT = 107 # rd_kafka_event_type_t
585
+
586
+ attach_function :rd_kafka_DeleteConsumerGroupOffsets, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
587
+ attach_function :rd_kafka_DeleteConsumerGroupOffsets_new, [:pointer, :pointer], :pointer, blocking: true # const char*, const rd_kafka_topic_partition_list_t* => rd_kafka_DeleteConsumerGroupOffsets_t*
588
+ attach_function :rd_kafka_DeleteConsumerGroupOffsets_destroy, [:pointer], :void, blocking: true
589
+ attach_function :rd_kafka_event_DeleteConsumerGroupOffsets_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteConsumerGroupOffsets_result_t*
590
+ attach_function :rd_kafka_DeleteConsumerGroupOffsets_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_DeleteConsumerGroupOffsets_result_t*, size_t* => rd_kafka_group_result_t**
591
+
550
592
  # Delete Records
551
593
  RD_KAFKA_ADMIN_OP_DELETERECORDS = 6 # rd_kafka_admin_op_t
552
594
  RD_KAFKA_EVENT_DELETERECORDS_RESULT = 105 # rd_kafka_event_type_t
@@ -696,5 +738,6 @@ module Rdkafka
696
738
 
697
739
  attach_function :rd_kafka_group_result_error, [:pointer], NativeError.by_ref # rd_kafka_group_result_t* => rd_kafka_error_t*
698
740
  attach_function :rd_kafka_group_result_name, [:pointer], :pointer
741
+ attach_function :rd_kafka_group_result_partitions, [:pointer], :pointer # rd_kafka_group_result_t* => rd_kafka_topic_partition_list_t*
699
742
  end
700
743
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ module Callbacks
5
+ # Handles `RD_KAFKA_EVENT_ALTERCONSUMERGROUPOFFSETS_RESULT` events
6
+ # @private
7
+ class AlterConsumerGroupOffsetsHandler < BaseHandler
8
+ class << self
9
+ # Resolves the alter consumer group offsets 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 = Rdkafka::Bindings.rd_kafka_event_AlterConsumerGroupOffsets_result(event_ptr)
14
+
15
+ pointer_to_size_t = FFI::MemoryPointer.new(:size_t)
16
+ group_result_array = Rdkafka::Bindings.rd_kafka_AlterConsumerGroupOffsets_result_groups(result, pointer_to_size_t)
17
+ group_results = GroupResult.create_group_results_from_array(pointer_to_size_t.read_int, group_result_array)
18
+ handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
19
+
20
+ if (handle = Rdkafka::Admin::AlterConsumerGroupOffsetsHandle.remove(handle_ptr.address))
21
+ unless resolve_operation_error(event_ptr, handle)
22
+ group_result = group_results[0]
23
+
24
+ # librdkafka only supports one group per invocation, so a missing group result
25
+ # means the broker returned nothing to act on rather than a partial success.
26
+ if group_result.nil?
27
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
28
+ handle.result = Rdkafka::Admin::AlterConsumerGroupOffsetsReport.new(
29
+ FFI::Pointer::NULL,
30
+ FFI::Pointer::NULL
31
+ )
32
+ else
33
+ report = Rdkafka::Admin::AlterConsumerGroupOffsetsReport.new(
34
+ group_result.error_string,
35
+ group_result.result_name,
36
+ Rdkafka::Bindings.rd_kafka_group_result_partitions(group_result_array.read_pointer)
37
+ )
38
+ handle.result = report
39
+
40
+ # Kafka reports a rejected offset change per partition, leaving the group level
41
+ # error unset - a group with live members comes back with the group error NULL
42
+ # and `unknown_member_id` on each partition. Resolving on the group error alone
43
+ # would hand back a report that looks like success, so any failed partition has
44
+ # to fail the handle too.
45
+ failed = report.partitions.find { |partition| partition[:error] }
46
+
47
+ if !group_result.result_error.zero?
48
+ handle[:response] = group_result.result_error
49
+ handle.broker_message = report.error_string
50
+ elsif failed
51
+ handle[:response] = failed[:error].rdkafka_response
52
+ handle.broker_message = "Failed for partition #{failed[:partition]} of '#{failed[:topic]}'"
53
+ else
54
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
55
+ end
56
+ end
57
+
58
+ handle.unlock
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rdkafka
4
+ module Callbacks
5
+ # Handles `RD_KAFKA_EVENT_DELETECONSUMERGROUPOFFSETS_RESULT` events
6
+ # @private
7
+ class DeleteConsumerGroupOffsetsHandler < BaseHandler
8
+ class << self
9
+ # Resolves the delete consumer group offsets 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 = Rdkafka::Bindings.rd_kafka_event_DeleteConsumerGroupOffsets_result(event_ptr)
14
+
15
+ pointer_to_size_t = FFI::MemoryPointer.new(:size_t)
16
+ group_result_array = Rdkafka::Bindings.rd_kafka_DeleteConsumerGroupOffsets_result_groups(result, pointer_to_size_t)
17
+ group_results = GroupResult.create_group_results_from_array(pointer_to_size_t.read_int, group_result_array)
18
+ handle_ptr = Rdkafka::Bindings.rd_kafka_event_opaque(event_ptr)
19
+
20
+ if (handle = Rdkafka::Admin::DeleteConsumerGroupOffsetsHandle.remove(handle_ptr.address))
21
+ unless resolve_operation_error(event_ptr, handle)
22
+ group_result = group_results[0]
23
+
24
+ # librdkafka only supports one group per invocation, so a missing group result
25
+ # means the broker returned nothing to act on rather than a partial success.
26
+ if group_result.nil?
27
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
28
+ handle.result = Rdkafka::Admin::DeleteConsumerGroupOffsetsReport.new(
29
+ FFI::Pointer::NULL,
30
+ FFI::Pointer::NULL
31
+ )
32
+ else
33
+ report = Rdkafka::Admin::DeleteConsumerGroupOffsetsReport.new(
34
+ group_result.error_string,
35
+ group_result.result_name,
36
+ Rdkafka::Bindings.rd_kafka_group_result_partitions(group_result_array.read_pointer)
37
+ )
38
+ handle.result = report
39
+
40
+ # Kafka reports a rejected offset change per partition, leaving the group level
41
+ # error unset - a group with live members comes back with the group error NULL
42
+ # and `unknown_member_id` on each partition. Resolving on the group error alone
43
+ # would hand back a report that looks like success, so any failed partition has
44
+ # to fail the handle too.
45
+ failed = report.partitions.find { |partition| partition[:error] }
46
+
47
+ if !group_result.result_error.zero?
48
+ handle[:response] = group_result.result_error
49
+ handle.broker_message = report.error_string
50
+ elsif failed
51
+ handle[:response] = failed[:error].rdkafka_response
52
+ handle.broker_message = "Failed for partition #{failed[:partition]} of '#{failed[:topic]}'"
53
+ else
54
+ handle[:response] = Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR
55
+ end
56
+ end
57
+
58
+ handle.unlock
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -21,10 +21,9 @@ module Rdkafka
21
21
  # @param array_pointer [FFI::Pointer] pointer to the results array
22
22
  # @return [Array<TopicResult>] array of topic results
23
23
  def self.create_topic_results_from_array(count, array_pointer)
24
- (1..count).map do |index|
25
- result_pointer = (array_pointer + (index - 1)).read_pointer
26
- new(result_pointer)
27
- end
24
+ return [] if count.zero?
25
+
26
+ array_pointer.read_array_of_pointer(count).map { |result_pointer| new(result_pointer) }
28
27
  end
29
28
  end
30
29
 
@@ -53,10 +52,9 @@ module Rdkafka
53
52
  # @param array_pointer [FFI::Pointer] pointer to the results array
54
53
  # @return [Array<GroupResult>] array of group results
55
54
  def self.create_group_results_from_array(count, array_pointer)
56
- (1..count).map do |index|
57
- result_pointer = (array_pointer + (index - 1)).read_pointer
58
- new(result_pointer)
59
- end
55
+ return [] if count.zero?
56
+
57
+ array_pointer.read_array_of_pointer(count).map { |result_pointer| new(result_pointer) }
60
58
  end
61
59
  end
62
60
 
@@ -77,10 +75,9 @@ module Rdkafka
77
75
  # @param array_pointer [FFI::Pointer] pointer to the results array
78
76
  # @return [Array<CreateAclResult>] array of ACL results
79
77
  def self.create_acl_results_from_array(count, array_pointer)
80
- (1..count).map do |index|
81
- result_pointer = (array_pointer + (index - 1)).read_pointer
82
- new(result_pointer)
83
- end
78
+ return [] if count.zero?
79
+
80
+ array_pointer.read_array_of_pointer(count).map { |result_pointer| new(result_pointer) }
84
81
  end
85
82
  end
86
83
 
@@ -108,10 +105,9 @@ module Rdkafka
108
105
  # @param array_pointer [FFI::Pointer] pointer to the results array
109
106
  # @return [Array<DeleteAclResult>] array of delete ACL results
110
107
  def self.delete_acl_results_from_array(count, array_pointer)
111
- (1..count).map do |index|
112
- result_pointer = (array_pointer + (index - 1)).read_pointer
113
- new(result_pointer)
114
- end
108
+ return [] if count.zero?
109
+
110
+ array_pointer.read_array_of_pointer(count).map { |result_pointer| new(result_pointer) }
115
111
  end
116
112
  end
117
113
 
@@ -213,6 +209,8 @@ module Rdkafka
213
209
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETETOPICS_RESULT then DeleteTopicHandler
214
210
  when Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS_RESULT then CreatePartitionsHandler
215
211
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEGROUPS_RESULT then DeleteGroupsHandler
212
+ when Rdkafka::Bindings::RD_KAFKA_EVENT_ALTERCONSUMERGROUPOFFSETS_RESULT then AlterConsumerGroupOffsetsHandler
213
+ when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETECONSUMERGROUPOFFSETS_RESULT then DeleteConsumerGroupOffsetsHandler
216
214
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETERECORDS_RESULT then DeleteRecordsHandler
217
215
  when Rdkafka::Bindings::RD_KAFKA_EVENT_CREATEACLS_RESULT then CreateAclHandler
218
216
  when Rdkafka::Bindings::RD_KAFKA_EVENT_DELETEACLS_RESULT then DeleteAclHandler
@@ -22,6 +22,12 @@ module Rdkafka
22
22
  @@log_mutex = Mutex.new
23
23
  # @!visibility private
24
24
  @@oauthbearer_token_refresh_callback = nil
25
+ # @!visibility private
26
+ # Whether the partition key length passed to the partitioner is the byte length (`bytesize`)
27
+ # rather than the character length (`size`). `false` (character length) is the legacy default
28
+ # to avoid changing partition assignment for existing multibyte/binary keys; set to `true` to
29
+ # opt into the correct, other-client-consistent byte-length hashing.
30
+ @@partitioner_key_uses_bytesize = false
25
31
 
26
32
  # Returns the current logger, by default this is a logger to stdout.
27
33
  #
@@ -122,6 +128,34 @@ module Rdkafka
122
128
  @@oauthbearer_token_refresh_callback
123
129
  end
124
130
 
131
+ # Whether the partitioner hashes the partition key by its byte length instead of its character
132
+ # length. Defaults to `false` (character length) to preserve existing partition assignment for
133
+ # multibyte/binary keys. Passing the byte length is the correct, other-client-consistent
134
+ # behavior; enable it (and be aware it can move such keys to a different partition) with
135
+ # `Rdkafka::Config.partitioner_key_uses_bytesize = true`. This default is expected to change in
136
+ # a future major version.
137
+ #
138
+ # @return [Boolean]
139
+ def self.partitioner_key_uses_bytesize
140
+ @@partitioner_key_uses_bytesize
141
+ end
142
+
143
+ # Sets whether the partitioner hashes the partition key by its byte length rather than its
144
+ # character length. The key length method is resolved here once rather than on every produced
145
+ # message, and each call re-resolves it, so changing the setting at runtime takes effect
146
+ # immediately.
147
+ #
148
+ # @param value [Boolean] true to hash by byte length, false (default) for character length
149
+ # @return [void]
150
+ def self.partitioner_key_uses_bytesize=(value)
151
+ @@partitioner_key_uses_bytesize = value
152
+
153
+ Rdkafka::Bindings.singleton_class.alias_method(
154
+ :partition_key_length,
155
+ value ? :partition_key_bytesize : :partition_key_size
156
+ )
157
+ end
158
+
125
159
  # @private
126
160
  def self.opaques
127
161
  @@opaques
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Rdkafka
4
4
  # Current rdkafka-ruby gem version
5
- VERSION = "0.29.2"
5
+ VERSION = "0.30.0"
6
6
  # Target librdkafka version to be used
7
- LIBRDKAFKA_VERSION = "2.14.2"
7
+ LIBRDKAFKA_VERSION = "2.15.0"
8
8
  # SHA256 hash of the librdkafka source tarball for verification
9
- LIBRDKAFKA_SOURCE_SHA256 = "d7eec9c31c817fa44402f679c252dfbf97e4c338a849a25c3579a31fd127beb8"
9
+ LIBRDKAFKA_SOURCE_SHA256 = "259015220cdca708afe838b5aa79ebf1a5fb710fb4179cf918d390aed85d5dbc"
10
10
  end
data/lib/rdkafka.rb CHANGED
@@ -13,6 +13,10 @@ require "rdkafka/helpers/list_offsets"
13
13
  require "rdkafka/defaults"
14
14
  require "rdkafka/abstract_handle"
15
15
  require "rdkafka/admin"
16
+ require "rdkafka/admin/alter_consumer_group_offsets_handle"
17
+ require "rdkafka/admin/alter_consumer_group_offsets_report"
18
+ require "rdkafka/admin/delete_consumer_group_offsets_handle"
19
+ require "rdkafka/admin/delete_consumer_group_offsets_report"
16
20
  require "rdkafka/admin/create_topic_handle"
17
21
  require "rdkafka/admin/create_topic_report"
18
22
  require "rdkafka/admin/delete_groups_handle"
@@ -46,6 +50,8 @@ require "rdkafka/callbacks/base_handler"
46
50
  require "rdkafka/callbacks/create_topic_handler"
47
51
  require "rdkafka/callbacks/delete_topic_handler"
48
52
  require "rdkafka/callbacks/create_partitions_handler"
53
+ require "rdkafka/callbacks/alter_consumer_group_offsets_handler"
54
+ require "rdkafka/callbacks/delete_consumer_group_offsets_handler"
49
55
  require "rdkafka/callbacks/delete_groups_handler"
50
56
  require "rdkafka/callbacks/delete_records_handler"
51
57
  require "rdkafka/callbacks/create_acl_handler"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdkafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.2
4
+ version: 0.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
@@ -93,7 +93,7 @@ files:
93
93
  - README.md
94
94
  - Rakefile
95
95
  - bin/verify_kafka_warnings
96
- - dist/librdkafka-2.14.2.tar.gz
96
+ - dist/librdkafka-2.15.0.tar.gz
97
97
  - dist/patches/rdkafka_global_init.patch
98
98
  - docker-compose-ssl.yml
99
99
  - docker-compose.yml
@@ -102,6 +102,8 @@ files:
102
102
  - lib/rdkafka/abstract_handle.rb
103
103
  - lib/rdkafka/admin.rb
104
104
  - lib/rdkafka/admin/acl_binding_result.rb
105
+ - lib/rdkafka/admin/alter_consumer_group_offsets_handle.rb
106
+ - lib/rdkafka/admin/alter_consumer_group_offsets_report.rb
105
107
  - lib/rdkafka/admin/config_binding_result.rb
106
108
  - lib/rdkafka/admin/config_resource_binding_result.rb
107
109
  - lib/rdkafka/admin/create_acl_handle.rb
@@ -112,6 +114,8 @@ files:
112
114
  - lib/rdkafka/admin/create_topic_report.rb
113
115
  - lib/rdkafka/admin/delete_acl_handle.rb
114
116
  - lib/rdkafka/admin/delete_acl_report.rb
117
+ - lib/rdkafka/admin/delete_consumer_group_offsets_handle.rb
118
+ - lib/rdkafka/admin/delete_consumer_group_offsets_report.rb
115
119
  - lib/rdkafka/admin/delete_groups_handle.rb
116
120
  - lib/rdkafka/admin/delete_groups_report.rb
117
121
  - lib/rdkafka/admin/delete_records_handle.rb
@@ -130,11 +134,13 @@ files:
130
134
  - lib/rdkafka/admin/list_offsets_report.rb
131
135
  - lib/rdkafka/bindings.rb
132
136
  - lib/rdkafka/callbacks.rb
137
+ - lib/rdkafka/callbacks/alter_consumer_group_offsets_handler.rb
133
138
  - lib/rdkafka/callbacks/base_handler.rb
134
139
  - lib/rdkafka/callbacks/create_acl_handler.rb
135
140
  - lib/rdkafka/callbacks/create_partitions_handler.rb
136
141
  - lib/rdkafka/callbacks/create_topic_handler.rb
137
142
  - lib/rdkafka/callbacks/delete_acl_handler.rb
143
+ - lib/rdkafka/callbacks/delete_consumer_group_offsets_handler.rb
138
144
  - lib/rdkafka/callbacks/delete_groups_handler.rb
139
145
  - lib/rdkafka/callbacks/delete_records_handler.rb
140
146
  - lib/rdkafka/callbacks/delete_topic_handler.rb
@@ -192,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
198
  - !ruby/object:Gem::Version
193
199
  version: '0'
194
200
  requirements: []
195
- rubygems_version: 4.0.16
201
+ rubygems_version: 4.0.20
196
202
  specification_version: 4
197
203
  summary: The rdkafka gem is a modern Kafka client library for Ruby based on librdkafka.
198
204
  It wraps the production-ready C client using the ffi gem and targets Kafka 1.0+