karafka-rdkafka 0.29.0-aarch64-linux-gnu → 0.30.0-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 +55 -21
- data/README.md +2 -1
- data/bin/verify_kafka_warnings +2 -0
- data/docker-compose-ssl.yml +13 -0
- data/docker-compose.yml +11 -0
- data/ext/librdkafka.so +0 -0
- data/lib/rdkafka/admin/alter_consumer_group_offsets_handle.rb +31 -0
- data/lib/rdkafka/admin/alter_consumer_group_offsets_report.rb +50 -0
- data/lib/rdkafka/admin/delete_consumer_group_offsets_handle.rb +31 -0
- data/lib/rdkafka/admin/delete_consumer_group_offsets_report.rb +50 -0
- data/lib/rdkafka/admin.rb +120 -0
- data/lib/rdkafka/bindings.rb +105 -4
- data/lib/rdkafka/callbacks/alter_consumer_group_offsets_handler.rb +65 -0
- data/lib/rdkafka/callbacks/delete_consumer_group_offsets_handler.rb +65 -0
- data/lib/rdkafka/callbacks.rb +14 -16
- data/lib/rdkafka/config.rb +143 -14
- data/lib/rdkafka/defaults.rb +8 -0
- data/lib/rdkafka/error.rb +13 -2
- data/lib/rdkafka/helpers/oauth.rb +24 -6
- data/lib/rdkafka/share_consumer/message.rb +40 -0
- data/lib/rdkafka/share_consumer.rb +558 -0
- data/lib/rdkafka/version.rb +3 -3
- data/lib/rdkafka.rb +8 -0
- metadata +10 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a95cc07b43b59b31c12efc8b80643d382d047ca631ac05ef300a1cc5fabbc66
|
|
4
|
+
data.tar.gz: 8c805df25595be165c1c8355354a7383db06febf3981870e1dcf34212a5417ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be9fd31b26db576a5fa7c1f4274944c18c5ac94a86c102802648d69e180065e52579efe200e7a0ebc0825411b74bf17dbeeb5c0b8166b5be80d9d186ec6e8f08
|
|
7
|
+
data.tar.gz: de443969d5bb5e1e26e2f5f4962e3e294c0f38f8b70fe3ae9fdafead8e9f2803261da7fe1caf5810e3daf2fbca043a21347e0fe8bbfb3f0ceb042d138cef5c1e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,44 +1,78 @@
|
|
|
1
1
|
# Rdkafka Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
4
|
-
- [
|
|
3
|
+
## 0.30.0 (2026-09-25)
|
|
4
|
+
- [Fix] Register share consumers in `Rdkafka::Clients` and destroy the native handle when `Config#share_consumer` fails part-way. Share consumers own the native handle directly rather than a `NativeKafka` wrapper, so they bypass `build_native_client` and were missed by the `at_exit` shutdown hook, leaving librdkafka to be unloaded with a live share handle.
|
|
5
|
+
- [Feature] Add preview support for KIP-932 share groups ("Queues for Kafka") via `Rdkafka::ShareConsumer`, created with `Config#share_consumer`. Members consume the same partitions cooperatively with per-record acknowledgements (`:accept`, `:release`, `:reject`) instead of committed offsets. Like the regular `Consumer`, `ShareConsumer` is a thin binding that exposes the librdkafka share primitives (`#subscribe`/`#unsubscribe`/`#subscription`, batch `#poll`, `#acknowledge`, `#commit_sync`, `#commit_async`, `#acknowledgement_commit_callback=`, `#close`) but drives none of them itself - there is no built-in poll loop, acknowledgement strategy or offset/lifecycle orchestration, leaving that to a higher layer such as Karafka. The handle is single-threaded by design, servicing log, statistics and error callbacks from within `#poll`. Requires a broker with share groups enabled (Apache Kafka 4.2.0+); librdkafka marks the feature as preview and not production-ready.
|
|
6
|
+
- [Enhancement] `RdkafkaError.build_from_c` now uses the human readable string librdkafka attaches to the `rd_kafka_error_t` instead of always using `rd_kafka_err2str`, improving diagnostics for every error-pointer path. It also destroys a code-0 error object instead of leaking it on the early return.
|
|
7
|
+
- [Enhancement] Extract the OAuthBearer token buffer/extension plumbing in `Helpers::OAuth` around two private native-call hooks so the share consumer overrides only the hooks instead of duplicating both public methods.
|
|
8
|
+
- [Fix] Make `ShareConsumer#close` safe against in-flight calls from other threads: closing now waits for operations in progress (mirroring `NativeKafka`), preventing a NULL handle from reaching librdkafka or a double destroy when two threads race `close`.
|
|
9
|
+
- [Fix] Keep the `ShareConsumer` native handle and its GC finalizer when `close`/`destroy` report an error. librdkafka leaves the instance intact in that case, so dropping the references beforehand leaked the client permanently; `close` is now retriable after such an error.
|
|
10
|
+
- [Fix] Pin the acknowledgement commit callback `FFI::Function` in the state holder shared with the `ShareConsumer` GC finalizer, preventing a use-after-free when an unclosed consumer is garbage collected and the finalizer-driven destroy flushes pending acknowledgements through it.
|
|
11
|
+
- [Fix] Make `ShareConsumer` fork-aware, mirroring `NativeKafka`. `rd_kafka_share_consumer_new` is backed by the same broker/main threads as any librdkafka client, which do not survive `fork`; the hand-rolled share lifecycle previously had no `@creator_pid` guard, so a process that forked after creating a share consumer would segfault (or deadlock) when the child's GC finalizer or `close` ran `rd_kafka_share_destroy` on the inherited handle. It now records the creating pid and reports `closed?` in any other process, so the finalizer and `close` skip the native teardown for an inherited handle while `with_native` rejects any use of it.
|
|
12
|
+
- [Fix] Scope `ShareConsumer#each`'s `ClosedConsumerError` rescue to the `poll` call only. It previously wrapped the `yield`, so a `ClosedConsumerError` raised from inside the caller's block was swallowed and silently ended iteration; the block's errors now propagate, and only the consumer actually closing ends the loop. Its docs also note that, like `#poll`, `#each` can yield an `RdkafkaError` for a record that fails to build.
|
|
13
|
+
- [Fix] Raise `ArgumentError` for `ShareConsumer#subscribe` without topics. librdkafka treats an empty share subscribe as an unsubscribe and returns no error (unlike the regular consumer), silently dropping the subscription.
|
|
14
|
+
- [Fix] Capture the librdkafka client name onto `ShareConsumer#name` from the OAuthBearer token refresh callback. The share handle has no native name accessor, which made the documented name-based routing of the global oauth callback impossible for share consumers.
|
|
15
|
+
- [Fix] Update `ext/build_common.sh` (precompiled builds) to librdkafka `2.15.0` and its tarball checksum; it still pinned `2.14.1`, whose tarball is no longer vendored.
|
|
16
|
+
- [Fix] Stop the `share_consumer_multi_member` integration spec from failing on redelivery. KIP-932 share groups are documented as at-least-once, so a record whose acquisition lock expires before it is acknowledged may be redelivered with an incremented `delivery_count`; the spec now tracks distinct payloads and fails only when a record is never delivered.
|
|
17
|
+
- [Fix] Apply the same at-least-once tolerance to the `share_consumer_explicit_ack` integration spec, which still asserted exactly one redelivered record. It now requires only the released record to be redelivered (with `delivery_count >= 2`), forbids only the rejected record, and tolerates an accepted record reappearing when its acquisition lock expired before the commit flushed the accept.
|
|
18
|
+
- [Fix] Add the `nofile` ulimit to `docker-compose-ssl.yml`, mirroring `docker-compose.yml`. The SSL CI broker runs the same topic-heavy suite (now enlarged by the share consumer specs) and could otherwise exhaust the default file-descriptor limit under the many short-lived topics.
|
|
19
|
+
- [Fix] Enable KIP-932 share groups on the macOS CI broker, whose KRaft `server.properties` never opted into the share rebalance protocol, so the one broker-backed share consumer spec received zero records on every macOS runner. `CONFLUENT_VERSION` is bumped to `8.3.0` and the download path is derived from it so a Renovate bump cannot desync them.
|
|
20
|
+
- [Enhancement] Add two share consumer integration specs: `share_consumer_implicit_ack_spec` (polling alone accepts the previous batch, and accepted records are not redelivered to a second member) and `share_consumer_multi_topic_spec` (one consumer subscribed to several topics receives every topic's records, attributed to the right topic). Both track distinct payloads so an at-least-once redelivery cannot end the consume loop early.
|
|
21
|
+
- [Fix] Stop the `statistics_unassigned_producer` integration spec from flaking on a metadata-propagation race: the freshly built producer could send before fetching the new topic's metadata, so the produce is now retried on `unknown_topic_or_part` and `leader_not_available`.
|
|
22
|
+
- [Fix] Also stabilize the `statistics_unassigned_producer` integration spec against a delivery wait that outlives its budget. With 1000 partitions librdkafka keeps the message queued while leaders are still being elected, so the handle stays pending and the wait raises `WaitTimeoutError` - a `RuntimeError` the spec's existing code-based rescue could never catch. The produce now uses the default 60s handle wait (matching the sibling `statistics_unassigned_*` specs, instead of a self-imposed 15s) and retries on that timeout too.
|
|
23
|
+
- [Fix] Stabilize the `consumer_memberid_clusterid_leak` integration spec against RSS measurement noise on Ruby 4.0. It now compacts the heap before sampling (matching the `to_native_tpl` leak spec) and the ceiling is 3 MB, still well under the ~5.7 MB a genuine per-call leak would cost.
|
|
24
|
+
- [Note] Share consumers emit the regular consumer statistics JSON (including `cgrp`; there is no share-specific section in librdkafka 2.15.0) through the usual `statistics_callback`, serviced from within `#poll`. The share fetch path bypasses the per-partition stats bookkeeping entirely, so the `topics` section carries no partition entries and the `statistics.unassigned.include` filter needs no share-consumer special-casing; per-partition share metrics are not exposed by librdkafka 2.15.0 at all.
|
|
25
|
+
- [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. Ported from rdkafka-ruby (#983).
|
|
26
|
+
- [Enhancement] Bump librdkafka to `2.15.1` for OpenSSL and libcurl security fixes. It changes how IPv6 addresses are formatted and validated against broker certificates.
|
|
27
|
+
- [Enhancement] Bump the bundled zlib to `1.3.2`.
|
|
28
|
+
- [Enhancement] Bump the bundled MIT Kerberos (krb5) to `1.22.2`. Ported from rdkafka-ruby (#979).
|
|
29
|
+
- [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`. Ported from rdkafka-ruby (#985).
|
|
30
|
+
- [Maintenance] Derive the zlib `CHECKSUMS` entry from `ZLIB_VERSION`.
|
|
31
|
+
- [Maintenance] Drop the unused `dist/openssl-3.0.16.tar.gz` build cache.
|
|
32
|
+
- [Fix] Honor the `isolation_level:` argument to `Admin#list_offsets`, which was silently ignored. Ported from rdkafka-ruby (#983).
|
|
33
|
+
- [Fix] Return correct results for every item of a multi-item topic, partition, group or ACL admin request, not just the first. Ported from rdkafka-ruby (#987).
|
|
34
|
+
- [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). Ported from rdkafka-ruby (#991).
|
|
35
|
+
- [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), give the non-blocking `poll_nb` message check a generous retry budget instead of a fixed ~2s, and let the long-running consumption spec drain its backlog instead of stopping at a fixed 60s. The assignment wait is tunable via `RDKAFKA_TEST_ASSIGNMENT_TIMEOUT`. Ported from rdkafka-ruby (#990).
|
|
36
|
+
|
|
37
|
+
## 0.29.0 (2026-09-14)
|
|
38
|
+
- [Enhancement] Bump librdkafka to `2.15.0` (staying on `2.15.0` rather than `2.15.1` so users hitting a regression in `2.15.1` have a stable fallback).
|
|
5
39
|
|
|
6
40
|
## 0.28.2 (2026-09-11)
|
|
7
|
-
- [Fix] Close live clients
|
|
8
|
-
- [Fix]
|
|
9
|
-
- [Fix]
|
|
10
|
-
- [Fix] Free
|
|
11
|
-
- [Fix] Raise
|
|
12
|
-
- [Fix]
|
|
41
|
+
- [Fix] Close live clients before Ruby shutdown finalization, preventing a possible segfault on exit. Ported from rdkafka-ruby (#964, Alex Selesse).
|
|
42
|
+
- [Fix] Destroy the native handle when client construction fails partway, so it is no longer orphaned. Ported from rdkafka-ruby (#964, Alex Selesse).
|
|
43
|
+
- [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`. Ported from rdkafka-ruby (#973).
|
|
44
|
+
- [Fix] Free native resources when `Admin#describe_configs`/`#incremental_alter_configs` raise while building their request (e.g. a non-String resource name). Ported from rdkafka-ruby (#973).
|
|
45
|
+
- [Fix] Raise `ConfigError` instead of segfaulting when `Admin#describe_configs`/`#incremental_alter_configs` get an empty resource name or a negative resource type. Ported from rdkafka-ruby (#973).
|
|
46
|
+
- [Fix] Stop the topic-partition metadata string from being freed while librdkafka still uses it. Ported from rdkafka-ruby (#969, Randy Stauner).
|
|
13
47
|
- [Maintenance] Bump the bundled OpenSSL used by the precompiled builds to `3.5.8` (LTS). Ported from rdkafka-ruby (#972, Scott Francis).
|
|
14
48
|
|
|
15
49
|
## v0.28.1 (2026-09-04)
|
|
16
|
-
- [Enhancement] Add `Admin#delete_records
|
|
17
|
-
- [Enhancement] Add `Admin#list_consumer_groups
|
|
50
|
+
- [Enhancement] Add `Admin#delete_records` to delete messages in a partition up to a given offset, or all current data with `:end`. Ported from rdkafka-ruby (#956).
|
|
51
|
+
- [Enhancement] Add `Admin#list_consumer_groups` for a cluster-wide listing of consumer groups. Ported from rdkafka-ruby (#955).
|
|
18
52
|
- [Fix] Make `NativeKafka#close` fork-aware so a forked child no longer segfaults on exit. Handles record their creator pid and skip the native teardown in any other process.
|
|
19
53
|
- [Fix] Stabilize the flaky partitions count cache statistics spec.
|
|
20
54
|
- [Fix] Stabilize the `to_native_tpl` leak integration spec against RSS measurement noise.
|
|
21
55
|
|
|
22
56
|
## v0.28.0 (2026-07-12)
|
|
23
|
-
- [Enhancement] Bump librdkafka to `2.14.2
|
|
24
|
-
- [Enhancement] Add `Consumer#metadata` and `Producer#metadata`, mirroring `Admin#metadata`,
|
|
25
|
-
- [Enhancement] Name the failing
|
|
26
|
-
- [Enhancement] Add `Consumer#list_offsets`, mirroring `Admin#list_offsets`,
|
|
57
|
+
- [Enhancement] Bump librdkafka to `2.14.2` (maintenance release with bundled dependency CVE fixes and a fix for duplicate groups in `ListConsumerGroups`).
|
|
58
|
+
- [Enhancement] Add `Consumer#metadata` and `Producer#metadata`, mirroring `Admin#metadata`, to fetch cluster metadata without a separate admin connection.
|
|
59
|
+
- [Enhancement] Name the failing topic and partition in `RdkafkaError`s raised for per-partition `list_offsets` errors.
|
|
60
|
+
- [Enhancement] Add `Consumer#list_offsets`, mirroring `Admin#list_offsets`, and compute `Consumer#lag` with one batched query instead of a roundtrip per partition.
|
|
27
61
|
- [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.
|
|
28
62
|
- [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.
|
|
29
63
|
- [Enhancement] Reuse per-thread scratch pointers in `Consumer::Headers.from_native`, removing the per-message native allocations from the consumer hot path.
|
|
30
64
|
- [Enhancement] Remove the unused `DeliveryHandle` `:topic_name` struct field and its per-message allocation. Use `DeliveryHandle#topic` or `DeliveryReport#topic_name`, both unchanged.
|
|
31
|
-
- [Fix] Stop `poll_batch`/`poll_batch_nb` from discarding a whole batch when one message fails to build. The failure is
|
|
65
|
+
- [Fix] Stop `poll_batch`/`poll_batch_nb` from discarding a whole batch when one message fails to build. The failure is returned inline as an `RdkafkaError`.
|
|
32
66
|
- [Fix] Add the missing `closed_consumer_check` to `Consumer#position`, so it raises a consistent `ClosedConsumerError` like every sibling offset method.
|
|
33
67
|
- [Fix] Stop leaking the native `rd_kafka_topic_conf_t` in `Producer#set_topic_config` when a per-topic config value is rejected.
|
|
34
68
|
- [Fix] Raise instead of silently dropping a rejected `incremental_alter_configs` entry, which previously left the alter request reporting success.
|
|
35
69
|
- [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.
|
|
36
|
-
- [Fix]
|
|
37
|
-
- [Fix] Stop `describe_configs`, `incremental_alter_configs` and `list_offsets` from leaking
|
|
70
|
+
- [Fix] Fully close a consumer collected without an explicit `close`, preventing a hang or leak.
|
|
71
|
+
- [Fix] Stop `describe_configs`, `incremental_alter_configs` and `list_offsets` from leaking native resources when their arguments are rejected.
|
|
38
72
|
- [Fix] Destroy the native topic-partition list in `TopicPartitionList#to_native_tpl` when population fails partway, which previously leaked the half-built list.
|
|
39
73
|
- [Fix] Allocate the admin result-count out-parameter as `:size_t` instead of `:int32`, fixing a 4-byte overflow on every admin result parse.
|
|
40
|
-
- [Fix]
|
|
41
|
-
- [Fix]
|
|
74
|
+
- [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.
|
|
75
|
+
- [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.
|
|
42
76
|
- [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.
|
|
43
77
|
- [Fix] Stop `Metadata` from leaking the native metadata struct on every retried fetch; each attempt now frees its own native resources.
|
|
44
78
|
- [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`.
|
|
@@ -46,10 +80,10 @@
|
|
|
46
80
|
- [Fix] Stop `Producer#produce` from orphaning the delivery handle in the process-global registry when it fails after registering it.
|
|
47
81
|
- [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`.
|
|
48
82
|
- [Fix] Stabilize the flaky `Consumer#lag` spec on overloaded CI. Backported from rdkafka-ruby (#912).
|
|
49
|
-
- [Fix]
|
|
83
|
+
- [Fix] Raise `ConfigError` instead of `NameError` in `Admin#delete_group`, `#delete_acl` and `#describe_acl` when the background queue is unavailable.
|
|
50
84
|
- [Fix] Forward `broker_message` and `instance_name` through `RdkafkaError.build`; both were previously discarded on the `rd_kafka_error_t` pointer path.
|
|
51
85
|
- [Fix] Synchronize `AbstractHandle::REGISTRY` mutations with a mutex, which could otherwise lose a write on JRuby and leave a handle unregistered or leaked.
|
|
52
|
-
- [Fix]
|
|
86
|
+
- [Fix] Bound the `Metadata` retry loop to about 5 seconds, so a synchronous metadata fetch can no longer block for minutes.
|
|
53
87
|
- [Fix] Cache the partition count for a missing topic, so `produce` with a `partition_key` to a not-yet-created topic no longer runs a blocking metadata query on every message.
|
|
54
88
|
|
|
55
89
|
## 0.27.2 (2026-05-21)
|
data/README.md
CHANGED
|
@@ -63,7 +63,8 @@ Contributions should generally be made to the upstream [rdkafka-ruby repository]
|
|
|
63
63
|
|
|
64
64
|
| karafka-rdkafka | librdkafka | patches |
|
|
65
65
|
|-|-|-|
|
|
66
|
-
| 0.
|
|
66
|
+
| 0.30.x (2026-09-25) | 2.15.1 (2026-09-09) | yes |
|
|
67
|
+
| 0.29.x (2026-09-14) | 2.15.0 (2026-06-30) | yes |
|
|
67
68
|
| 0.28.x (2026-07-12) | 2.14.2 (2026-06-03) | yes |
|
|
68
69
|
| 0.27.x (2026-05-08) | 2.14.1 (2026-04-15) | yes |
|
|
69
70
|
| 0.26.x (2026-04-11) | 2.14.0 (2026-04-01) | yes |
|
data/bin/verify_kafka_warnings
CHANGED
|
@@ -14,6 +14,8 @@ allowed_patterns=(
|
|
|
14
14
|
"closing connection"
|
|
15
15
|
"sent a heartbeat request but received error REQUEST_TIMED_OUT"
|
|
16
16
|
"Topic '__consumer_offsets' already exists"
|
|
17
|
+
"is deprecated. Share groups are controlled by the 'share.version' feature"
|
|
18
|
+
"is deprecated and will be removed in Kafka 5.0. The following protocol(s) are currently disabled"
|
|
17
19
|
)
|
|
18
20
|
|
|
19
21
|
# Get all warnings
|
data/docker-compose-ssl.yml
CHANGED
|
@@ -7,6 +7,14 @@ services:
|
|
|
7
7
|
- 9093:9093
|
|
8
8
|
volumes:
|
|
9
9
|
- ./ssl:/etc/kafka/secrets
|
|
10
|
+
|
|
11
|
+
# The suite creates hundreds of short-lived topics; each keeps several segment/index file
|
|
12
|
+
# descriptors open on the broker
|
|
13
|
+
ulimits:
|
|
14
|
+
nofile:
|
|
15
|
+
soft: 262144
|
|
16
|
+
hard: 262144
|
|
17
|
+
|
|
10
18
|
environment:
|
|
11
19
|
CLUSTER_ID: kafka-docker-cluster-1
|
|
12
20
|
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
|
|
@@ -25,6 +33,11 @@ services:
|
|
|
25
33
|
KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true"
|
|
26
34
|
KAFKA_AUTHORIZER_CLASS_NAME: org.apache.kafka.metadata.authorizer.StandardAuthorizer
|
|
27
35
|
|
|
36
|
+
# KIP-932 share groups (queues for Kafka) used by the share consumer specs
|
|
37
|
+
KAFKA_GROUP_COORDINATOR_REBALANCE_PROTOCOLS: classic,consumer,share
|
|
38
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR: 1
|
|
39
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR: 1
|
|
40
|
+
|
|
28
41
|
# SSL Configuration
|
|
29
42
|
KAFKA_SSL_KEYSTORE_FILENAME: kafka.server.keystore.jks
|
|
30
43
|
KAFKA_SSL_KEYSTORE_CREDENTIALS: kafka_keystore_creds
|
data/docker-compose.yml
CHANGED
|
@@ -6,6 +6,13 @@ services:
|
|
|
6
6
|
ports:
|
|
7
7
|
- 9092:9092
|
|
8
8
|
|
|
9
|
+
# The suite creates hundreds of short-lived topics; each keeps several segment/index file
|
|
10
|
+
# descriptors open on the broker
|
|
11
|
+
ulimits:
|
|
12
|
+
nofile:
|
|
13
|
+
soft: 262144
|
|
14
|
+
hard: 262144
|
|
15
|
+
|
|
9
16
|
environment:
|
|
10
17
|
CLUSTER_ID: kafka-docker-cluster-1
|
|
11
18
|
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
|
|
@@ -23,3 +30,7 @@ services:
|
|
|
23
30
|
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
|
|
24
31
|
KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true"
|
|
25
32
|
KAFKA_AUTHORIZER_CLASS_NAME: org.apache.kafka.metadata.authorizer.StandardAuthorizer
|
|
33
|
+
# KIP-932 share groups (queues for Kafka) used by the share consumer integration specs
|
|
34
|
+
KAFKA_GROUP_COORDINATOR_REBALANCE_PROTOCOLS: classic,consumer,share
|
|
35
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR: 1
|
|
36
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR: 1
|
data/ext/librdkafka.so
CHANGED
|
Binary file
|
|
@@ -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
|
|
@@ -1134,6 +1206,54 @@ module Rdkafka
|
|
|
1134
1206
|
|
|
1135
1207
|
private
|
|
1136
1208
|
|
|
1209
|
+
# Shared enqueue path for the two consumer group offset admin operations. They differ only
|
|
1210
|
+
# in their C entry points, so keeping one body avoids two near identical copies of the
|
|
1211
|
+
# queue/handle/options dance and its cleanup.
|
|
1212
|
+
#
|
|
1213
|
+
# @param request_ptr [FFI::Pointer] the op specific request object
|
|
1214
|
+
# @param handle [AbstractHandle] the handle to register and return
|
|
1215
|
+
# @param admin_op [Integer] the RD_KAFKA_ADMIN_OP_* constant for this operation
|
|
1216
|
+
# @param destroy [Method] bound function used to free the request object
|
|
1217
|
+
# @param enqueue [Method] bound function used to enqueue the request
|
|
1218
|
+
# @return [AbstractHandle] the registered handle
|
|
1219
|
+
def enqueue_group_offsets_op(request_ptr:, handle:, admin_op:, destroy:, enqueue:)
|
|
1220
|
+
array_ptr = FFI::MemoryPointer.new(:pointer)
|
|
1221
|
+
array_ptr.write_array_of_pointer([request_ptr])
|
|
1222
|
+
|
|
1223
|
+
queue_ptr = @native_kafka.with_inner do |inner|
|
|
1224
|
+
Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
|
|
1225
|
+
end
|
|
1226
|
+
|
|
1227
|
+
if queue_ptr.null?
|
|
1228
|
+
destroy.call(request_ptr)
|
|
1229
|
+
raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
handle[:pending] = true
|
|
1233
|
+
handle[:response] = Rdkafka::Bindings::RD_KAFKA_PARTITION_UA
|
|
1234
|
+
handle.class.register(handle)
|
|
1235
|
+
|
|
1236
|
+
admin_options_ptr = @native_kafka.with_inner do |inner|
|
|
1237
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, admin_op)
|
|
1238
|
+
end
|
|
1239
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, handle.to_ptr)
|
|
1240
|
+
|
|
1241
|
+
begin
|
|
1242
|
+
@native_kafka.with_inner do |inner|
|
|
1243
|
+
enqueue.call(inner, array_ptr, 1, admin_options_ptr, queue_ptr)
|
|
1244
|
+
end
|
|
1245
|
+
rescue Exception
|
|
1246
|
+
handle.class.remove(handle.to_ptr.address)
|
|
1247
|
+
raise
|
|
1248
|
+
ensure
|
|
1249
|
+
Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
|
|
1250
|
+
Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
|
|
1251
|
+
destroy.call(request_ptr)
|
|
1252
|
+
end
|
|
1253
|
+
|
|
1254
|
+
handle
|
|
1255
|
+
end
|
|
1256
|
+
|
|
1137
1257
|
# Checks if the admin is closed and raises an error if so
|
|
1138
1258
|
# @param method [Symbol] name of the calling method for error context
|
|
1139
1259
|
# @raise [ClosedAdminError] when the admin is closed
|