[//]: # (This file is auto-generated by bin/refresh_remote_content) [//]: # (Do not edit manually - changes will be overwritten) # Karafka Core Changelog ## Karafka Core Changelog / 2.6.2 (2026-06-29) - [Enhancement] Document that a leaf's `default` value is intentionally shared by reference across the class template and every config instance produced by `Configurable::Node#deep_dup`. This uniform rule (the leaf is shallow-copied) is what lets a shared service object passed as a default (e.g. a logger) keep its identity across all configs; the flip side is that an in-place mutation of a mutable container default (`config.list << :x`) is visible on every instance. Callers that need a per-instance mutable default should assign it inside a `configure` block or dup it themselves rather than relying on a mutable `default:` (e.g. `default: []`). Adds characterization tests covering the shared-default behavior. - [Fix] `require "pathname"` explicitly in `lib/karafka-core.rb` (with the other top-level requires). `Karafka::Core.gem_root` returns a `Pathname`, but the gem never required `pathname` -- it only worked because Bundler (or another gem) happened to load it first. In an environment where nothing else loads it, `gem_root` raised `NameError: uninitialized constant Pathname`. - [Enhancement] Document the `virtual` rule result contract: a rule must return a freshly built `Array` of `[path, message]` error pairs on every call. `Contract#call` takes ownership of that array and prepends the current scope onto each pair in place (avoiding a per-error allocation), so returning a memoized, shared or frozen array is unsupported -- the in-place scoping would accumulate the scope prefix across validations or raise `FrozenError`. Adds characterization tests for the supported and unsupported patterns. - [Fix] `Configurable::Node#register` raises the documented "already registered" `ArgumentError` for a name already used by an unread lazy-with-constructor setting. The duplicate guard only checked `@configs_refs`, but a lazy setting with a constructor is absent from it until first read, so `register` silently overwrote it; it now checks the defined children. - [Fix] `Contractable::Contract.nested` now pops its path in an `ensure`. If the block raised while the contract was being defined and the caller rescued it, the path stayed on the nesting stack and was prefixed onto every rule defined afterwards. - [Fix] `Contract#call` no longer raises `NoMethodError` when validating a non-Hash root with a 1-key or 2-key rule path; it reports the path as missing, consistent with the 3+-key path (and the non-Hash intermediate handling added in 2.6.1). - [Fix] Honor `excluded_keys` containing `"cgrp"` in `StatisticsDecorator` `only_keys` mode. The `cgrp` branch of the structure-aware fast path lacked the exclusion guard that the `brokers` and `topics` branches have, so excluding the consumer-group subtree still decorated it (inconsistent with the full-decoration path). - [Fix] Guard the patched rdkafka error callback against a null client pointer. librdkafka can invoke the error callback with a NULL `rd_kafka_t` (e.g. very early in client construction); calling `rd_kafka_name` on it dereferenced the null pointer and could segfault the process. Mirrors the upstream `ErrorCallback`. - [Fix] Resolve fatal errors in the patched rdkafka error callback. `ERR__FATAL` is only a generic marker, so the callback now fetches the real underlying error code and description via `RdkafkaError.build_fatal` (`rd_kafka_fatal_error`) instead of reporting the generic fatal code. Mirrors the upstream `ErrorCallback`. - [Fix] A lazy setting declared without a constructor (`setting(:x, lazy: true)`) no longer raises when its accessor is read. `lazy: true` only makes sense together with a constructor to (re)evaluate; without one there is nothing to evaluate, so such a setting now behaves like a regular setting backed by its default. Previously reading it raised `NoMethodError` — `nil.arity` through the dynamic accessor for a falsy default, or a missing accessor for a truthy default. - [Fix] `Contract#call` no longer raises `NoMethodError` when a virtual rule returns `false`. A virtual rule now signals "no errors" with any non-Array result (`true`/`false`/`nil`); only an `Array` of error pairs is collected. Previously a `false` return reached `false.each` (a `nil` return was already tolerated). - [Fix] Manage `CallbacksManager` callbacks copy-on-write: `add`/`delete` rebuild and atomically swap an immutable values snapshot under a mutex, and `#call` iterates that snapshot directly. The previous values cache (introduced in 2.5.11) was lazily invalidated from within `#call`, which could not be done atomically against a concurrent `add`/`delete`, so a callback racing with dispatch could be silently lost — a removed one kept firing forever, or a newly added one never fired. The copy-on-write read takes no lock and allocates nothing per call, so the race is fixed without reintroducing a per-call `#values` allocation. librdkafka statistics/error callbacks fire from a background thread while callbacks are registered/unregistered, so this was reachable in practice. - [Fix] Manage `Notifications` subscriptions copy-on-write (`#subscribe`, `#unsubscribe` and `#clear` replace the per-event listener array instead of mutating it in place) so a listener that unsubscribes itself (or another) from within its own handler no longer causes the listener following it to be silently skipped, and concurrent subscribe/unsubscribe during dispatch is safe. Dispatch keeps iterating the live array directly, so there is no per-notification allocation on the hot path. - [Fix] Report a freeze duration (`_fd`) of `0` for statistics keys that are newly introduced in an emission (e.g. a broker or partition that appears mid-stream) instead of the elapsed time since the previous emission. A key that did not exist in the prior emission could not have been "frozen" for any duration, so accumulating the inter-emission gap was incorrect and also made the related `StatisticsDecorator` spec flaky on slow CIs (`_fd` depended on the wall-clock gap between the two emissions). - [Fix] Make assigning a setting on a frozen `Configurable::Node` atomic. The ivar-backed writer evaluated `@configs_refs[name] = value` before `instance_variable_set`, so a frozen node mutated the canonical store and only then raised `FrozenError`, leaving the store and the ivar-backed reader permanently out of sync. It now raises before touching any state. - [Fix] `Configurable::Node#to_h` now evaluates a setting's constructor with its default (arity-aware, matching `#compile`) instead of calling it with no arguments. The documented `->(default) { ... }` constructor form previously raised `ArgumentError: wrong number of arguments` from `#to_h` whenever the value was not yet in the config store (e.g. `#to_h` on an unconfigured instance, or an unread lazy setting). - [Fix] Honor `excluded_keys` inside `StatisticsDecorator` `only_keys` decoration. A key listed in both `only_keys` and `excluded_keys` was still decorated because the direct-access decoration loop never consulted `excluded_keys`; exclusion now wins, matching the full-decoration path. - [Fix] Strip the tests/specs root directory as an anchored prefix (`sub(/\A.../)`) instead of a global `gsub` in `MinitestLocator` and `RSpecLocator`. When the root directory string recurred later in a test/spec file path, the global replace removed every occurrence and corrupted the derived subject class path; only the leading prefix is now removed. ## Karafka Core Changelog / 2.6.1 (2026-06-15) - [Enhancement] Speed up `Contract#call` by ~1.25x for minimal and ~1.4x for fully populated data: resolve rule paths with a single `Hash#fetch` per level instead of `key?` + `[]`, inline the per-rule type dispatch into the rules loop, and compare the dig sentinel via `#equal?` so `#==` is never dispatched to the validated (user-provided) values. This is the per-message validation path in WaterDrop producers. - [Fix] `Contract#call` with rule paths of 3+ keys no longer raises `NoMethodError` when an intermediate value is not a `Hash` and reports the path as missing instead, consistent with the 2-key path behavior. - [Change] Reject reserved setting names with an `ArgumentError` in `Configurable::Node#setting` and `#register`: internal state names (`node_name`, `children`, `nestings`, `compiled`, `configs_refs`, `local_defs`) and the node public API names (`setting`, `configure`, `to_h`, `deep_dup`, `register`, `compile`). Previously such names silently shadowed the node own accessors, breaking `deep_dup` or `to_h`, and assignments like `config.children = value` corrupted the node internal state. - [Enhancement] Skip the event name mapping hash lookup in `Monitor#instrument` when no namespace is used and the event id is already a `String`, which is the case for all events in the Karafka ecosystem (~1.2x faster dispatch on the common no-subscribers path). Symbol event ids and namespaced monitors keep going through the mapping. - [Enhancement] Mirror config values into instance variables and use `attr_reader` based readers in `Configurable::Node`, yielding ~1.4x faster flat and ~1.6x faster nested settings reads on hot paths. `@configs_refs` remains the canonical store; non-identifier setting names (e.g. registered names with dashes) keep the previous hash-based accessors. - [Enhancement] Instantiate each `Configurable::Node` through a per-layout anonymous subclass so the ivar-backed settings do not grow object shape variations on the shared `Node` class (which would degrade ivar access and trigger Ruby performance warnings). `deep_dup` reuses the template's subclass, so duplicated configs share object shapes. - [Fix] Symbolize setting names at definition time (`setting`, same as `register`) and on config store writes so `String` setting names work end to end (accessors, `#to_h`, recompilation state) and cannot corrupt node internal state when matching reserved internal names (previously string-named settings were quietly broken as accessors and the store disagreed on the key type). - [Change] Config nodes are now instances of anonymous `Node` subclasses: `is_a?(Karafka::Core::Configurable::Node)` still holds, but `instance_of?(Node)` is now `false` and `node.class.name` is `nil`. - [Change] Assigning a setting on a frozen config node now raises `FrozenError` (previously the write silently mutated internal storage despite the freeze). ## Karafka Core Changelog / 2.6.0 (2026-06-10) - [Enhancement] Add `Node#register` to allow runtime key-value registration on compiled nodes without going through the static `setting` DSL. Useful for dynamic registries (e.g. named clusters) where setting names are not known at class-load time. - [Enhancement] Replace version-gated `Warning[:performance]` with a `Warning.categories`-based loop that enables all opt-in Ruby warning categories automatically, picking up new categories (e.g. `strict_unused_block` in Ruby 3.4+) without future patches. ## Karafka Core Changelog / 2.5.13 (2026-04-08) - [Enhancement] Extract `decorate_partitions` method from `StatisticsDecorator` to allow subclasses to filter which partitions are decorated (e.g. skip unassigned partitions in a consumer context). ## Karafka Core Changelog / 2.5.12 (2026-04-02) - [Fix] Exclude `test/` directory from gem releases to reduce package size. ## Karafka Core Changelog / 2.5.11 (2026-04-02) - [Enhancement] Specialize `Contract#dig` for common 1-key and 2-key paths to avoid iterator overhead, yielding ~1.5x faster single-key lookups and ~1.45x faster two-key nested lookups. - [Enhancement] Replace `Node#build_accessors` `@local_defs` Array with Hash for O(1) membership checks instead of O(n) `Array#include?`, yielding up to ~5x faster accessor lookups at 50 settings. - [Enhancement] Use frozen `EMPTY_ARRAY` constant for `Contract#call` and `#validate!` default `scope` parameter to avoid allocating a new Array on every invocation, yielding ~1.36x faster call dispatch and saving 1 Array allocation per call. - [Enhancement] Pre-resolve `@events_methods_map` method name before the listener notification loop in `Notifications#instrument` to avoid repeated Hash lookup per listener, yielding ~1.12x faster event dispatch with multiple listeners. - [Enhancement] Cache a frozen success `Result` singleton via `Result.success` to eliminate 1 object allocation per successful `Contract#call` on the happy path. - [Enhancement] Skip nestings block re-evaluation in `Node#deep_dup` to avoid recreating children that are immediately overwritten, yielding ~14x faster deep_dup and reducing allocations from ~620 to ~66 objects for large configs. - [Enhancement] Cache `CallbacksManager#call` values snapshot and invalidate on `add`/`delete` to avoid allocating a new Array on every invocation while preserving thread-safety snapshot semantics, saving 1 Array allocation per call. - [Enhancement] Store execution time separately in `Event` and build the merged payload hash lazily on `#payload` access, eliminating 1 Hash allocation per `Notifications#instrument` call when listeners use `#[]` access (the common pattern), yielding ~1.7x faster event dispatch. - [Enhancement] Replace `StatisticsDecorator#diff` pending-writes buffer with `keys.each` direct-write iteration, eliminating the buffer and write-back loop for ~13% faster decoration at scale (10 brokers, 20 topics, 2000 partitions). - [Enhancement] Reorder `StatisticsDecorator#diff` type checks to test `Numeric` before `Hash`, matching the ~80% numeric value distribution in librdkafka statistics. - [Enhancement] Support `only_keys` option in `StatisticsDecorator` to decorate only specified numeric keys (e.g. `consumer_lag`, `committed_offset`). When combined with `excluded_keys`, reduces decoration cost from ~80ms to ~8.5ms per call on large clusters (10 brokers, 20 topics, 2000 partitions) by using structure-aware navigation of the librdkafka statistics tree and direct key access instead of full-hash iteration. - [Enhancement] Cache `Tags#to_a` values array and invalidate on `add`/`delete`/`clear` to avoid allocating a new Array and running `uniq` on every call, yielding ~7x faster reads at 5 tags and ~28x faster at 20 tags. ## Karafka Core Changelog / 2.5.10 (2026-03-02) - [Enhancement] Introduce `MinitestLocator` helper for minitest/spec subject class auto-discovery from test file paths. ## Karafka Core Changelog / 2.5.9 (2026-03-02) - [Enhancement] Optimize `StatisticsDecorator` to eliminate per-hash Array allocations by using `each_pair` with a per-call pending-writes buffer instead of `current.keys.each`, reducing allocations from tens of thousands to one per call at scale. - [Enhancement] Inline `StatisticsDecorator#append` and `#suffix_keys_for` into `#diff` to reduce method call overhead by ~96% (from ~915k to ~39k calls at 6400 partitions). - [Enhancement] Support `excluded_keys` option in `StatisticsDecorator` to skip decoration of unused librdkafka statistics subtrees (e.g. broker toppars, window stats), yielding ~28% additional speedup at scale. ## Karafka Core Changelog / 2.5.8 (2025-11-23) - [Enhancement] Memoize `StatisticsDecorator` suffix keys to reduce string allocations (#268). ## Karafka Core Changelog / 2.5.7 (2025-09-28) - [Enhancement] Optimize `Node#deep_dup` to reduce array allocations during configuration deep copying. - [Enhancement] Optimize `Result#initialize` to use shared `EMPTY_HASH` constant for successful validations. - [Enhancement] Optimize `StatisticsDecorator#append` string concatenation to reduce allocations. - [Enhancement] Optimize `Notifications#instrument` payload handling to avoid unnecessary hash merges for empty payloads. - **[EOL]** Remove Ruby 3.1 support due to EOL. ## Karafka Core Changelog / 2.5.6 (2025-09-02) - [Change] Normalize how libs and dependencies are required (no functional change for the end user) - [Change] Set minimum `karafka-rdkafka` on `0.20.0` to support new features and allow for open range as both `waterdrop` and `karafka` manage this. ## Karafka Core Changelog / 2.5.5 (2025-08-04) - [Enhancement] Remove reliance on `Set` class. ## Karafka Core Changelog / 2.5.4 (2025-08-04) - [Fix] Fix old regression on misbehaviour when Object methods are overwritten. ## Karafka Core Changelog / 2.5.3 (2025-08-04) - [Enhancement] Optimize code to mitigate the Ruby performance warning from `Karafka::Core::Configurable::Node` (#208) - [Enhancement] Raise errors on detected Ruby warnings. - [Change] Remove unused Ruby 2.7 code. - [Change] Remove `funding_uri` from the gemspec to minimize double-funding info. ## Karafka Core Changelog / 2.5.2 (2025-06-11) - [Enhancement] Support `#unsubscribe`. - [Enhancement] Allow for providing a root scope path for error keys. - [Fix] Fix a bug where on no errors the result would be an array instead of a hash. - [Fix] Fix spec hanging when Kafka cluster on 9092 is running. ## Karafka Core Changelog / 2.5.1 (2025-05-23) - [Change] Move to trusted-publishers and remove signing since no longer needed. ## Karafka Core Changelog / 2.5.0 (2025-05-21) - [Change] Set minimum `karafka-rdkafka` on `0.19.2` to support new features. ## Karafka Core Changelog / 2.4.11 (2025-03-20) - [Enhancement] Rename internal node `#name` method to `#node_name` so we can use `#name` as the attribute name. ## Karafka Core Changelog / 2.4.10 (2025-03-14) - [Fix] Relax lock on `karafka-rdkafka` ## Karafka Core Changelog / 2.4.9 (2025-03-03) - [Enhancement] Remove `RspecLocator` dependency on `activesupport`. ## Karafka Core Changelog / 2.4.8 (2024-12-26) - [Maintenance] Declare `logger` as a dependency. ## Karafka Core Changelog / 2.4.7 (2024-11-26) - [Fix] Make sure that `karafka-core` works with older versions of `karafka-rdkafka` that do not support macos fork mitigation. ## Karafka Core Changelog / 2.4.6 (2024-11-26) - [Enhancement] Mitigate macos forking issues when librdkafka is not loaded to memory. - [Change] Allow `karafka-rdkafka` `0.18.0`. ## Karafka Core Changelog / 2.4.5 (2024-11-19) - **[EOL]** Drop Ruby `3.0` support according to the EOL schedule. - [Enhancement] Support listeners inspection via `#listeners`. - [Fix] Restore `#available_events` notifications bus method. - [Change] Set minimum `karafka-rdkafka` on `0.17.6` to support new features. ## Karafka Core Changelog / 2.4.4 (2024-07-20) - [Change] Set minimum `karafka-rdkafka` on `0.16.0` to support new features and allow for `0.17.0`. ## Karafka Core Changelog / 2.4.3 (2024-06-18) - [Fix] Use `Object` instead of `BasicObject` for rule result comparison because of Time mismatch with BasicObject. ## Karafka Core Changelog / 2.4.2 (2024-06-17) - [Enhancement] Allow `karafka-rdkafka` `0.16.x` to be used since API compatible. ## Karafka Core Changelog / 2.4.1 (2024-06-17) - [Enhancement] Provide fast-track for events without subscriptions to save on allocations. - [Enhancement] Save memory allocation on each contract rule validation execution. - [Enhancement] Save one allocation per `float_now` + 2-3x performance by using the Posix clock instead of `Time.now.utc.to_f`. - [Enhancement] Use direct `float_millisecond` precision in `monotonic_now` not to multiply by 1000 (allocations and CPU savings). - [Enhancement] Save one array allocation on one instrumentation. - [Enhancement] Allow clearing one event type (dorner). ## Karafka Core Changelog / 2.4.0 (2024-04-26) - **[EOL]** Drop Ruby `2.7` support. - [Enhancement] Provide necessary alterations for custom oauth token callbacks to operate. - [Change] Set minimum `karafka-rdkafka` on `0.15.0` to support new features. ## Karafka Core Changelog / 2.3.0 (2024-01-26) - [Change] Set minimum `karafka-rdkafka` on `0.14.8` to support new features. - [Change] Remove `concurrent-ruby` usage. ## Karafka Core Changelog / 2.2.7 (2023-11-07) - [Change] Set minimum `karafka-rdkafka` on `0.13.9` to support alternative consumer builder. ## Karafka Core Changelog / 2.2.6 (2023-11-03) - [Enhancement] Set backtrace for errors propagated via the errors callbacks. ## Karafka Core Changelog / 2.2.5 (2023-10-31) - **[EOL]** Drop support for Ruby 2.6 due to incompatibilities in usage of `ObjectSpace::WeakMap` - [Change] Set minimum `karafka-rdkafka` on `0.13.8` to support consumer `#position`. ## Karafka Core Changelog / 2.2.4 (2023-10-25) - [Enhancement] Allow for `lazy` evaluated constructors. - [Enhancement] Allow no-arg constructors. ## Karafka Core Changelog / 2.2.3 (2023-10-17) - [Change] Set minimum `karafka-rdkafka` on `0.13.6`. ## Karafka Core Changelog / 2.2.2 (2023-09-11) - [Fix] Reuse previous frozen duration as a base for incoming computation. ## Karafka Core Changelog / 2.2.1 (2023-09-10) - Optimize statistics decorator by minimizing number of new objects created. - Expand the decoration to include new value `_fd` providing freeze duration in milliseconds. This value informs us for how many consecutive ms the given value did not change. It can be useful for detecting values that should change once in a while but are stale. ## Karafka Core Changelog / 2.2.0 (2023-09-01) - [Maintenance] Update the signing cert (old expired) ## Karafka Core Changelog / 2.1.1 (2023-06-28) - [Change] Set minimum `karafka-rdkafka` on `0.13.1`. ## Karafka Core Changelog / 2.1.0 (2023-06-19) - [Change] Set `karafka-rdkafka` requirement from `>= 0.13.0` to `<= 0.14.0`. - [Change] Remove no longer needed patch. ## Karafka Core Changelog / 2.0.13 (2023-05-26) - Set minimum `karafka-rdkafka` on `0.12.3`. ## Karafka Core Changelog / 2.0.12 (2023-02-23) - Introduce ability to tag certain objects by including the `Karafka::Core::Taggable` module. ## Karafka Core Changelog / 2.0.11 (2023-02-12) - Set minimum `karafka-rdkafka` on `0.12.1`. ## Karafka Core Changelog / 2.0.10 (2023-02-01) - Move `RspecLocator` to core. ## Karafka Core Changelog / 2.0.9 (2023-01-11) - Use `karafka-rdkafka` instead of `rdkafka`. This change is needed to ensure that all consecutive releases are stable and compatible. - Relax Ruby requirement to `2.6`. It does not mean we officially support it but it may work. Go to [Versions Lifecycle and EOL](https://karafka.io/docs/Versions-Lifecycle-and-EOL/) for more details. ## Karafka Core Changelog / 2.0.8 (2023-01-07) - Add `Karafka::Core::Helpers::Time` utility for time reporting. ## Karafka Core Changelog / 2.0.7 (2022-12-18) - Allow for recompilation of config upon injecting new config nodes. - Compile given config scope automatically after it is defined. - Support sub-config merging via their nested definitions. ## Karafka Core Changelog / 2.0.6 (2022-12-07) - Reverse node compilation state tracking removal. ## Karafka Core Changelog / 2.0.5 (2022-12-07) - Move `librdkafka` generic (producer and consumer) patches from WaterDrop here. - Move dependency on `librdkafka` here from both Karafka and WaterDrop to unify management. - Move `CallbacksManager` from WaterDrop because it's shared. ## Karafka Core Changelog / 2.0.4 (2022-11-20) - Disallow publishing events that were not registered. - Fix a potential race condition when adding listeners concurrently from multiple threads. ## Karafka Core Changelog / 2.0.3 (2022-10-13) - Maintenance release. Cert chain update. No code changes. ## Karafka Core Changelog / 2.0.2 (2022-08-01) - Add extracted statistics decorator (#932) ## Karafka Core Changelog / 2.0.1 (2022-07-30) - Fix a case where setting would match a method monkey-patched on an object (#1) causing initializers not to build proper accessors on nodes. This is not the core bug, but still worth handling this case. ## Karafka Core Changelog / 2.0.0 (2022-07-28) - Initial extraction of common components used in the Karafka ecosystem from WaterDrop. --- *Last modified: 2026-06-29 20:46:37*