написать впереди
В повседневной разработке мы часто сталкиваемся со сценариями, в которых нам нужно вызывать внешние сервисы и интерфейсы. Внешние службы, как правило, ненадежны для вызывающих абонентов, особенно в случае плохой сетевой среды, дрожание сети может легко привести к ненормальным условиям, таким как тайм-аут запроса. . Стратегия повторных попыток также широко используется в управлении службами: она проверяет, является ли служба активной (активной) путем регулярного обнаружения.
Guava Retrying — это гибкие и удобные компоненты повторной попытки, включающие несколько стратегий повторной попытки и очень легко масштабируемые.
Со слов автора:
Это небольшое расширение библиотеки Google Guava, позволяющее создавать настраиваемые стратегии повторных попыток для произвольного вызова функции, например, что-то, что взаимодействует с удаленной службой с непостоянным временем безотказной работы.
Используя Guava-retry, вы можете настроить выполнение повторных попыток, а также вы можете отслеживать результаты и поведение каждой повторной попытки, и, что наиболее важно, метод повторных попыток в стиле Guava действительно удобен.
пример кода
- Представьте Guava-retry
<guava-retry.version>2.0.0</guava-retry.version>
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>${guava-retry.version}</version>
</dependency>
- Определите метод, который реализует интерфейс Callable, чтобы повторитель Guava мог вызывать
/**
* @desc 更新可代理报销人接口
* @author jianzhang11
* @date 2017/3/31 15:17
*/
private static Callable<Boolean> updateReimAgentsCall = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
String url = ConfigureUtil.get(OaConstants.OA_REIM_AGENT);
String result = HttpMethod.post(url, new ArrayList<BasicNameValuePair>());
if(StringUtils.isEmpty(result)){
throw new RemoteException("获取OA可报销代理人接口异常");
}
List<OAReimAgents> oaReimAgents = JSON.parseArray(result, OAReimAgents.class);
if(CollectionUtils.isNotEmpty(oaReimAgents)){
CacheUtil.put(Constants.REIM_AGENT_KEY,oaReimAgents);
return true;
}
return false;
}
};
- Определить объекты Retry и установить соответствующие политики
Retryer<Boolean> retryer = RetryerBuilder
.<Boolean>newBuilder()
//抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
.retryIfException()
//返回false也需要重试
.retryIfResult(Predicates.equalTo(false))
//重调策略
.withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
//尝试次数
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
try {
retryer.call(updateReimAgentsCall);
} catch (ExecutionException e) {
// e.printStackTrace();
} catch (RetryException e) {
logger.error("更新可代理报销人异常,需要发送提醒邮件");
}
В три простых шага вы можете использовать Guava Retryer для элегантной реализации методов перенастройки.
Далее подробно объясняется:
-
RetryerBuilder
Это создатель фабрики, который может настраивать источник повторных попыток и поддерживать несколько источников повторных попыток, настраивать количество повторных попыток или тайм-аут повторных попыток, а также настраивать интервал времени ожидания и создавать экземпляр Retryer для повторной попытки. -
RetryerBuilder
Источник повторных попыток поддерживает объект Exception и пользовательский объект утверждения черезretryIfException
иretryIfResult
Настройка, поддерживает несколько и совместимых одновременно. -
retryIfException
, когда возникает исключение времени выполнения или проверенное исключение, оно будет повторено, но когда возникнет ошибка, оно не будет повторено. -
retryIfRuntimeException
Будет пытаться снова, только когда время выполнения ненормально, Checked не возвращается. -
retryIfExceptionOfType
Позволяет нам повторять попытку только при возникновении определенных исключений, таких какNullPointerException和
IllegalStateException` — это все исключения времени выполнения, включая пользовательские ошибки.
как:
.retryIfExceptionOfType(Error.class)// 只在抛出error重试
Конечно, мы также можем повторить попытку только тогда, когда возникает указанное исключение, например:
.retryIfExceptionOfType(IllegalStateException.class)
.retryIfExceptionOfType(NullPointerException.class)
Или через предикат
.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),
Predicates.instanceOf(IllegalStateException.class)))
retryIfResult может указать, что ваш метод Callable будет повторять попытку при возврате значения, например
// 返回false重试
.retryIfResult(Predicates.equalTo(false))
//以_error结尾才重试
.retryIfResult(Predicates.containsPattern("_error$"))
Когда происходит повторная попытка, если нам нужно выполнить некоторые дополнительные действия по обработке, такие как отправка электронного письма с предупреждением или что-то еще, мы можем использоватьRetryListener
. После каждой повторной попытки guava-retry будет автоматически вызывать зарегистрированный нами слушатель.可以注册多个RetryListener
, который будет вызываться в порядке регистрации.
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import java.util.concurrent.ExecutionException;
public class MyRetryListener<Boolean> implements RetryListener {
@Override
public <Boolean> void onRetry(Attempt<Boolean> attempt) {
// 第几次重试,(注意:第一次重试其实是第一次调用)
System.out.print("[retry]time=" + attempt.getAttemptNumber());
// 距离第一次重试的延迟
System.out.print(",delay=" + attempt.getDelaySinceFirstAttempt());
// 重试结果: 是异常终止, 还是正常返回
System.out.print(",hasException=" + attempt.hasException());
System.out.print(",hasResult=" + attempt.hasResult());
// 是什么原因导致异常
if (attempt.hasException()) {
System.out.print(",causeBy=" + attempt.getExceptionCause().toString());
} else {
// 正常返回时的结果
System.out.print(",result=" + attempt.getResult());
}
// bad practice: 增加了额外的异常处理代码
try {
Boolean result = attempt.get();
System.out.print(",rude get=" + result);
} catch (ExecutionException e) {
System.err.println("this attempt produce exception." + e.getCause().toString());
}
System.out.println();
}
}
Далее указываем прослушиватель в объекте Retry:
.withRetryListener(new MyRetryListener<>())
Использованная литература:
сегмент fault.com/ah/119000000…
Сотни семьи. Baidu.com / есть? ID = 157532 ...
Ооо, ооо на .cn blog .com/почти 5/страх/6...