This is an automated email from the ASF dual-hosted git repository.

frankvicky pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 90b1ab7fc78 KAFKA-20630: Add documentation for topology description 
plugin feature (#22776)
90b1ab7fc78 is described below

commit 90b1ab7fc782b6530d9a71fb2437e85fc3061985
Author: Alieh Saeedi <[email protected]>
AuthorDate: Tue Jul 14 14:08:49 2026 +0200

    KAFKA-20630: Add documentation for topology description plugin feature 
(#22776)
    
    Documents the streams group topology description plugin
    
([KIP-1331](https://cwiki.apache.org/confluence/display/KAFKA/KIP-1331%3A+Streams+Group+Topology+Description+Plugin));
    docs subtask of KAFKA-20618.
    
    ### Changes
    
    - **New page**
    `docs/streams/developer-guide/topology-description-plugin.md`: feature
    overview, the push/describe cycle (heartbeat solicitation via
    `TopologyDescriptionRequired`, the
    `StreamsGroupTopologyDescriptionUpdate` RPC, permanent vs. transient
    plugin failures and the per-group back-off, describe via
    `StreamsGroupDescribe` v1), broker and client configuration, plugin
    implementation guidelines, Admin API and CLI usage,
    `TopologyDescriptionStatus` interpretation, `GROUP_DELETION_FAILED`
    semantics, and troubleshooting.
    - `config-streams.md`: add `topology.description.push.enabled` to the
    config table and the detailed entries.
    - `kafka-streams-group-sh.md`: document `--topology` output format,
    broker requirements (4.4+, plugin configured), and the tool's error
    messages / exit-code behavior.
    - `streams-rebalance-protocol.md`: list the feature as supported, add
    `group.streams.topology.description.plugin.class` to the broker-config
    list, and link the new page from the administration section.
    - `getting-started/upgrade.md`: notable-changes entry for 4.4.0 covering
    the new RPC, the `StreamsGroupDescribe`/`StreamsGroupHeartbeat` v1
    bumps, `DeleteGroups` v3 with per-group `ErrorMessage`, the new error
    codes `GROUP_DELETION_FAILED` (134) and
    `STREAMS_TOPOLOGY_DESCRIPTION_UPDATE_FAILED` (135), and the new
    broker/client configs.
    - `streams/upgrade-guide.md`: 4.4.0 entry from the application
    perspective.
    - `operations/basic-kafka-operations.md`: point streams-group management
    at `kafka-streams-groups.sh`, including `--topology`.
    - `scala-migration.md`: weight bump only (16 → 17) to make room for the
    new page in the developer-guide ordering.
    
    All described behavior was verified against the implementation
    (`StreamsGroupTopologyDescriptionPlugin` SPI,
    `StreamsGroupTopologyDescriptionManager`, `StreamsGroupCommand`, the
    message JSON schemas, and the config definitions).
    
    ### Committer Checklist (excluded from commit message)
    - [ ] Verify design and implementation
    - [ ] Verify test coverage and CI build status
    - [ ] Verify documentation (including upgrade notes)
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Reviewers: TengYao Chi <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Fable 5 <[email protected]>
---
 docs/getting-started/upgrade.md                    |   1 +
 docs/operations/basic-kafka-operations.md          |   2 +-
 docs/operations/monitoring.md                      | 208 +++++++++++++++++++++
 docs/streams/developer-guide/config-streams.md     |  23 +++
 .../developer-guide/kafka-streams-group-sh.md      |  23 ++-
 docs/streams/developer-guide/scala-migration.md    |   2 +-
 .../developer-guide/streams-rebalance-protocol.md  |   7 +
 .../developer-guide/topology-description-plugin.md | 195 +++++++++++++++++++
 docs/streams/upgrade-guide.md                      |   2 +
 9 files changed, 460 insertions(+), 3 deletions(-)

diff --git a/docs/getting-started/upgrade.md b/docs/getting-started/upgrade.md
index f2594cdd3e8..bd429ee95b6 100644
--- a/docs/getting-started/upgrade.md
+++ b/docs/getting-started/upgrade.md
@@ -44,6 +44,7 @@ type: docs
     For further details, please refer to 
[KIP-1301](https://cwiki.apache.org/confluence/x/Z5U8G).
   * The broker-side OAUTHBEARER JWT validator now fails fast at startup when a 
JWKS endpoint (`sasl.oauthbearer.jwks.endpoint.url`) is configured but 
`sasl.oauthbearer.expected.audience` or `sasl.oauthbearer.expected.issuer` is 
not set. Brokers that previously started without these settings will now fail 
to start until they are configured. To intentionally accept tokens regardless 
of their audience or issuer, set the new 
`sasl.oauthbearer.allow.unverified.audience` or `sasl.oauthbearer.a [...]
   * When clients connect to the cluster, they now include cluster and node 
information to enable detection and handling of misrouted connections. For 
further details, please refer to 
[KIP-1242](https://cwiki.apache.org/confluence/x/W4LMFw).
+  * Brokers can now record a human-readable description of each streams 
group's processing topology via a pluggable backend, retrievable through 
`Admin#describeStreamsGroups` and `kafka-streams-groups.sh --describe 
--topology`. The feature is disabled unless the new broker configuration 
`group.streams.topology.description.plugin.class` is set to a 
`StreamsGroupTopologyDescriptionPlugin` implementation; on the client side, the 
new Kafka Streams configuration `topology.description.push.ena [...]
 
 ## Upgrading to 4.3.0
 
diff --git a/docs/operations/basic-kafka-operations.md 
b/docs/operations/basic-kafka-operations.md
index 4ed37d87417..d5146f7404d 100644
--- a/docs/operations/basic-kafka-operations.md
+++ b/docs/operations/basic-kafka-operations.md
@@ -151,7 +151,7 @@ my-topic                       2          2               3 
              1
 
 ## Managing groups
 
-With the GroupCommand tool, we can list groups of all types, including 
consumer groups, share groups and streams groups. Each type of group has its 
own tool for administering groups of that type. For example, to list all groups 
in the cluster: 
+With the GroupCommand tool, we can list groups of all types, including 
consumer groups, share groups and streams groups. Each type of group has its 
own tool for administering groups of that type. For streams groups, use the 
[bin/kafka-streams-groups.sh](/{version}/streams/developer-guide/kafka-streams-group-sh/)
 tool to list, describe (including the group's processing topology via 
`--describe --topology`, when a [topology description 
plugin](/{version}/streams/developer-guide/topology-de [...]
 
 ```bash
 $ bin/kafka-groups.sh --bootstrap-server localhost:9092 --list
diff --git a/docs/operations/monitoring.md b/docs/operations/monitoring.md
index 3f5fb0ec66f..92badfae27a 100644
--- a/docs/operations/monitoring.md
+++ b/docs/operations/monitoring.md
@@ -1348,6 +1348,214 @@ Total number of Streams Group Rebalances
 <tr>  
 <td>
 
+Topology Description Set Success Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-set-success-rate
+</td>  
+<td>
+
+The rate of successful setTopology plugin calls (driven by client 
topology-description pushes)
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Set Success Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-set-success-count
+</td>  
+<td>
+
+The total number of successful setTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Set Error Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-set-error-rate
+</td>  
+<td>
+
+The rate of failed setTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Set Error Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-set-error-count
+</td>  
+<td>
+
+The total number of failed setTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Get Success Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-get-success-rate
+</td>  
+<td>
+
+The rate of successful getTopology plugin calls (driven by describe requests)
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Get Success Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-get-success-count
+</td>  
+<td>
+
+The total number of successful getTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Get Error Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-get-error-rate
+</td>  
+<td>
+
+The rate of failed getTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Get Error Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-get-error-count
+</td>  
+<td>
+
+The total number of failed getTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Delete Success Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-delete-success-rate
+</td>  
+<td>
+
+The rate of successful deleteTopology plugin calls (driven by group deletion 
and cleanup)
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Delete Success Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-delete-success-count
+</td>  
+<td>
+
+The total number of successful deleteTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Delete Error Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-delete-error-rate
+</td>  
+<td>
+
+The rate of failed deleteTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Delete Error Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-delete-error-count
+</td>  
+<td>
+
+The total number of failed deleteTopology plugin calls
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Cleanup Cycle Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-cleanup-cycle-rate
+</td>  
+<td>
+
+The rate of periodic topology-description cleanup cycles run by the coordinator
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Cleanup Cycle Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-cleanup-cycle-count
+</td>  
+<td>
+
+The total number of periodic topology-description cleanup cycles run by the 
coordinator
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Cleanup Eligible Rate
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-cleanup-eligible-rate
+</td>  
+<td>
+
+The rate of groups found eligible for plugin-state deletion by the cleanup scan
+</td> </tr>  
+<tr>  
+<td>
+
+Topology Description Cleanup Eligible Count
+</td>  
+<td>
+
+kafka.server:type=group-coordinator-metrics,name=streams-group-topology-description-cleanup-eligible-count
+</td>  
+<td>
+
+The total number of groups found eligible for plugin-state deletion by the 
cleanup scan
+</td> </tr>  
+<tr>  
+<td>
+
 Classic Group Count
 </td>  
 <td>
diff --git a/docs/streams/developer-guide/config-streams.md 
b/docs/streams/developer-guide/config-streams.md
index 51bacbc2066..80c13125a9b 100644
--- a/docs/streams/developer-guide/config-streams.md
+++ b/docs/streams/developer-guide/config-streams.md
@@ -1131,6 +1131,23 @@ The maximum amount of time in milliseconds a task might 
stall due to internal er
 <tr>  
 <td>
 
+topology.description.push.enabled
+</td>  
+<td>
+
+Medium
+</td>  
+<td>
+
+Controls whether the Kafka Streams client sends topology descriptions to the 
broker when requested. When set to `false`, the client will not prepare or push 
topology descriptions. See [Topology Description 
Plugin](/{version}/streams/developer-guide/topology-description-plugin/).
+</td>  
+<td>
+
+`true`
+</td> </tr>  
+<tr>  
+<td>
+
 topology.optimization
 </td>  
 <td>
@@ -1691,6 +1708,12 @@ Serde for the inner class of a windowed record. Must 
implement the `Serde` inter
 
 > A task assignor class or class name implementing the 
 > `org.apache.kafka.streams.processor.assignment.TaskAssignor` interface. 
 > Defaults to the high-availability task assignor. One possible alternative 
 > implementation provided in Apache Kafka is the 
 > `org.apache.kafka.streams.processor.assignment.assignors.StickyTaskAssignor`,
 >  which was the default task assignor before KIP-441 and minimizes task 
 > movement at the cost of stateful task availability. Alternative 
 > implementations of the task assi [...]
  
+ #### topology.description.push.enabled
+
+> Controls whether the Kafka Streams client sends topology descriptions to the 
broker when requested. When set to `false`, the client will not prepare or push 
topology descriptions. Enabled by default.
+
+This configuration only has an effect for streams groups 
(`group.protocol=streams`) on clusters where the broker configuration 
`group.streams.topology.description.plugin.class` is set; otherwise, the broker 
never requests topology descriptions. See [Topology Description 
Plugin](/{version}/streams/developer-guide/topology-description-plugin/) for 
details.
+ 
  #### topology.optimization
 
 > A configuration telling Kafka Streams if it should optimize the topology and 
 > what optimizations to apply. Acceptable values are: 
 > `StreamsConfig.NO_OPTIMIZATION` (`none`), `StreamsConfig.OPTIMIZE` (`all`) 
 > or a comma separated list of specific optimizations: 
 > `StreamsConfig.REUSE_KTABLE_SOURCE_TOPICS` (`reuse.ktable.source.topics`), 
 > `StreamsConfig.MERGE_REPARTITION_TOPICS` (`merge.repartition.topics`), 
 > `StreamsConfig.SINGLE_STORE_SELF_JOIN` (`single.store.self.join`). 
diff --git a/docs/streams/developer-guide/kafka-streams-group-sh.md 
b/docs/streams/developer-guide/kafka-streams-group-sh.md
index cbde1399e50..c8d4b77b197 100644
--- a/docs/streams/developer-guide/kafka-streams-group-sh.md
+++ b/docs/streams/developer-guide/kafka-streams-group-sh.md
@@ -41,7 +41,7 @@ A **Streams group** is a broker‑coordinated group type for 
Kafka Streams that
     * Group state, group epoch, target assignment epoch (with `--state`, 
`--verbose` for additional details).
     * Per‑member info such as epochs, current vs target assignments, and 
whether a member still uses the classic protocol (with `--members` and 
`--verbose`).
     * Input‑topic offsets and lag (with `--offsets`), to understand how far 
behind processing is.
-    * The processing topology, as recorded by the broker's topology 
description plugin (with `--topology`), in a format that mirrors 
`Topology#describe()`.
+    * The processing topology, as recorded by the broker's [topology 
description 
plugin](/{version}/streams/developer-guide/topology-description-plugin/) (with 
`--topology`), in a format that mirrors `Topology#describe()`. Requires brokers 
running Apache Kafka 4.4 or newer with 
`group.streams.topology.description.plugin.class` configured.
   * **Reset input‑topic offsets** for a Streams group to control reprocessing 
boundaries using precise specifiers (earliest, latest, to‑offset, to‑datetime, 
by‑duration, shift‑by, from‑file). Requires `--dry-run` or `--execute` and 
inactive instances.
   * **Delete offsets** for input topics to force re‑consumption on next start.
   * **Delete a Streams group** to clean up broker‑side Streams metadata 
(offsets, topology, assignments). Internal topics can be deleted by specifying 
selected topics with `--delete-internal-topic`, or all internal topics with 
`--delete-all-internal-topics`.
@@ -90,6 +90,27 @@ Inspecting group's state, members, and lag
       --describe --group my-streams-app --topology
     
 
+### Describing the processing topology {#describe-topology}
+
+The `--topology` option prints the processing topology of the group, as 
recorded by the broker's [topology description 
plugin](/{version}/streams/developer-guide/topology-description-plugin/), in a 
format that mirrors `Topology#describe()`:
+
+    
+    Topologies:
+       Sub-topology: 0
+        Source: KSTREAM-SOURCE-0000000000 (topics: [streams-plaintext-input])
+          --> KSTREAM-FLATMAPVALUES-0000000001
+        Processor: KSTREAM-FLATMAPVALUES-0000000001 (stores: [])
+          --> KSTREAM-AGGREGATE-0000000002
+          <-- KSTREAM-SOURCE-0000000000
+        ...
+
+This requires brokers running Apache Kafka 4.4 or newer with the broker 
configuration `group.streams.topology.description.plugin.class` set; against 
older brokers the command fails with `UnsupportedVersionException`. If no 
topology description is available, the tool prints one of the following 
messages and exits with a non-zero exit code:
+
+  * `No topology description is stored for streams group '<id>'.` — No 
description is recorded, for example because no topology description plugin is 
configured on the broker or the application has not pushed a description yet.
+  * `The broker failed to fetch the topology description for streams group 
'<id>'. See the broker logs for details.` — The broker's plugin failed to read 
the stored description.
+
+See the [Topology Description 
Plugin](/{version}/streams/developer-guide/topology-description-plugin/) 
documentation for how the feature works and how to troubleshoot it.
+
 ## Reset input-topic offsets (preview, then apply) {#reset-offsets}
 
 Ensure all application instances are stopped/inactive. Always preview changes 
with `--dry-run` before using `--execute`.
diff --git a/docs/streams/developer-guide/scala-migration.md 
b/docs/streams/developer-guide/scala-migration.md
index 0975fce0441..de8a03213a3 100644
--- a/docs/streams/developer-guide/scala-migration.md
+++ b/docs/streams/developer-guide/scala-migration.md
@@ -1,7 +1,7 @@
 ---
 title: Migrating from Streams Scala to Java API
 description: Migration guidance from the Kafka Streams Scala API to the Java 
API.
-weight: 16
+weight: 17
 tags: ['kafka', 'docs']
 aliases:
 keywords:
diff --git a/docs/streams/developer-guide/streams-rebalance-protocol.md 
b/docs/streams/developer-guide/streams-rebalance-protocol.md
index eb49f43dc5d..5f9cc280d58 100644
--- a/docs/streams/developer-guide/streams-rebalance-protocol.md
+++ b/docs/streams/developer-guide/streams-rebalance-protocol.md
@@ -47,6 +47,8 @@ The following features are available in the current release:
 
 * **CLI Integration**: You can list, describe, and delete streams groups via 
the 
[bin/kafka-streams-groups.sh](/{version}/streams/developer-guide/kafka-streams-group-sh/)
 script.
 
+* **Topology Description Plugin**: Brokers can record a human-readable 
description of each streams group's processing topology via a pluggable 
backend, configured with `group.streams.topology.description.plugin.class`. The 
recorded topology can be inspected via the 
[`Admin`](/{version}/javadoc/org/apache/kafka/clients/admin/Admin.html) 
interface or `kafka-streams-groups.sh --describe --topology`. See the [Topology 
Description Plugin](/{version}/streams/developer-guide/topology-descriptio [...]
+
 * **Offline Migration**: After shutting down all members and waiting for their 
`session.timeout.ms` to expire (or forcing an explicit group leave), a classic 
group can be converted to a streams group and a streams group can be converted 
to a classic group. The only broker-side group data that will be preserved are 
the committed offsets. Internal topics (changelog and repartition topics) will 
continue to exist as regular Kafka topics.
 
 * **Static Membership**: Streams applications can configure 
`group.instance.id` when using `group.protocol=streams`. Kafka Streams derives 
unique group instance IDs for its stream threads internally.
@@ -117,6 +119,7 @@ The following broker configurations control the behavior of 
streams groups. For
 * 
[`group.streams.num.standby.replicas`](/{version}/configuration/broker-configs#brokerconfigs_group.streams.num.standby.replicas):
 The default number of standby replicas for each task.
 * 
[`group.streams.max.standby.replicas`](/{version}/configuration/broker-configs#brokerconfigs_group.streams.max.standby.replicas):
 Maximum for dynamic configurations of the standby replica configuration.
 * 
[`group.streams.initial.rebalance.delay.ms`](/{version}/configuration/broker-configs#brokerconfigs_group.streams.initial.rebalance.delay.ms):
 The first rebalance of a new (ie, previously empty) group is delayed by this 
amount to allow more members to join the group.
+* 
[`group.streams.topology.description.plugin.class`](/{version}/configuration/broker-configs#brokerconfigs_group.streams.topology.description.plugin.class):
 The fully qualified class name of a `StreamsGroupTopologyDescriptionPlugin` 
implementation. When not set, the [topology description 
feature](/{version}/streams/developer-guide/topology-description-plugin/) is 
disabled.
 
 ## Group Configuration
 
@@ -179,6 +182,10 @@ The main differences from consumer group APIs are:
 
 A new tool called `bin/kafka-streams-groups.sh` is added for working with 
streams groups. It replaces `bin/kafka-streams-application-reset.sh` for 
streams groups and can be used to list, describe, and delete streams groups. 
See the [kafka-streams-groups.sh 
documentation](/{version}/streams/developer-guide/kafka-streams-group-sh/) for 
detailed usage information.
 
+## Topology Description
+
+When a topology description plugin is configured on the brokers via 
`group.streams.topology.description.plugin.class`, the group coordinator 
records a human-readable description of each streams group's processing 
topology, pushed automatically by the Kafka Streams clients. The description 
can be retrieved via `Admin#describeStreamsGroups` or `kafka-streams-groups.sh 
--describe --topology`. See the [Topology Description 
Plugin](/{version}/streams/developer-guide/topology-description-plugi [...]
+
 # Architecture and How It Works
 
 ## Streams Groups
diff --git a/docs/streams/developer-guide/topology-description-plugin.md 
b/docs/streams/developer-guide/topology-description-plugin.md
new file mode 100644
index 00000000000..a90314770c8
--- /dev/null
+++ b/docs/streams/developer-guide/topology-description-plugin.md
@@ -0,0 +1,195 @@
+---
+title: Topology Description Plugin
+type: docs
+description: Broker-side plugin for recording and exposing the processing 
topology of streams groups.
+weight: 16
+tags: ['kafka', 'docs']
+aliases: 
+keywords: 
+---
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+Starting with Apache Kafka 4.4, brokers can record a human-readable 
description of the processing topology of each **streams group**, as defined by 
[KIP-1331](https://cwiki.apache.org/confluence/display/KAFKA/KIP-1331%3A+Streams+Group+Topology+Description+Plugin).
 Kafka Streams clients push the same information that `Topology#describe()` 
returns to the group coordinator, which hands it to a pluggable, broker-side 
storage backend. Operators can then inspect the topology of any streams gro 
[...]
+
+# Overview
+
+The feature applies only to streams groups using the [Streams Rebalance 
Protocol](/{version}/streams/developer-guide/streams-rebalance-protocol/) 
(`group.protocol=streams`, KIP-1071). It is **disabled by default**: the broker 
only solicits, stores, and serves topology descriptions when the broker 
configuration `group.streams.topology.description.plugin.class` is set to a 
`StreamsGroupTopologyDescriptionPlugin` implementation.
+
+When the feature is enabled:
+
+  * Kafka Streams clients automatically push a description of their topology 
when the broker requests one — no application code changes are required. The 
push can be turned off per client via the Streams configuration 
`topology.description.push.enabled`.
+  * The description is versioned by the group's **topology epoch**, so the 
broker always knows whether its stored description matches the topology the 
group is currently running.
+  * The stored description can be retrieved with `Admin#describeStreamsGroups` 
(using `DescribeStreamsGroupsOptions#includeTopologyDescription(true)`) or with 
`kafka-streams-groups.sh --describe --topology`.
+
+# How it works: the push/describe cycle
+
+The feature adds one new RPC, `StreamsGroupTopologyDescriptionUpdate`, and 
extends the existing `StreamsGroupHeartbeat` and `StreamsGroupDescribe` RPCs. 
The cycle works as follows:
+
+  1. **Solicitation.** When the group coordinator has not yet recorded a 
successful push for the group's current topology epoch (for example, a new 
group or a topology change that bumped the epoch), it sets the 
`TopologyDescriptionRequired` flag in the `StreamsGroupHeartbeat` response.
+  2. **Push.** A client that sees this flag — and has 
`topology.description.push.enabled=true` — sends a 
`StreamsGroupTopologyDescriptionUpdate` request to the group coordinator, 
containing its group ID, member ID, the topology epoch, and the topology 
description (subtopologies, sources, processors, sinks, state stores, and 
global stores).
+  3. **Store.** The broker validates that the sender is a known member of the 
group and invokes the plugin's `setTopology(groupId, topologyEpoch, 
description)` method. On success, the broker records the stored topology epoch 
and stops soliciting. Multiple members may push concurrently for the same 
epoch; the pushed data is identical, and the plugin must handle this 
idempotently.
+  4. **Failure handling.** If the plugin fails to store the description, the 
broker distinguishes two cases:
+     * A **permanent failure** 
(`StreamsTopologyDescriptionPermanentFailureException`) means the description 
will never be accepted at this topology epoch (for example, it is too large or 
semantically rejected). The broker records the failed epoch and stops 
soliciting until the topology epoch advances.
+     * A **transient failure** 
(`StreamsTopologyDescriptionTransientFailureException`, or any other exception) 
causes the broker to arm a per-group exponential back-off (30 seconds up to 1 
hour) and re-solicit the description on a later heartbeat.
+
+     In both cases, the pushing client receives the error code 
`STREAMS_TOPOLOGY_DESCRIPTION_UPDATE_FAILED`. The client does not retry on its 
own; the broker drives retries through heartbeat solicitation.
+  5. **Describe.** When a caller requests the topology description via 
`StreamsGroupDescribe` (version 1 or higher, with 
`IncludeTopologyDescription=true`), the broker invokes the plugin's 
`getTopology(groupId, topologyEpoch)` method and attaches the description 
together with a status field to the response. See [Interpreting the topology 
description status](#interpreting-the-topology-description-status) below.
+  6. **Deletion.** When a streams group is deleted (via `DeleteGroups`) or 
expires, the broker invokes the plugin's `deleteTopology(groupId)` method so 
that the plugin can clean up its stored data. See [Group deletion and 
GROUP_DELETION_FAILED](#group-deletion-and-group_deletion_failed) below for the 
failure semantics.
+
+# Broker configuration
+
+  * 
[`group.streams.topology.description.plugin.class`](/{version}/configuration/broker-configs#brokerconfigs_group.streams.topology.description.plugin.class):
 The fully qualified class name of a `StreamsGroupTopologyDescriptionPlugin` 
implementation. When not set (the default), the feature is disabled: the broker 
never solicits topology descriptions, and describe requests report status 
`NOT_STORED`.
+
+Apache Kafka ships a reference implementation, 
`org.apache.kafka.server.streams.InMemoryTopologyDescriptionPlugin`, which 
stores one description per group in an in-memory map. It is intended for 
testing and as a starting point for real implementations. It is **not suitable 
for production** because its state is lost on broker restart and is not shared 
across brokers.
+
+# Client configuration
+
+  * 
[`topology.description.push.enabled`](/{version}/configuration/kafka-streams-configs#streamsconfigs_topology.description.push.enabled):
 Controls whether the Kafka Streams client sends topology descriptions to the 
broker when requested. When set to `false`, the client will not prepare or push 
topology descriptions. Enabled by default.
+
+Note that this configuration only controls whether the client *responds* to 
broker solicitations. If the broker has no plugin configured, the client is 
never asked to push, regardless of this setting.
+
+# Implementing a plugin
+
+A plugin implements the 
[`StreamsGroupTopologyDescriptionPlugin`](/{version}/javadoc/org/apache/kafka/coordinator/group/api/streams/StreamsGroupTopologyDescriptionPlugin.html)
 interface from the `group-coordinator-api` module:
+
+```java
+public interface StreamsGroupTopologyDescriptionPlugin extends Configurable, 
AutoCloseable {
+
+    CompletableFuture<Void> setTopology(String groupId, int topologyEpoch, 
StreamsGroupTopologyDescription description);
+
+    CompletableFuture<Void> deleteTopology(String groupId);
+
+    CompletableFuture<StreamsGroupTopologyDescription> getTopology(String 
groupId, int topologyEpoch);
+}
+```
+
+Guidelines for implementations:
+
+  * **Be thread-safe.** `setTopology` may be called concurrently by multiple 
members of the same group.
+  * **Be idempotent.** Calls to `setTopology` with the same `(groupId, 
topologyEpoch)` carry identical data and must be idempotent. `deleteTopology` 
may be called more than once for the same group, including when nothing is 
stored.
+  * **Complete futures asynchronously; never throw synchronously.** Failures 
must be signalled by completing the returned future exceptionally. A 
synchronous throw from `setTopology` is treated as a permanent failure with a 
generic client-visible error message.
+  * **Classify failures.** Complete the `setTopology` future with 
`StreamsTopologyDescriptionPermanentFailureException` when the description will 
never be accepted at this topology epoch, and with 
`StreamsTopologyDescriptionTransientFailureException` (or any other exception) 
for retriable backend failures. The permanent-vs-transient distinction is 
broker-internal; the pushing client always sees 
`STREAMS_TOPOLOGY_DESCRIPTION_UPDATE_FAILED` with the exception's message.
+  * **Key data by group and epoch.** `getTopology(groupId, topologyEpoch)` 
should return the description only if it matches the requested topology epoch, 
and complete with `null` when the plugin no longer has the data (for example, 
after a backend wipe) — the broker then reports status `NOT_STORED`. If the 
future completes exceptionally, the broker reports a read error (status 
`ERROR`) for the group. Note that the broker only solicits a new push when it 
has not recorded a successful push [...]
+  * **Lifecycle.** The plugin is instantiated once per broker, configured via 
`Configurable#configure(Map)` with the broker configuration, and closed via 
`AutoCloseable#close()` on broker shutdown.
+
+# Reading the topology description
+
+## Admin API
+
+Pass `DescribeStreamsGroupsOptions#includeTopologyDescription(true)` to 
`Admin#describeStreamsGroups`:
+
+```java
+try (Admin admin = Admin.create(props)) {
+    DescribeStreamsGroupsResult result = admin.describeStreamsGroups(
+        List.of("my-streams-app"),
+        new DescribeStreamsGroupsOptions().includeTopologyDescription(true));
+    StreamsGroupDescription description = 
result.describedGroups().get("my-streams-app").get();
+    StreamsGroupTopologyDescriptionStatus status = 
description.topologyDescriptionStatus();
+    Optional<StreamsGroupTopologyDescription> topology = 
description.topologyDescription();
+}
+```
+
+The returned `StreamsGroupTopologyDescription` mirrors 
`org.apache.kafka.streams.TopologyDescription` (subtopologies with source, 
processor, and sink nodes, plus global stores) without requiring a dependency 
on the `kafka-streams` library. Requesting a topology description against a 
broker that does not support it (older than 4.4) fails with 
`UnsupportedVersionException`.
+
+## CLI
+
+Use the `--topology` option of `bin/kafka-streams-groups.sh` together with 
`--describe`:
+
+```
+kafka-streams-groups.sh --bootstrap-server localhost:9092 \
+  --describe --group my-streams-app --topology
+```
+
+When a description is available, the output mirrors the format of 
`Topology#describe()`:
+
+```
+Topologies:
+   Sub-topology: 0
+    Source: KSTREAM-SOURCE-0000000000 (topics: [streams-plaintext-input])
+      --> KSTREAM-FLATMAPVALUES-0000000001
+    Processor: KSTREAM-FLATMAPVALUES-0000000001 (stores: [])
+      --> KSTREAM-AGGREGATE-0000000002
+      <-- KSTREAM-SOURCE-0000000000
+    Processor: KSTREAM-AGGREGATE-0000000002 (stores: [counts-store])
+      --> KSTREAM-SINK-0000000003
+      <-- KSTREAM-FLATMAPVALUES-0000000001
+    Sink: KSTREAM-SINK-0000000003 (topic: streams-wordcount-output)
+      <-- KSTREAM-AGGREGATE-0000000002
+```
+
+If no description is available, the tool prints an explanatory message and 
exits with a non-zero exit code. See the [kafka-streams-groups.sh 
documentation](/{version}/streams/developer-guide/kafka-streams-group-sh/) for 
the full CLI reference.
+
+## Interpreting the topology description status
+
+Every describe response that requested a topology description carries a 
`StreamsGroupTopologyDescriptionStatus`. The description itself is present if 
and only if the status is `AVAILABLE`.
+
+  * `NOT_REQUESTED`: The topology description was not requested (the caller 
did not set `includeTopologyDescription(true)`).
+  * `NOT_STORED`: No topology description is recorded for this group — for 
example, because no topology description plugin is configured on the broker, or 
the clients have not pushed a description yet.
+  * `ERROR`: The broker failed to fetch the topology description from the 
plugin. See the broker logs for details.
+  * `AVAILABLE`: The topology description is available and carried in the 
response.
+
+# Group deletion and GROUP_DELETION_FAILED
+
+When a streams group is deleted while a topology description plugin is 
configured, the broker calls the plugin's `deleteTopology` method before 
removing the group. If the plugin fails to delete its data, the `DeleteGroups` 
request returns the error code `GROUP_DELETION_FAILED` for that group, with the 
plugin's exception message in the per-group `ErrorMessage` field (available in 
`DeleteGroups` version 3 and higher), and the broker does **not** delete the 
group. Retrying the deletion re-i [...]
+
+# Observability
+
+The broker exposes metrics for every plugin interaction under the MBean group 
`kafka.server:type=group-coordinator-metrics`; the full list is in the [group 
coordinator monitoring 
reference](/{version}/operations/monitoring#group-coordinator-monitoring). Each 
sensor is published as both a `-rate` (per-second) and a `-count` (cumulative) 
metric, so `streams-group-topology-description-set-success` becomes 
`streams-group-topology-description-set-success-rate` and 
`streams-group-topology-desc [...]
+
+  * `streams-group-topology-description-set-success` / 
`streams-group-topology-description-set-error`: outcomes of `setTopology` 
calls, driven by client pushes.
+  * `streams-group-topology-description-get-success` / 
`streams-group-topology-description-get-error`: outcomes of `getTopology` 
calls, driven by describe requests.
+  * `streams-group-topology-description-delete-success` / 
`streams-group-topology-description-delete-error`: outcomes of `deleteTopology` 
calls, driven by group deletion and cleanup.
+  * `streams-group-topology-description-cleanup-cycle`: number of periodic 
cleanup cycles the coordinator has run.
+  * `streams-group-topology-description-cleanup-eligible`: number of groups 
the cleanup scan found eligible for plugin-state deletion.
+
+Watch the `-error` sensors first: a rising `get-error` rate explains `ERROR` 
describe responses, a rising `set-error` rate explains descriptions that never 
appear, and a rising `delete-error` rate explains `GROUP_DELETION_FAILED`.
+
+# Troubleshooting
+
+Before reading broker logs, check the 
`streams-group-topology-description-*-error` metrics described under 
[Observability](#observability) — they pinpoint which plugin call (`set`, 
`get`, or `delete`) is failing.
+
+**`--topology` reports "No topology description is stored" (status 
`NOT_STORED`).**
+
+  * Verify that `group.streams.topology.description.plugin.class` is set on 
all brokers hosting the group coordinator. Without it, the feature is disabled.
+  * Verify that the application does not set 
`topology.description.push.enabled=false`.
+  * If the group (or its topology epoch) is new, the clients may simply not 
have pushed yet — the broker solicits the push via the heartbeat, so the 
description typically appears within a few heartbeat intervals.
+  * If the description still does not appear, check the broker logs for failed 
`setTopology` calls. After a permanent failure (for example, a description the 
plugin rejects), the broker stops soliciting until the topology epoch advances.
+  * If the description used to appear and has now vanished, the plugin may 
have lost its stored data. When the plugin's `getTopology` returns `null`, the 
broker surfaces the status as `NOT_STORED` (logged at `WARN`) and keeps 
returning `NOT_STORED` on subsequent describes. Because the broker only 
re-solicits a push when the topology epoch advances, restarting the application 
without bumping the topology will not recover the description — advance the 
topology epoch or clear the plugin sta [...]
+
+**Status `ERROR` when describing.**
+
+  * The plugin's `getTopology` call failed on the broker. Check the broker 
logs of the group coordinator for the underlying exception.
+
+**Push delivery issues.**
+
+  * A failed push surfaces to the client as 
`STREAMS_TOPOLOGY_DESCRIPTION_UPDATE_FAILED` and is logged by the Streams 
client; the client does not retry on its own. The broker re-solicits the push 
via the heartbeat — after transient plugin failures with an exponential 
back-off between 30 seconds and 1 hour.
+  * If the pushing member has been fenced or the group was deleted meanwhile, 
the push fails with `UNKNOWN_MEMBER_ID` and the client rejoins the group; this 
is expected and self-healing.
+
+**`DeleteGroups` fails with `GROUP_DELETION_FAILED`.**
+
+  * The plugin failed to delete the stored description. The per-group error 
message contains the plugin's failure reason; the broker logs contain the full 
exception. Resolve the plugin/backend problem and retry the deletion — 
`deleteTopology` is invoked again idempotently.
+
+**`UnsupportedVersionException` when requesting the topology description.**
+
+  * The broker is older than Apache Kafka 4.4 and does not support 
`StreamsGroupDescribe` version 1. Upgrade the broker, or describe the group 
without requesting the topology description.
+
+  * [Documentation](/documentation)
+  * [Kafka Streams](/documentation/streams)
+  * [Developer Guide](/documentation/streams/developer-guide/)
+
diff --git a/docs/streams/upgrade-guide.md b/docs/streams/upgrade-guide.md
index df78b93d72c..c6e737f56c7 100644
--- a/docs/streams/upgrade-guide.md
+++ b/docs/streams/upgrade-guide.md
@@ -71,6 +71,8 @@ Kafka Streams no longer emits a WARN from 
`KafkaStreams#cleanUp()` when the appl
 
 Kafka Streams now validates the `application.server` configuration when 
`StreamsConfig` is created. The value must be empty or a valid endpoint from 
which Kafka Streams can parse both host and port, such as `host:port` or 
`protocol://host:port`. Invalid values that may previously have failed later 
during startup or assignment now fail earlier with a `ConfigException`. More 
details can be found in 
[KIP-1245](https://cwiki.apache.org/confluence/display/KAFKA/KIP-1245%3A+Enforce+%27applicat
 [...]
 
+For applications using the Streams Rebalance Protocol 
(`group.protocol=streams`), brokers can now record a human-readable description 
of the group's processing topology via a pluggable backend 
([KIP-1331](https://cwiki.apache.org/confluence/display/KAFKA/KIP-1331%3A+Streams+Group+Topology+Description+Plugin)).
 When the broker configuration 
`group.streams.topology.description.plugin.class` is set, Kafka Streams clients 
automatically push a description equivalent to `Topology#describe()` t [...]
+
 ## Streams API changes in 4.3.0
 
 **Note:** Kafka Streams 4.3.0 contains a critical native memory leak in the 
RocksDB state store layer 
([KAFKA-20616](https://issues.apache.org/jira/browse/KAFKA-20616)). The 
`ColumnFamilyOptions` for the offsets column family is not closed, and column 
family handles can leak on close-path exceptions, which under cascading task 
closes (e.g., rebalances or error-triggered recoveries) leads to unbounded 
off-heap memory growth and eventual OOM. Users running Kafka Streams should 
consider upg [...]


Reply via email to