Skip to content

Commit 84fc90d

Browse files
committed
Added migration guide for KIP-848
1 parent adc1b81 commit 84fc90d

File tree

4 files changed

+449
-6
lines changed

4 files changed

+449
-6
lines changed

CHANGELOG.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,52 @@
11
# Confluent Python Client for Apache Kafka - CHANGELOG
22

3-
## Unreleased
4-
53
## v2.12.0b1 - 2025-10-01
64

7-
### Added
5+
- **General Availability for Next Generation Consumer Group Protocol (KIP-848)**:
6+
Starting with __confluent-kafka-python 2.12.0__, the next generation consumer group rebalance protocol defined in **[KIP-848](https://cwiki.apache.org/confluence/display/KAFKA/KIP-848%3A+The+Next+Generation+of+the+Consumer+Rebalance+Protocol)** is **production-ready** (GA release). Please refer the following [migration guide](docs/kip-848-migration-guide.md) for moving from `classic` to `consumer` protocol.
7+
- **AsyncIO Producer (experimental):** Introduces beta class `AIOProducer` for
8+
asynchronous message production in asyncio applications.
9+
10+
<details>
11+
<summary> AsyncIO Producer (experimental) </summary>
12+
13+
#### Added
814

915
- AsyncIO Producer (experimental): Introduces `confluent_kafka.aio.AIOProducer` for
1016
asynchronous message production in asyncio applications. This API offloads
1117
blocking librdkafka calls to a thread pool and schedules common callbacks
1218
(`error_cb`, `throttle_cb`, `stats_cb`, `oauth_cb`, `logger`) onto the event
1319
loop for safe usage inside async frameworks.
1420

15-
### Features
21+
#### Features
1622

1723
- Batched async produce: `await aio.AIOProducer(...).produce(topic, value=...)`
1824
buffers messages and flushes when the buffer threshold or timeout is reached.
1925
- Async lifecycle: `await producer.flush()`, `await producer.purge()`, and
2026
transactional operations (`init_transactions`, `begin_transaction`,
2127
`commit_transaction`, `abort_transaction`).
2228

23-
### Limitations
29+
#### Limitations
2430

2531
- Per-message headers are not supported in the current batched async produce
2632
path. If headers are required, use the synchronous `Producer.produce(...)` or
2733
offload a sync produce call to a thread executor within your async app.
2834

29-
### Guidance
35+
#### Guidance
3036

3137
- Use the AsyncIO Producer inside async apps/servers (FastAPI/Starlette, aiohttp,
3238
asyncio tasks) to avoid blocking the event loop.
3339
- For batch jobs, scripts, or highest-throughput pipelines without an event
3440
loop, the synchronous `Producer` remains recommended.
3541

42+
</details>
43+
<br />
44+
45+
confluent-kafka-python v2.12.0 is based on librdkafka v2.12.0, see the
46+
[librdkafka release notes](https://github.com/confluentinc/librdkafka/releases/tag/v2.12.0)
47+
for a complete list of changes, enhancements, fixes and upgrade considerations.
48+
49+
3650
## v2.11.1 - 2025-08-18
3751

3852
v2.11.1 is a maintenance release with the following fixes:

docs/index.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ A reliable, performant and feature-rich Python client for Apache Kafka v0.8 and
66
Guides
77
- :ref:`Configuration Guide <pythonclient_configuration>`
88
- :ref:`Transactional API <pythonclient_transactional>`
9+
- :ref:`KIP-848 Migration Guide <pythonclient_migration_kip848>`
910

1011
Client API
1112
- :ref:`Producer <pythonclient_producer>`
@@ -1090,3 +1091,11 @@ addition to the properties dictated by the underlying librdkafka C library:
10901091

10911092
For the full range of configuration properties, please consult librdkafka's documentation:
10921093
https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md
1094+
1095+
1096+
.. _pythonclient_migration_kip848:
1097+
1098+
KIP-848 - Migration Guide
1099+
=========================
1100+
1101+
.. include:: kip-848-migration-guide.rst

docs/kip-848-migration-guide.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
### KIP-848 - Migration Guide
2+
3+
#### Overview
4+
5+
- **What changed:**
6+
7+
The **Group Leader role** (consumer member) is removed. Assignments are calculated by the **Group Coordinator (broker)** and distributed via **heartbeats**.
8+
9+
- **Requirements:**
10+
11+
- Broker version **4.0.0+**
12+
- confluent-kafka-python version **2.12.0+**: GA (production-ready)
13+
14+
- **Enablement (client-side):**
15+
16+
- `group.protocol=consumer`
17+
- `group.remote.assignor=<assignor>` (optional; broker-controlled if `NULL`; default broker assignor is `uniform`)
18+
19+
#### Available Features
20+
21+
All KIP-848 features are supported including:
22+
23+
- Subscription to one or more topics, including **regular expression (regex) subscriptions**
24+
- Rebalance callbacks (**incremental only**)
25+
- Static group membership
26+
- Configurable remote assignor
27+
- Enforced max poll interval
28+
- Upgrade from `classic` protocol or downgrade from `consumer` protocol
29+
- AdminClient changes as per KIP
30+
31+
#### Contract Changes
32+
33+
##### Client Configuration changes
34+
35+
| Classic Protocol (Deprecated Configs in KIP-848) | KIP-848 / Next-Gen Replacement |
36+
|--------------------------------------------------|-------------------------------------------------------|
37+
| `partition.assignment.strategy` | `group.remote.assignor` |
38+
| `session.timeout.ms` | Broker config: `group.consumer.session.timeout.ms` |
39+
| `heartbeat.interval.ms` | Broker config: `group.consumer.heartbeat.interval.ms` |
40+
| `group.protocol.type` | Not used in the new protocol |
41+
42+
**Note:** The properties listed under “Classic Protocol (Deprecated Configs in KIP-848)” are **no longer used** when using the KIP-848 consumer protocol.
43+
44+
##### Rebalance Callback Changes
45+
46+
- The **protocol is fully incremental** in KIP-848.
47+
- In the **rebalance callbacks**, you **must use**:
48+
- `consumer.incremental_assign(partitions)` to assign new partitions
49+
- `consumer.incremental_unassign(partitions)` to revoke partitions
50+
- **Do not** use `consumer.assign()` or `consumer.unassign()` when using `group.protocol='consumer'` (KIP-848).
51+
- ⚠️ The `partitions` list passed to `incremental_assign()` and `incremental_unassign()` contains only the **incremental changes** — partitions being **added** or **revoked****not the full assignment**, as was the case with `assign()` in the classic protocol.
52+
- All assignors under KIP-848 are now **sticky**, including `range`, which was **not sticky** in the classic protocol.
53+
54+
##### Static Group Membership
55+
56+
- Duplicate `group.instance.id` handling:
57+
- **Newly joining member** is fenced with **UNRELEASED_INSTANCE_ID (fatal)**.
58+
- (Classic protocol fenced the **existing** member instead.)
59+
- Implications:
60+
- Ensure only **one active instance per** `group.instance.id`.
61+
- Consumers must shut down cleanly to avoid blocking replacements until session timeout expires.
62+
63+
##### Session Timeout & Fetching
64+
65+
- **Session timeout is broker-controlled**:
66+
- If the Coordinator is unreachable, a consumer **continues fetching messages** but cannot commit offsets.
67+
- Consumer is fenced once a heartbeat response is received from the Coordinator.
68+
- In the classic protocol, the client stopped fetching when session timeout expired.
69+
70+
##### Closing / Auto-Commit
71+
72+
- On `close()` or unsubscribe with auto-commit enabled:
73+
- Member retries committing offsets until a timeout expires.
74+
- Currently uses the **default remote session timeout**.
75+
- Future **KIP-1092** will allow custom commit timeouts.
76+
77+
##### Error Handling Changes
78+
79+
- `UNKNOWN_TOPIC_OR_PART` (**subscription case**):
80+
- No longer returned if a topic is missing in the **local cache** when subscribing; the subscription proceeds.
81+
- `TOPIC_AUTHORIZATION_FAILED`:
82+
- Reported once per heartbeat or subscription change, even if only one topic is unauthorized.
83+
84+
##### Summary of Key Differences (Classic vs Next-Gen)
85+
86+
- **Assignment:** Classic protocol calculated by **Group Leader (consumer)**; KIP-848 calculated by **Group Coordinator (broker)**
87+
- **Assignors:** Classic range assignor was **not sticky**; KIP-848 assignors are **sticky**, including range
88+
- **Deprecated configs:** Classic client configs are replaced by `group.remote.assignor` and broker-controlled session/heartbeat configs
89+
- **Static membership fencing:** KIP-848 fences **new member** on duplicate `group.instance.id`
90+
- **Session timeout:** Classic enforced on client; KIP-848 enforced on broker
91+
- **Auto-commit on close:** Classic stops at client session timeout; KIP-848 retries until remote timeout
92+
- **Unknown topics:** KIP-848 does not return error on subscription if topic missing
93+
- **Upgrade/Downgrade:** KIP-848 supports upgrade/downgrade from/to `classic` and `consumer` protocols
94+
95+
#### Minimal Example Config
96+
97+
##### Classic Protocol
98+
99+
``` properties
100+
# Optional; default is 'classic'
101+
group.protocol=classic
102+
103+
partition.assignment.strategy=<range,roundrobin,sticky>
104+
session.timeout.ms=45000
105+
heartbeat.interval.ms=15000
106+
```
107+
108+
##### Next-Gen Protocol / KIP-848
109+
110+
``` properties
111+
group.protocol=consumer
112+
113+
# Optional: select a remote assignor
114+
# Valid options currently: 'uniform' or 'range'
115+
# group.remote.assignor=<uniform,range>
116+
# If unset(NULL), broker chooses the assignor (default: 'uniform')
117+
118+
# Session & heartbeat now controlled by broker:
119+
# group.consumer.session.timeout.ms
120+
# group.consumer.heartbeat.interval.ms
121+
```
122+
123+
#### Rebalance Callback Migration
124+
125+
##### Range Assignor (Classic)
126+
127+
``` python
128+
# Rebalance Callback for Range Assignor (Classic Protocol)
129+
def on_assign(consumer, partitions):
130+
# Full partition list is provided under the classic protocol
131+
print(f"[Classic] Assigned partitions: {partitions}")
132+
consumer.assign(partitions)
133+
134+
def on_revoke(consumer, partitions):
135+
print(f"[Classic] Revoked partitions: {partitions}")
136+
consumer.unassign()
137+
```
138+
139+
##### Incremental Assignor (Including Range in Consumer / KIP-848, Any Protocol)
140+
141+
``` python
142+
# Rebalance callback for incremental assignor
143+
def on_assign(consumer, partitions):
144+
# Only incremental partitions are passed here (not full list)
145+
print(f"[KIP-848] Incrementally assigning: {partitions}")
146+
consumer.incremental_assign(partitions)
147+
148+
def on_revoke(consumer, partitions):
149+
print(f"[KIP-848] Incrementally revoking: {partitions}")
150+
consumer.incremental_unassign(partitions)
151+
```
152+
153+
**Note:** The `partitions` list contains **only partitions being added or revoked**, not the full partition list as in the classic `consumer.assign()`.
154+
155+
#### Upgrade and Downgrade
156+
157+
- A group made up entirely of `classic` consumers runs under the classic protocol.
158+
- The group is **upgraded to the consumer protocol** as soon as at least one `consumer` protocol member joins.
159+
- The group is **downgraded back to the classic protocol** if the last `consumer` protocol member leaves while `classic` members remain.
160+
- Both **rolling upgrade** (classic → consumer) and **rolling downgrade** (consumer → classic) are supported.
161+
162+
#### Migration Checklist (Next-Gen Protocol / KIP-848)
163+
164+
1. Upgrade to **confluent-kafka-python ≥ 2.12.0** (GA release)
165+
2. Run against **Kafka brokers ≥ 4.0.0**
166+
3. Set `group.protocol=consumer`
167+
4. Optionally set `group.remote.assignor`; leave `NULL` for broker-controlled (default: `uniform`), valid options: `uniform` or `range`
168+
5. Replace deprecated configs with new ones
169+
6. Update rebalance callbacks to **incremental APIs only**
170+
7. Review static membership handling (`group.instance.id`)
171+
8. Ensure proper shutdown to avoid fencing issues
172+
9. Adjust error handling for unknown topics and authorization failures

0 commit comments

Comments
 (0)