Skip to content

fix(consumer): stop roundrobin balancer looping on an unsubscribed topic - #3740

Merged
dnwe merged 2 commits into
IBM:mainfrom
lenamonj:roundrobin-unsubscribed-topic
Sep 20, 2026
Merged

dnwe merged 2 commits into
IBM:mainfrom
lenamonj:roundrobin-unsubscribed-topic

Conversation

@lenamonj

@lenamonj lenamonj commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

roundRobinBalancer.Plan never returns when the topics map holds a topic no member subscribes to: the subscriber search walks members[i%n] forever. The range and sticky strategies leave such a topic unassigned.

The search is now bounded to one pass over the members and a topic with no subscriber is skipped. Whenever a subscriber exists the same member is chosen and the cursor advances by the same amount, so existing plans are unchanged.

Sarama's own consumer group builds the topics map from the members' subscriptions, so this reaches direct callers of Plan.

A row added to TestBalanceStrategyRoundRobin covers it; on main that row hangs until the test timeout.

roundRobinBalancer.Plan searched members[i%n] forever when the topics
map held a topic no member subscribes to. Bound the search to one pass
over the members and leave such a topic unassigned, as the range and
sticky strategies do. When a subscriber exists the same member is chosen
and the cursor advances by the same amount, so existing plans do not
change.

Signed-off-by: Jeff Lenamon <jlenamon@gmail.com>
@lenamonj
lenamonj force-pushed the roundrobin-unsubscribed-topic branch from e02d71f to 0520471 Compare September 13, 2026 18:06
Comment thread balance_strategy.go Outdated
Comment on lines 453 to 459
probe := 0
for probe < n && !members[(i+probe)%n].hasTopic(tp.topic) {
probe++
}
if probe == n {
continue // no member subscribes to this topic
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 We could probably do this by reworking the existing control flow instead:

m := member[i%n]
for range len(members) {
	if m.hasTopic(tp.topic) {
		break
	}
	i++
	m = member[i%n]
}
if !m.hasTopic(tp.topic) {
	continue // no member subscribes to this topic
}

… cursor

Rework the subscriber search as the reviewer suggested: advance the
existing member cursor inside a loop bounded by the member count and
skip the topic when the cursor comes back without a subscriber.

Signed-off-by: Jeff Lenamon <jlenamon@gmail.com>
@lenamonj

Copy link
Copy Markdown
Contributor Author

Reworked to your form in the second commit; the same member is chosen and the cursor advances by the same amount, so the added test row and the existing rows still pass.

@puellanivis puellanivis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is good. 👍

@dnwe dnwe left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Great contribution – lgtm

@dnwe
dnwe merged commit e97cfe8 into IBM:main Sep 20, 2026
20 checks passed
@dnwe dnwe added the fix label Sep 20, 2026
@lenamonj
lenamonj deleted the roundrobin-unsubscribed-topic branch September 21, 2026 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants