karafka-rdkafka 0.30.0 → 0.30.1

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: 290a1e79997166534339567e0f46bf560191141a22c754bdd67c656ea68594f4
4
- data.tar.gz: 972ca0af039c92a2b68d6767214ede8c06d7da0eaffde72f98c79bfcef0b8943
3
+ metadata.gz: a0e958e572e7b8e0c56325da653e4635b1dc296868d531f237ec1d275c75d207
4
+ data.tar.gz: 2ca9f29779c17216cc815ec759cf2a04a0f8c631718f530810aa13b76183cadc
5
5
  SHA512:
6
- metadata.gz: 33ba78845a20d938ad79d61c859b08303dfe28ffdbf6a0fa5e99184805fa1d842153c0d676ba6fa25640241b71b2188a65d8ac58208e78526a5e2e3eedc433ad
7
- data.tar.gz: 92f7639fca0c51e06844f705285df809a8680315d44531953d6d9b0049aff2964a7633933c31522b8fd75f4bb1606cb13f6a1a5c1d097e8a3f7011b5f3e04083
6
+ metadata.gz: 6d1fa15d28c82fb010b8c2a435285a39358a44973f022c6e0a6cbde422dcacf5ef79ac8ccd92a1dc91c17da799c147413e1555f5450a555e6401b9e2f2fcac75
7
+ data.tar.gz: 1523595543d9af2b27194492cf88bf2c37bda387009b49d3c9293c00efdb9d6db425657c60184739535ec89bd30dc86102b88cc6b24d26640e73021f36cf0760
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Rdkafka Changelog
2
2
 
3
+ ## 0.30.1 (2026-09-30)
4
+ - [Fix] Derive `ShareConsumer#name` from the native handle at creation (mirroring `Consumer#name`) instead of leaving it `nil` until an OAuthBearer callback happened to set it. A `nil` name meant downstreams that route the global statistics and error callbacks by client name (e.g. Karafka) silently dropped every share-consumer statistic and background error.
5
+
3
6
  ## 0.30.0 (2026-09-25)
4
7
  - [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
8
  - [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.
@@ -517,6 +517,18 @@ module Rdkafka
517
517
  # rd_kafka_share_consumer_new instead of rd_kafka_new. It is single-threaded by design and
518
518
  # librdkafka itself rejects concurrent access with RD_KAFKA_RESP_ERR__CONFLICT.
519
519
 
520
+ # Minimal mirror of the head of librdkafka's `struct rd_kafka_share_s`, whose first member is
521
+ # the wrapped `rd_kafka_t` (`rkshare_rk`). `rd_kafka_share_t` has no public accessors of its
522
+ # own - not even for the client name - but the handle it wraps is a normal `rd_kafka_t` and is
523
+ # the very handle librdkafka passes to the statistics, error and OAuthBearer callbacks. Reading
524
+ # it lets a share consumer report a name that matches its statistics `name` field, which
525
+ # `rd_kafka_name` cannot do when handed the `rd_kafka_share_t` directly (it would read an
526
+ # unrelated field and return garbage). This mirrors how the gem already maps other librdkafka
527
+ # structs by layout for the pinned librdkafka version.
528
+ class NativeShareConsumer < FFI::Struct
529
+ layout :rkshare_rk, :pointer
530
+ end
531
+
520
532
  # Acknowledge types for share consumer records
521
533
  RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_ACCEPT = 1
522
534
  RD_KAFKA_SHARE_ACKNOWLEDGE_TYPE_RELEASE = 2
@@ -57,14 +57,17 @@ module Rdkafka
57
57
  private_constant :State
58
58
 
59
59
  # The client name librdkafka reports for this consumer (e.g. "rdkafka#consumer-1"), used to
60
- # correlate global callbacks (such as the OAuthBearer token refresh callback) with this
61
- # instance. librdkafka exposes no name accessor on the share handle, so this is captured
62
- # from the first callback that carries it and is nil until then.
63
- # @return [String, nil]
60
+ # correlate the global callbacks (statistics, error and the OAuthBearer token refresh
61
+ # callback, all of which carry the client name) with this instance. Captured from the native
62
+ # handle when the consumer is created, so it is available immediately - before the first
63
+ # {#poll} and without OAuth configured - and stays readable after the consumer is closed or
64
+ # inherited by a forked child.
65
+ # @return [String] the librdkafka client name
64
66
  attr_reader :name
65
67
 
66
68
  # @private
67
- # Captures the librdkafka client name once known (from callback context)
69
+ # Lets the OAuthBearer token refresh callback set the name from its callback context. It
70
+ # carries the same `rd_kafka_name` value already captured at creation, so both paths agree.
68
71
  attr_writer :name
69
72
 
70
73
  # @private
@@ -80,6 +83,18 @@ module Rdkafka
80
83
  # every teardown path can skip the native destroy in a forked child (librdkafka is not
81
84
  # fork-safe).
82
85
  @state = State.new(native, nil, Process.pid)
86
+ # Capture the librdkafka client name up front. It is needed to correlate this consumer with
87
+ # the global statistics and error callbacks (which carry the client name) - the common
88
+ # downstream pattern (e.g. Karafka) filters those broadcast callbacks by matching `name`.
89
+ #
90
+ # `rd_kafka_name` has no `rd_kafka_share_t` overload: handing it the share handle reads an
91
+ # unrelated field and returns garbage. The share handle's first member is the `rd_kafka_t`
92
+ # it wraps (`rkshare_rk`), which is the same handle librdkafka passes to those callbacks, so
93
+ # the name read from it matches the statistics `name` field. Capturing it here (rather than
94
+ # lazily like the regular consumer) keeps it available before the first poll, without OAuth,
95
+ # and after close or in a forked child, where the native handle must not be touched.
96
+ # librdkafka assigns the name at creation, so no broker connection is required.
97
+ @name = Rdkafka::Bindings.rd_kafka_name(Rdkafka::Bindings::NativeShareConsumer.new(native)[:rkshare_rk])
83
98
  # Guards handle teardown against in-flight calls: increments happen under this mutex and
84
99
  # close holds it while draining and destroying (mirrors NativeKafka's approach)
85
100
  @access_mutex = Mutex.new
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rdkafka
4
4
  # Current rdkafka-ruby gem version
5
- VERSION = "0.30.0"
5
+ VERSION = "0.30.1"
6
6
  # Target librdkafka version to be used
7
7
  LIBRDKAFKA_VERSION = "2.15.1"
8
8
  # SHA256 hash of the librdkafka source tarball for verification
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka-rdkafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.30.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier