-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[automatic failover] Implement wait on healthCheck results during client init #4207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
atakavci
merged 24 commits into
redis:feature/automatic-failover
from
atakavci:ali/aa-failover-healthCheckOnInit
Aug 13, 2025
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
8a9f876
- weighted cluster seleciton
atakavci d514ecf
- add builder for ClusterConfig
atakavci df66b1e
- fix naming
atakavci 13757f5
clean up and mark override methods
atakavci ef5d83a
fix link in javadoc
atakavci a15fc64
fix formatting
atakavci cf38240
- fix double registered listeners in healtstatusmgr
atakavci c2fb34c
Update src/main/java/redis/clients/jedis/mcf/EchoStrategy.java
atakavci ade866d
- add remove endpoints
atakavci ca3378d
- replace cluster disabled with failbackCandidate
atakavci ddcec73
- remove failback candidate
atakavci c1b6d5f
- fix remove logic
atakavci ff16330
- periodic failback checks
atakavci c39fda1
- introduce StatusTracker with purpose of waiting initial healthcheck…
atakavci 975ab78
- introduce forceActiveCluster by duration
atakavci 405101e
- fix failing tests by waiting on clusters to get healthy
atakavci 607c66d
- fix failing scenario test
atakavci aaac8f7
- adressing reviews and feedback
atakavci 2ffffef
- fix formatting
atakavci e6e1121
- fix formatting
atakavci b8d4e87
- get rid of the queue and event ordering for healthstatus change in …
atakavci 1ae7219
- replace use of reflection with helper methods
atakavci a751a84
Merge branch 'feature/automatic-failover' into ali/aa-failover-health…
atakavci 004a022
- replace 'sleep' with 'await', feedback from @a-TODO-rov
atakavci File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package redis.clients.jedis.mcf; | ||
|
||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
import redis.clients.jedis.exceptions.JedisConnectionException; | ||
import redis.clients.jedis.exceptions.JedisValidationException; | ||
|
||
/** | ||
* StatusTracker is responsible for tracking and waiting for health status changes for specific endpoints. It provides | ||
* an event-driven approach to wait for health status transitions from UNKNOWN to either HEALTHY or UNHEALTHY. | ||
*/ | ||
public class StatusTracker { | ||
|
||
private final HealthStatusManager healthStatusManager; | ||
|
||
public StatusTracker(HealthStatusManager healthStatusManager) { | ||
this.healthStatusManager = healthStatusManager; | ||
} | ||
|
||
/** | ||
* Waits for a specific endpoint's health status to be determined (not UNKNOWN). Uses event-driven approach with | ||
* CountDownLatch to avoid polling. | ||
* @param endpoint the endpoint to wait for | ||
* @return the determined health status (HEALTHY or UNHEALTHY) | ||
* @throws JedisConnectionException if interrupted while waiting | ||
*/ | ||
public HealthStatus waitForHealthStatus(Endpoint endpoint) { | ||
// First check if status is already determined | ||
HealthStatus currentStatus = healthStatusManager.getHealthStatus(endpoint); | ||
if (currentStatus != HealthStatus.UNKNOWN) { | ||
return currentStatus; | ||
} | ||
|
||
// Set up event-driven waiting | ||
final CountDownLatch latch = new CountDownLatch(1); | ||
final AtomicReference<HealthStatus> resultStatus = new AtomicReference<>(); | ||
|
||
// Create a temporary listener for this specific endpoint | ||
HealthStatusListener tempListener = new HealthStatusListener() { | ||
@Override | ||
public void onStatusChange(HealthStatusChangeEvent event) { | ||
if (event.getEndpoint().equals(endpoint) && event.getNewStatus() != HealthStatus.UNKNOWN) { | ||
resultStatus.set(event.getNewStatus()); | ||
latch.countDown(); | ||
} | ||
} | ||
}; | ||
|
||
// Register the temporary listener | ||
healthStatusManager.registerListener(endpoint, tempListener); | ||
|
||
try { | ||
// Double-check status after registering listener (race condition protection) | ||
currentStatus = healthStatusManager.getHealthStatus(endpoint); | ||
if (currentStatus != HealthStatus.UNKNOWN) { | ||
return currentStatus; | ||
} | ||
|
||
// Wait for the health status change event | ||
// just for safety to not block indefinitely | ||
boolean completed = latch.await(60, TimeUnit.SECONDS); | ||
atakavci marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!completed) { | ||
throw new JedisValidationException("Timeout while waiting for health check result"); | ||
} | ||
return resultStatus.get(); | ||
|
||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
throw new JedisConnectionException("Interrupted while waiting for health check result", e); | ||
} finally { | ||
// Clean up: unregister the temporary listener | ||
healthStatusManager.unregisterListener(endpoint, tempListener); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.