package org.zstack.core.retry; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.errorcode.SysErrors; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.utils.TypeUtils; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import static org.zstack.core.Platform.i18n; import java.lang.reflect.Method; import java.util.concurrent.TimeUnit; /** * Created by xing5 on 2016/6/25. */ public abstract class Retry<T> { private static final CLogger logger = Utils.getLogger(Retry.class); protected abstract T call(); protected String __name__; public T run() { Method m; try { m = getClass().getDeclaredMethod("call"); } catch (Exception e) { throw new CloudRuntimeException(e); } int times = 5; int interval = 1; Class[] onExceptions = {}; RetryCondition cond = m.getAnnotation(RetryCondition.class); if (cond != null) { times = cond.times(); interval = cond.interval(); onExceptions = cond.onExceptions(); } int count = times; if (__name__ == null) { __name__ = getClass().getName(); } do { try { return call(); } catch (Throwable t) { if (onExceptions.length != 0 && !TypeUtils.isTypeOf(t, onExceptions)) { throw t; } try { TimeUnit.SECONDS.sleep(interval); } catch (InterruptedException e) { logger.warn(e.getMessage(), e); } logger.debug(String.format("running [%s] encounters an exception[%s], will retry %s times with the" + " interval[%s]", __name__, t.getMessage(), count, interval)); count --; if (count == 0) { ErrorCode errorCode = new ErrorCode(); errorCode.setCode(SysErrors.OPERATION_ERROR.toString()); errorCode.setDescription(i18n("an operation[%s] fails after retrying %s times with the interval %s seconds", __name__, times, interval)); errorCode.setDetails(t.getMessage()); logger.warn(errorCode.toString(), t); throw t; } } } while (true); } }