gems karafka-core 2.6.2
v2.6.2

2 hours ago
  • [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 NoMethodErrornil.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.

Don't miss a new karafka-core release

NewReleases is sending notifications on new releases.