Skip to content

KAFKA-20983: Keep static member id when LeaveGroup is suppressed - #23265

Closed
suzhiking wants to merge 1 commit into
apache:trunkfrom
suzhiking:KAFKA-20983-static-member-fenced-rejoin
Closed

KAFKA-20983: Keep static member id when LeaveGroup is suppressed#23265
suzhiking wants to merge 1 commit into
apache:trunkfrom
suzhiking:KAFKA-20983-static-member-fenced-rejoin

Conversation

@suzhiking

@suzhiking suzhiking commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

A static consumer that calls unsubscribe() suppresses the LeaveGroup RPC in AbstractCoordinator.maybeLeaveGroup(), but resetGenerationOnLeaveGroup() wiped the local member id anyway. The subsequent rejoin therefore carries UNKNOWN_MEMBER_ID while the coordinator still has the member registered under its old id, and the coordinator has to treat such a join as a new process claiming the group.instance.id: it evicts the current member and fences its pending join/sync attempts with FENCED_INSTANCE_ID.

A lone consumer can hit this against itself. If its first blind rejoin is abandoned client-side (for example during a coordinator stall) but was already delivered, the broker still processes it later; whichever of the two joins is processed last fences the other, and the pending attempt of the same consumer receives FencedInstanceIdException, which Kafka Streams treats as fatal (SHUTDOWN_APPLICATION). See KAFKA-20985 for the full failure sequence observed on a long-running Streams application.

The fix keeps the member id whenever no LeaveGroup was actually sent, reusing the existing keep-member-id branch of resetStateAndGeneration(). State and generation are still reset and a rejoin is requested exactly as before; only the id retention changes, and only for the suppressed case. The next rejoin then identifies as the existing member and is handled as a recognized rejoin instead of a static replacement, so no ordering of connections and request queues can make a consumer fence itself. Dynamic members and explicit LEAVE_GROUP close operations keep the previous behavior.

Testing: new regression test testStaticMemberKeepsMemberIdWhenLeaveGroupIsSuppressed (static member, DEFAULT membership operation: no LeaveGroup sent, member id retained, generation reset, rejoin requested); AbstractCoordinatorTest, ConsumerCoordinatorTest and clients checkstyle pass locally.

A static consumer that calls unsubscribe() suppresses the LeaveGroup RPC,
but resetGenerationOnLeaveGroup() wiped the local member id anyway, so the
subsequent rejoin carried UNKNOWN_MEMBER_ID while the coordinator still had
the member registered under its old id. The coordinator has to treat such a
join as a new process claiming the group.instance.id, so it evicts the
current member and fences any of its pending join/sync attempts with
FENCED_INSTANCE_ID. A consumer can hit this against itself: if its first
blind rejoin is abandoned client-side (for example during a coordinator
stall) but still delivered, whichever of the two joins is processed last
fences the other, and the pending attempt of the same consumer receives
FencedInstanceIdException, which Kafka Streams treats as fatal
(SHUTDOWN_APPLICATION).

Keep the member id whenever no LeaveGroup was actually sent, using the
existing keep-member-id branch of resetStateAndGeneration; state and
generation are still reset and a rejoin is requested as before. The next
rejoin then identifies as the existing member and is handled as a recognized
rejoin instead of a static replacement, so no ordering of connections and
request queues can make a lone consumer fence itself. Dynamic members and
explicit LEAVE_GROUP close operations keep the previous behavior.
@github-actions github-actions Bot added triage PRs from the community consumer clients small Small PRs labels Aug 25, 2026
@suzhiking suzhiking closed this Aug 25, 2026
@suzhiking
suzhiking deleted the KAFKA-20983-static-member-fenced-rejoin branch August 25, 2026 08:42
@suzhiking

Copy link
Copy Markdown
Contributor Author

Closed by a head-branch rename after the JIRA was renumbered (duplicates consolidated into KAFKA-20985). Superseded by #23266.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients consumer small Small PRs triage PRs from the community

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant