redis.clients.jedis.mcf.CircuitBreakerFailoverBase Maven / Gradle / Ivy
Show all versions of jedis_preview Show documentation
package redis.clients.jedis.mcf;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider;
import redis.clients.jedis.util.IOUtils;
/**
* @author Allen Terleto (aterleto)
*
* Base class for CommandExecutor with built-in retry, circuit-breaker, and failover to another cluster/database
* endpoint. With this executor users can seamlessly failover to Disaster Recovery (DR), Backup, and Active-Active
* cluster(s) by using simple configuration which is passed through from
* Resilience4j - https://resilience4j.readme.io/docs
*
*/
public class CircuitBreakerFailoverBase implements AutoCloseable {
protected final MultiClusterPooledConnectionProvider provider;
public CircuitBreakerFailoverBase(MultiClusterPooledConnectionProvider provider) {
this.provider = provider;
}
@Override
public void close() {
IOUtils.closeQuietly(this.provider);
}
/**
* Functional interface wrapped in retry and circuit breaker logic to handle open circuit breaker failure scenarios
*/
protected synchronized void clusterFailover(CircuitBreaker circuitBreaker) {
// Check state to handle race conditions since incrementActiveMultiClusterIndex() is non-idempotent
if (!CircuitBreaker.State.FORCED_OPEN.equals(circuitBreaker.getState())) {
// Transitions state machine to a FORCED_OPEN state, stopping state transition, metrics and event publishing.
// To recover/transition from this forced state the user will need to manually failback
circuitBreaker.transitionToForcedOpenState();
// Incrementing the activeMultiClusterIndex will allow subsequent calls to the executeCommand()
// to use the next cluster's connection pool - according to the configuration's prioritization/order
int activeMultiClusterIndex = provider.incrementActiveMultiClusterIndex();
// Implementation is optionally provided during configuration. Typically, used for activeMultiClusterIndex persistence or custom logging
provider.runClusterFailoverPostProcessor(activeMultiClusterIndex);
}
// Once the priority list is exhausted only a manual failback can open the circuit breaker so all subsequent operations will fail
else if (provider.isLastClusterCircuitBreakerForcedOpen()) {
throw new JedisConnectionException("Cluster/database endpoint could not failover since the MultiClusterClientConfig was not " +
"provided with an additional cluster/database endpoint according to its prioritized sequence. " +
"If applicable, consider failing back OR restarting with an available cluster/database endpoint");
}
}
}