All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.phantomthief.failover.util.FailoverUtils Maven / Gradle / Ivy

There is a newer version: 0.1.32
Show newest version
package com.github.phantomthief.failover.util;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.alwaysTrue;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;

import com.github.phantomthief.failover.Failover;
import com.github.phantomthief.failover.exception.NoAvailableResourceException;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableFunction;

/**
 * @author w.vela
 */
public class FailoverUtils {

    private FailoverUtils() {
        throw new UnsupportedOperationException();
    }

    public static  R supplyWithRetry(int maxRetryTimes,
            long sleepBetweenRetryMs, Failover failover, ThrowableFunction func)
            throws X {
        return supplyWithRetry(maxRetryTimes, sleepBetweenRetryMs, failover, func, alwaysTrue());
    }

    /**
     * @param failChecker {@code true} if need retry, {@code false} means no need retry and mark success
     */
    public static  R supplyWithRetry(@Nonnegative int maxRetryTimes,
            long sleepBetweenRetryMs, Failover failover, ThrowableFunction func,
            @Nonnull Predicate failChecker) throws X {
        checkArgument(maxRetryTimes > 0);
        Set failed = new HashSet<>();
        Throwable lastError = null;
        for (int i = 0; i < maxRetryTimes; i++) {
            T oneAvailable = failover.getOneAvailableExclude(failed);
            if (oneAvailable != null) {
                try {
                    R result = func.apply(oneAvailable);
                    failover.success(oneAvailable);
                    return result;
                } catch (Throwable e) {
                    if (failChecker.test(e)) {
                        failover.fail(oneAvailable);
                        failed.add(oneAvailable);
                        if (sleepBetweenRetryMs > 0) {
                            sleepUninterruptibly(sleepBetweenRetryMs, MILLISECONDS);
                        }
                        lastError = e;
                        continue;
                    } else {
                        failover.success(oneAvailable);
                        throw e;
                    }
                }
            } else {
                throw new NoAvailableResourceException();
            }
        }
        //noinspection unchecked
        throw (X) lastError;
    }

    public static  R supply(Failover failover,
            ThrowableFunction func, Predicate failChecker) throws X {
        T oneAvailable = failover.getOneAvailable();
        if (oneAvailable != null) {
            try {
                R result = func.apply(oneAvailable);
                failover.success(oneAvailable);
                return result;
            } catch (Throwable e) {
                if (failChecker == null || failChecker.test(e)) {
                    failover.fail(oneAvailable);
                } else {
                    failover.success(oneAvailable);
                }
                throw e;
            }
        } else {
            throw new NoAvailableResourceException();
        }
    }

    public static  void runWithRetry(int maxRetryTimes,
            long sleepBetweenRetryMs, Failover failover, ThrowableConsumer func) throws X {
        supplyWithRetry(maxRetryTimes, sleepBetweenRetryMs, failover, t -> {
            func.accept(t);
            return null;
        }, alwaysTrue());
    }

    /**
     * @param failChecker {@code true} if need retry, {@code false} means no need retry and mark success
     */
    public static  void runWithRetry(int maxRetryTimes,
            long sleepBetweenRetryMs, Failover failover, ThrowableConsumer func,
            @Nonnull Predicate failChecker) throws X {
        supplyWithRetry(maxRetryTimes, sleepBetweenRetryMs, failover, t -> {
            func.accept(t);
            return null;
        }, failChecker);
    }

    public static  void run(Failover failover,
            ThrowableConsumer func, Predicate failChecker) throws X {
        supply(failover, t -> {
            func.accept(t);
            return null;
        }, failChecker);
    }

    public static boolean isHostUnavailable(Throwable t) {
        Throwable rootCause = getRootCause(t);
        if (rootCause instanceof NoRouteToHostException) {
            return true;
        }
        if (rootCause instanceof UnknownHostException) {
            return false;
        }
        if (rootCause instanceof MalformedURLException) {
            return false;
        }
        if (rootCause instanceof ConnectException) {
            if (rootCause.getMessage() != null
                    && rootCause.getMessage().toLowerCase().contains("connection refused")) {
                return true;
            }
        }
        if (rootCause instanceof SocketTimeoutException) {
            if (rootCause.getMessage() != null
                    && rootCause.getMessage().toLowerCase().contains("connect timed out")) {
                return true;
            }
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy