Visitar URL original
Unregister the MultiDb health status listener when a database is removed by kdelay · Pull Request #4791 · redis/jedis · GitHub
Skip to content

Unregister the MultiDb health status listener when a database is removed - #4791

Merged
ggivo merged 4 commits into
redis:masterfrom
kdelay:fix/multidb-health-listener-unregister
Oct 19, 2026
Merged

ggivo merged 4 commits into
redis:masterfrom
kdelay:fix/multidb-health-listener-unregister

Conversation

@kdelay

@kdelay kdelay commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

MultiDbConnectionProvider.remove unregisters the health listener with a new this::onHealthStatusChange, which never equals the one addDatabaseInternal registered (each method reference is a new object), so the listener stays. Same cause as #4749.

Listeners left for the endpoint in HealthStatusManager.endpointListeners: 1 after remove, 2 after re-adding it, 3 after another remove/add. Each health event then runs onHealthStatusChange once per copy.

The fix keeps one instance for both calls, like ConnectionPool.postAuthenticationHook.

The new test fails on master (expected: <0> but was: <1>) and passes with the fix. mvn test on JDK 17: 3490 tests, 0 failures; the 1 error, TokenBasedAuthenticationUnitTests, also fails on master (500 ms await).


Note

Medium Risk
Touches multi-database failover health callbacks; incorrect unregister could duplicate failover handling, but the change is a small identity fix with targeted test coverage.

Overview
Fixes a listener leak when dynamically removing a database from MultiDbConnectionProvider. remove called unregisterListener with a new this::onHealthStatusChange method reference, which never equals the listener registered in addDatabaseInternal, so the callback stayed attached and could stack on remove/add cycles (same class of bug as #4749).

The provider now keeps one healthStatusListener instance and uses it for both register and unregister. HealthStatusManager exposes a test-only getListeners(Endpoint) snapshot, plus getHealthStatusManager() on the provider. A unit test asserts the endpoint has zero listeners after remove and exactly one after re-add.

Reviewed by Cursor Bugbot for commit ed77c35. Bugbot is set up for automated code reviews on this repo. Configure here.

remove() passed a fresh this::onHealthStatusChange to unregisterListener,
which never matches the instance registered by addDatabaseInternal, so the
listener stayed and accumulated across remove/add cycles. Keep one instance
for both calls, as ConnectionPool does for its post-authentication hook.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T10:28:51.801484Z ed77c35 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4b84fce4d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ggivo ggivo added waiting-for-feedback We need additional information before we can continue status: waiting-for-review and removed waiting-for-feedback We need additional information before we can continue labels Oct 16, 2026
ggivo added 2 commits October 19, 2026 12:12
MultiDbConnectionProviderDynamicEndpointUnitTest already covers add and
remove with the same mocked pool setup, so the case does not need its
own class. Package-private @VisibleForTesting accessors on the provider
and HealthStatusManager replace the reflection on their private fields.
@ggivo

ggivo commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Thanks for the contribution!

Confirmed: this::onHealthStatusChange creates a new instance on each evaluation, so the unregister in remove() never matched. Keeping one instance fixes it and matches #4749.

Pushed 854100a on top of your branch: the test moved into MultiDbConnectionProviderDynamicEndpointUnitTest, which already covers add/remove with the same setup, and package-private @VisibleForTesting accessors (MultiDbConnectionProvider.getHealthStatusManager(), HealthStatusManager.getListeners(Endpoint)) replace the reflection on private fields. The test still fails without the fix.

@ggivo ggivo added this to the 8.1.0 milestone Oct 19, 2026
@ggivo
ggivo merged commit ddee9d5 into redis:master Oct 19, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants