Java開發(fā)利器之重試器
代碼中存在依賴不穩(wěn)定的場景,需要使用重試獲取預(yù)期結(jié)果或者嘗試重新執(zhí)行邏輯不立即結(jié)束,比如遠(yuǎn)程接口訪問,數(shù)據(jù)加載訪問,數(shù)據(jù)上傳校驗(yàn)等 對于異常需要重試的場景,同時(shí)希望把正常邏輯和重試邏輯解耦 對方接口不支持異步回調(diào)
int time = 0;do {????time++;result = testRedo(); // 調(diào)用接口} while (null == result && time < 5);
?調(diào)用方需要不僅需要考慮多次調(diào)用的次數(shù),還要考慮每次調(diào)用的間隔時(shí)間,盡量在最少調(diào)用情況下獲取到最終結(jié)果(多一次請求意味著多一次網(wǎng)絡(luò)開銷,不方便實(shí)時(shí)調(diào)整) 多次調(diào)用過程中偶爾有一次調(diào)用出現(xiàn)異常(接口報(bào)錯,網(wǎng)絡(luò)異常),如果沒有異常處理就會影響剩下次數(shù)的調(diào)用,無法保證高可用 多線程情況下上面的代碼會出現(xiàn)并發(fā)問題,因?yàn)榈谝淮握{(diào)用的結(jié)果不一定是最早返回的,有可能后面調(diào)用的先返回,導(dǎo)致結(jié)果不是預(yù)期的 性能問題,如果使用多線程要考慮線程創(chuàng)建銷毀和切換問題
支持設(shè)置重試次數(shù)和間隔時(shí)間,支持多種復(fù)雜場景的重試策略,延遲策略 而且支持多個(gè)異常或者自定義實(shí)體對象的重試源,讓重試功能有更多的靈活性 線程安全,我們只需要關(guān)注我們的業(yè)務(wù)邏輯實(shí)現(xiàn)即可 內(nèi)部使用線程池管理線程 基于命令模式使用鏈?zhǔn)秸{(diào)用,使用方便
pom依賴:
<dependency>????<groupId>com.github.rholdergroupId>????<artifactId>guava-retryingartifactId><version>2.0.0version>dependency>
// 重試條件Predicate<String> condition = response -> Objects.nonNull(response)&& "處理中".equals(response.getReturnCode());Optional<String> response = RetryUtil.retry(????????????????condition,?//?重試條件() -> invoke(request), // 重試任務(wù)(比如調(diào)用接口)????????????????500,?//?500ms重試一次, 可以做成配置化3); // 一共重試3次, 可以做成配置化return response.orElse(null);
/*** 根據(jù)輸入的condition重復(fù)做task,在規(guī)定的次數(shù)內(nèi)達(dá)到condition則返回,* 如果超過retryTimes則返回null, 重試次數(shù),整個(gè)重試時(shí)間以及retry exception都會記錄log** @param condition 重試條件,比如接口返回errorCode為處理中,或不是最終需要的結(jié)果* @param task 重試做的任務(wù)* @param sleepTime 重試間隔時(shí)間,單位毫秒* @param retryTimes 重試次數(shù)* @return targetBean*/public staticOptional retry(Predicate {condition, Callable task, int sleepTime, int retryTimes) Optionalresult = Optional.empty(); StopWatch stopWatch = new StopWatch();????try?{stopWatch.start();Retryerretry = RetryerBuilder. newBuilder() // 默認(rèn)任務(wù)執(zhí)行過程中發(fā)生異常自動重試.retryIfException()// 重試條件(按照業(yè)務(wù)場景).retryIfResult(condition)// 等待策略.withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.MILLISECONDS))// 重試策略.withStopStrategy(StopStrategies.stopAfterAttempt(retryTimes))// 重試監(jiān)聽器.withRetryListener(new RetryListener() {publicvoid onRetry(Attempt attempt) {// 記錄重試次數(shù)和異常信息log.info(MessageFormat.format("{0}th retry", attempt.getAttemptNumber()));if (attempt.hasException()) {log.error(MessageFormat.format("retry exception:{0}", attempt.getExceptionCause()));}}}).build();// 開始執(zhí)行重試任務(wù)result = Optional.ofNullable(retry.call(task));} catch (Exception e) {log.error("retry fail:", e.getMessage());} finally {stopWatch.stop();log.info("retry execute time", stopWatch.getTime());}return result;}
AttemptTimeLimiter:單次任務(wù)執(zhí)行時(shí)間限制(如果單次任務(wù)執(zhí)行超時(shí),則終止執(zhí)行當(dāng)前任務(wù)) BlockStrategies:任務(wù)阻塞策略,默認(rèn)策略為:BlockStrategies.THREAD_SLEEP_STRATEGY,也就是調(diào)用Thread.sleep () StopStrategy:停止重試策略,提供三種: StopAfterDelayStrategy:設(shè)定一個(gè)最長允許的執(zhí)行時(shí)間,比如設(shè)定最長執(zhí)行10s,無論任務(wù)執(zhí)行次數(shù),只要重試的時(shí)候超出了最長時(shí)間,則任務(wù)終止,并返回重試異常RetryException NeverStopStrategy:不停止,用于需要一直輪詢直到返回期望結(jié)果的情況
WaitStrategy:等待時(shí)長策略(控制時(shí)間間隔),返回結(jié)果為下次執(zhí)行時(shí)長:

評論
圖片
表情
