gmr opened a new issue, #4273:
URL: https://github.com/apache/iggy/issues/4273
### Bug description
A consumer group that existed before a `0.9.0-edge.6` → `0.9.0-edge.8`
server upgrade stopped consuming at the moment of the upgrade and never
recovered. A member belonging to a process that terminated during the upgrade
kept ownership of the group's only partition for six days and across a full
server restart. Live members that joined afterwards were listed in the group
with zero partitions and polled indefinitely, receiving no messages and no
client-visible error.
Consumer groups created *after* the upgrade are unaffected, including four
other topics in the same stream drained by the same consumer process.
### Environment
- Server: `0.9.0-edge.8`, single node, TCP, one partition per topic,
upgraded in place from `0.9.0-edge.6`
- Consumer: `iggy-connectors` runtime with the ClickHouse sink plugin, same
build
- Storage: local disk, no purge or retention pressure (topic held 2.5 GB
across 3 segments)
### Timeline
| Time (UTC) | Event |
|---|---|
| 2026-09-17T21:34:32 | StatefulSet rolls `0.9.0-edge.6-0` →
`0.9.0-edge.8-0`. The consumer process is terminated by the rollout. |
| 2026-09-17T21:34:28 | Last message this group ever committed. Its stored
offset freezes at `156292`. |
| 2026-09-17 → 09-23 | Producers keep writing. The topic grows to 2.5 GB,
roughly 120k uncommitted messages. The consumer is restarted several times;
each restart joins the group and consumes nothing. |
| 2026-09-23T14:06 | Full server restart. The stale member and its partition
assignment are still present afterwards. |
| 2026-09-23T14:16 | Group deleted and recreated. Consumption resumes
immediately. |
### Observed state
`consumer-group get`, after three consumer restarts:
```
| Consumer group id | 0 |
| Consumer group name | events |
| Partitions count | 1 |
| Members count | 3 |
| Members | Member id | Partitions count | Partitions |
| | 0 | 1 | 0 |
| | 1 | 0 | |
| | 2 | 0 | |
```
Member `0` belongs to the process terminated on 09-17. Members `1` and `2`
are live consumers. Each consumer restart added a member; none was ever
removed, and the assignment never moved.
With one partition and three members this is a *balanced* assignment, so the
distribution logic is not obviously at fault. The problem is that member `0`
stayed eligible after its client went away.
The server logged the fencing path exactly once, when the previous
consumer's client was still attached:
```
WARN shard-1 server::dispatch::partition: poll_messages fenced; replying
re-sync sentinel
transport_client_id=... error=Consumer group member with client ID: ...
does not own
partition: 0 at the current generation (rebalance in progress).
```
After that the live members polled continuously with no server-side warning
and no client-side error — just empty results. On the client side this is
indistinguishable from an idle topic, which is why it went unnoticed for six
days.
### What is not the cause
- **Storage and offset are healthy.** `message poll --offset 156293 -m 1
<stream> <topic> 0` returns the message.
- **Not the sink or the client process.** The same runtime, same process,
same TCP client concurrently drained four other topics in the same stream plus
six other streams without interruption.
- **Not a server restart artifact.** A full restart did not clear the stale
membership.
### Expected behavior
A member whose client connection is gone should be evicted from the group,
and its partitions reassigned to a live member.
### Actual behavior
The stale member retains the partition. New members join, own nothing, and
poll empty forever with no error surfaced to the client.
### Workaround
Delete and recreate the consumer group:
```
iggy consumer-group delete <stream> <topic> <group>
iggy consumer-group create -g 0 <stream> <topic> <group>
```
Consumption resumed immediately. Two caveats for anyone hitting this:
1. Despite passing `-g 0`, the recreated group was assigned id `1`.
2. The delete removed the stored offset
(`.../partitions/0/offsets/groups/0`), so the consumer restarted from the
oldest retained offset and re-delivered roughly 120k already-processed
messages. That was harmless for us because the sink target is idempotent, but a
non-idempotent consumer would double-process.
### Notes
- The failure began at the same moment as the `edge.6` → `edge.8` upgrade. I
have not bisected or reproduced on a downgrade, so I can't state that the
upgrade *introduced* it as opposed to exposing a pre-existing path; the
correlation is exact to the second.
- I have not determined whether this is specific to the
terminate-during-upgrade sequence or applies to any ungraceful client
disconnect.
Suggested reproduction to separate an upgrade-migration defect from ordinary
stale-member cleanup:
1. On `edge.6`, create a single-partition topic and a consumer group;
consume and commit an offset.
2. Upgrade the server to `edge.8`, terminating the consumer without a
graceful leave.
3. Start a replacement consumer with a different client id.
4. Restart the server.
5. Check whether the old member still owns the partition.
Relevant code paths, from a read of the repo rather than a debugger:
`core/server/src/dispatch/partition.rs` (the fencing log) and
`core/metadata/src/stm/consumer_group.rs` (membership and rebalancing).
Related but distinct: #3334 covers cooperative rebalance *distribution*;
this is about a member that should no longer be eligible at all.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]