Skip to content

feat: add SubscriptionUserDataProvider hook for BalanceStrategy#3506

Merged
dnwe merged 3 commits into
IBM:mainfrom
honeycombio:claude/sarama-issue-3505-34O9M
May 12, 2026
Merged

feat: add SubscriptionUserDataProvider hook for BalanceStrategy#3506
dnwe merged 3 commits into
IBM:mainfrom
honeycombio:claude/sarama-issue-3505-34O9M

Conversation

@lizthegrey
Copy link
Copy Markdown
Contributor

Add an optional SubscriptionUserDataProvider interface that a BalanceStrategy may implement. When present, sarama invokes SubscriptionUserData(topics) immediately before each JoinGroup, and the returned bytes replace the statically configured Consumer.Group.Member.UserData for that strategy's subscription metadata only. A nil result or non-nil error falls back to the static UserData (errors are logged, not fatal). This mirrors the Java ConsumerPartitionAssignor.subscriptionUserData hook and enables load-aware assignors that report fresh per-cycle observations (CPU, lag, latency, etc.) to the group leader on every rebalance cycle.

Existing BalanceStrategy implementations are unaffected: the interface is optional and the behavior for strategies that do not implement it is unchanged. The interface is treated as V1; future revisions should be introduced as separate interfaces (e.g., SubscriptionUserDataProviderV2) to preserve backward compatibility.

Includes a unit test of the per-strategy metadata builder and a worked example under examples/consumer_load_aware/ that wraps the built-in sticky strategy with a load-reporting SubscriptionUserDataProvider.

Fixes #3505

Add an optional SubscriptionUserDataProvider interface that a BalanceStrategy
may implement. When present, sarama invokes SubscriptionUserData(topics)
immediately before each JoinGroup, and the returned bytes replace the
statically configured Consumer.Group.Member.UserData for that strategy's
subscription metadata only. A nil result or non-nil error falls back to the
static UserData (errors are logged, not fatal). This mirrors the Java
ConsumerPartitionAssignor.subscriptionUserData hook and enables load-aware
assignors that report fresh per-cycle observations (CPU, lag, latency, etc.)
to the group leader on every rebalance cycle.

Existing BalanceStrategy implementations are unaffected: the interface is
optional and the behavior for strategies that do not implement it is
unchanged. The interface is treated as V1; future revisions should be
introduced as separate interfaces (e.g., SubscriptionUserDataProviderV2) to
preserve backward compatibility.

Includes a unit test of the per-strategy metadata builder and a worked
example under examples/consumer_load_aware/ that wraps the built-in sticky
strategy with a load-reporting SubscriptionUserDataProvider.

Fixes IBM#3505

Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
Comment thread balance_strategy.go Outdated
Comment thread balance_strategy.go Outdated
Comment thread balance_strategy.go
// separate interfaces (e.g., SubscriptionUserDataProviderV2) to preserve
// backward compatibility with existing implementations.
type SubscriptionUserDataProvider interface {
SubscriptionUserData(topics []string) ([]byte, error)
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.

This receiver method is named as a noun. This is usually non-ideal, as the whole idiomatic use of Golang naming is to name the interface as a Doer, that has receiver method Do, or Handler that has receiver method Handle.

The receiver method is a verb, and the interface name is then the agent nominalization of that verb.

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.

Whilst I sort of agree, we do already have the AssignmentData noun in the BalanceStrategy interface, so there is some existing precedent for noun-named methods that return bytes and it does match Java's subscriptionUserData() so I think we're probably best to accept this as-is

Comment thread balance_strategy.go Outdated
Comment thread consumer_group.go Outdated
Comment thread consumer_group.go Outdated
Comment thread consumer_group_test.go Outdated
Comment thread consumer_group_test.go Outdated
Comment thread consumer_group_test.go Outdated
- Rename SubscriptionUserDataProvider to SubscriptionUserDataBalanceStrategy
  and embed BalanceStrategy so implementations must also be a BalanceStrategy.
- Drop the YAGNI paragraph about hypothetical V2.
- Treat nil and empty returned slices identically: a nil error means use
  whatever was returned (including nil/empty) verbatim. Only a non-nil error
  falls back to the static UserData. Update doc comment accordingly.
- Inline the single-line addProtocol helper in joinGroupRequest.
- Restructure subscriptionMetadata around an early return rather than a
  mutable userData local; tighten the fallback log line.
- Use slices.Clone in the test recorder and errors.New for the boom error.
- Add a test case for the empty-slice-clears-static behaviour now that nil
  and empty are handled the same way.

Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
@lizthegrey lizthegrey force-pushed the claude/sarama-issue-3505-34O9M branch from 8bf81de to f7cc882 Compare May 6, 2026 05:13
Copy link
Copy Markdown
Collaborator

@puellanivis puellanivis left a comment

Choose a reason for hiding this comment

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

Code seems to look fine, though I’m unsure of the integration into the larger logic though.

Copy link
Copy Markdown
Collaborator

@dnwe dnwe left a comment

Choose a reason for hiding this comment

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

LGTM, couple of minor comments:

Comment thread consumer_group.go Outdated
Comment thread consumer_group.go
Per dnwe's review on IBM#3506:

- Pass slices.Clone(topics) to the SubscriptionUserData hook so a
  user-provided provider cannot mutate the slice we later attach to the
  JoinGroup request.
- Rewrite the fallback log line to follow the codebase's
  "consumergroup/%s: ..." prefix convention.

Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
lizthegrey added a commit to honeycombio/sarama that referenced this pull request May 11, 2026
Per dnwe's review on IBM#3506:

- Pass slices.Clone(topics) to the SubscriptionUserData hook so a
  user-provided provider cannot mutate the slice we later attach to the
  JoinGroup request.
- Rewrite the fallback log line to follow the codebase's
  "consumergroup/%s: ..." prefix convention.

Signed-off-by: Liz Fong-Jones <lizf@honeycomb.io>
@lizthegrey lizthegrey requested a review from dnwe May 12, 2026 01:50
@dnwe dnwe added the feat label May 12, 2026
Copy link
Copy Markdown
Collaborator

@dnwe dnwe left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for those updates

@dnwe dnwe merged commit 6677d98 into IBM:main May 12, 2026
17 checks passed
@lizthegrey lizthegrey deleted the claude/sarama-issue-3505-34O9M branch May 12, 2026 10:51
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.

Add per-cycle SubscriptionUserData hook for BalanceStrategy

3 participants