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

com.aliyun.dts.subscribe.clients.common.RetryUtil Maven / Gradle / Ivy

package com.aliyun.dts.subscribe.clients.common;

import com.aliyun.dts.subscribe.clients.exception.CriticalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

public class RetryUtil {
    private static final Logger LOG = LoggerFactory.getLogger(RetryUtil.class);
    private final String globalJobType;
    private final String objectNameShouldBeRetried;
    private Function recoverableChecker;
    private int maxRetryTimes;
    private int freezeInterval;
    private TimeUnit freezeTimeUnit;

    public RetryUtil(String globalJobType, String objectNameShouldBeRetried,
                     int freezeInterval, TimeUnit freezeTimeUnit, int maxRetryTimes,
                     Function recoverableChecker) {
        this.globalJobType = globalJobType;
        this.objectNameShouldBeRetried = objectNameShouldBeRetried;
        this.maxRetryTimes = maxRetryTimes;
        this.freezeInterval = freezeInterval;
        this.freezeTimeUnit = freezeTimeUnit;
        this.recoverableChecker = recoverableChecker;
    }

    public RetryUtil(Function recoverableChecker) {
        this(5, TimeUnit.SECONDS, 1, recoverableChecker);
    }

    public RetryUtil(int freezeInterval, TimeUnit freezeTimeUnit, int maxRetryTimes,
                     Function recoverableChecker) {
        this("unknown", "unknown", freezeInterval, freezeTimeUnit, maxRetryTimes, recoverableChecker);
    }

    public void callFunctionWithRetry(ThrowableFunctionVoid throwableFunction) throws Exception {
        callFunctionWithRetry(throwableFunction, null, null);
    }

    public void callFunctionWithRetry(ThrowableFunctionVoid throwableFunction,
                                      BiFunction recoverableChecker,
                                      Consumer retryInfoConsumer) throws Exception {
        callFunctionWithRetry(
                () -> {
                    throwableFunction.call();
                    return null;
                },
                recoverableChecker, retryInfoConsumer);
    }

    public  T callFunctionWithRetry(ThrowableFunction throwableFunction) throws Exception {
        return callFunctionWithRetry(maxRetryTimes, freezeInterval, freezeTimeUnit, throwableFunction);
    }

    public  T callFunctionWithRetry(int maxRetryTimes, int freezeInternal, TimeUnit freezeTimeUnit,
                                       ThrowableFunction throwableFunction) throws Exception {
        return this.callFunctionWithRetry(maxRetryTimes, freezeInternal, freezeTimeUnit, throwableFunction,
                (e, times) -> recoverableChecker.apply(e), null);
    }

    public  T callFunctionWithRetry(ThrowableFunction throwableFunction,
                                       BiFunction recoverableChecker,
                                       Consumer retryInfoConsumer) throws Exception {
        return callFunctionWithRetry(maxRetryTimes, freezeInterval, freezeTimeUnit, throwableFunction, recoverableChecker, retryInfoConsumer);
    }

    public  T callFunctionWithRetry(int maxRetryTimes, int freezeInternal, TimeUnit freezeTimeUnit,
                                       ThrowableFunction throwableFunction,
                                       BiFunction recoverableChecker,
                                       Consumer retryInfoConsumer) throws Exception {
        Throwable error = null;
        RetryInfo retryInfo = null;
        maxRetryTimes = Math.max(1, maxRetryTimes);

        for (int i = 0; i < maxRetryTimes; i++) {
            try {
                T rs = throwableFunction.call();
                if (null != retryInfo) {
                    retryInfo.endRetry();
                }
                return rs;
            } catch (Throwable e) {
                error = e;
                if (recoverableChecker.apply(e, i)) {
                    if (null == retryInfo) {
                        retryInfo = new RetryInfo(globalJobType, objectNameShouldBeRetried);
                    }
                    retryInfo.retry(e);

                    LOG.warn("call function {} with {} times failed, try to execute it again",
                            throwableFunction.toString(), retryInfo.getRetryCount(), e);
                    freezeTimeUnit.sleep(freezeInternal);

                    if (null != retryInfoConsumer) {
                        retryInfoConsumer.accept(retryInfo);
                    }
                } else {
                    break;
                }
            }
        }

        if (error instanceof Exception) {
            throw (Exception) error;
        } else {
            throw new CriticalException("common", error);
        }
    }

    public interface ThrowableFunctionVoid {
        void call() throws Exception;
    }

    public interface ThrowableFunction {
        T call() throws Exception;
    }

    public static class RetryInfo {
        private final String retryModule;
        private final String retryTarget;
        private String errMsg;

        private long retryCount;
        private long beginTimestamp;
        private long endTimestamp;

        public RetryInfo(String retryModule, String retryTarget) {
            this.retryModule = retryModule;
            this.retryTarget = retryTarget;
            this.retryCount = 0;
            this.errMsg = "null";
            this.beginTimestamp = 0;
            this.endTimestamp = 0;
        }

        public boolean isRetrying() {
            return 0 != beginTimestamp && 0 == endTimestamp;
        }

        public long getBeginTimestamp() {
            return beginTimestamp;
        }

        void beginRetry() {
            this.beginTimestamp = Time.now();
        }

        void endRetry() {
            this.endTimestamp = Time.now();
        }

        public long getRetryCount() {
            return retryCount;
        }

        public void retry(Throwable e) {
            if (0 == beginTimestamp) {
                beginRetry();
            }
            if (null != e) {
                errMsg = e.toString();
            }
            retryCount++;
        }

        public String getRetryModule() {
            return retryModule;
        }

        public String getErrMsg() {
            return errMsg;
        }

        void setErrMsg(String errMsg) {
            this.errMsg = errMsg;
        }

        public String getRetryTarget() {
            return retryTarget;
        }

        public long getRetryTime(TimeUnit unit) {
            long end = (0 == endTimestamp) ? Time.now() : endTimestamp;
            return TimeUnit.MILLISECONDS.convert(end - beginTimestamp, unit);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy