package com.xiaomi.infra.galaxy.metrics.client; import com.xiaomi.infra.galaxy.metrics.thrift.ErrorCode; import com.xiaomi.infra.galaxy.metrics.thrift.ErrorsConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Copyright 2015, Xiaomi. * All rights reserved. * Author: linshangquan@xiaomi.com */ public class MetricsAutoRetryClient { private static class AutoRetryHandler<T> implements InvocationHandler { private static final Logger LOG = LoggerFactory.getLogger(AutoRetryHandler.class); private final Object instance; private final boolean isRetry; private final int maxRetry; public AutoRetryHandler(Class<T> interfaceClass, Object instance, boolean isRetry, int maxRetry) { this.instance = instance; this.isRetry = isRetry; this.maxRetry = maxRetry; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { int retry = 0; do { try { return method.invoke(instance, args); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (isRetry && retry < maxRetry) { ErrorCode code = RetryUtils.getErrorCode(cause); Long sleepTime = ErrorsConstants.ERROR_BACKOFF.get(code); if (sleepTime != null) { retry++; LOG.warn("sleep for {} ms in the {} retry", sleepTime, retry); Thread.sleep(sleepTime); } else { throw cause; } } else { throw cause; } } } while (true); } } /** * Create client wrapper which automatically retry the RPC calls for retryable errors until * success or reaches max retry time. */ @SuppressWarnings("unchecked") public static <T> T getAutoRetryClient(Class<T> interfaceClass, Object instance, boolean isRetry, int maxRetry) { return (T) Proxy .newProxyInstance(MetricsAutoRetryClient.class.getClassLoader(), new Class[] { interfaceClass }, new AutoRetryHandler<T>(interfaceClass, instance, isRetry, maxRetry)); } }