工具类, java8的方法参数是可以传函数
@Component
@Slf4j
public class RetryHandler {
@Autowired
private RetryProperties retryProperties;
public <T> T retry(Supplier<T> supplier){
return retry(supplier,
retryProperties.getRetryCount(),
retryProperties.getRetryWhenTimeOut());
}
public <T> T retry(Supplier<T> supplier, int retryCount, int timeBetweenCallInSeconds) {
int tryCount = retryCount + 1;
for (int i = 0; i < tryCount; i++) {
try {
T t = supplier.get();
log.info("The [{}] time call success", i);
return t;
} catch (TryExecption e) {
log.warn("The [{}] time try failed and will sleep [{}] seconds, because [{}]", i, timeBetweenCallInSeconds, e.getMessage());
ThreadUtil.sleep(timeBetweenCallInSeconds);
} catch (Exception e){
log.error("Call catch exception [{}], no retry again", e.getMessage());
return null;
}
}
log.error("TryCount [{}] times fail. Stop retry", tryCount);
return null;
}
@Configuration
@ConfigurationProperties(prefix = "retry")
@Getter
@Setter
class RetryProperties{
private int retryCount;
private int retryWhenTimeOut;
}
}
server:
port: 9999
retry:
retryCount: 3
retryWhenTimeOut: 5
线程工具类, 线程被打断不做处理
@UtilityClass
@Slf4j
public class ThreadUtil {
public void sleep(int i){
try {
TimeUnit.SECONDS.sleep(i);
} catch (InterruptedException e) {
log.error("Sleep thread interrupted, [{}]", e.getMessage());
Thread.currentThread().interrupt();
}
}
}
单元测试
@SpringBootTest
public class RetryHandlerTest {
@Autowired
private RetryHandler retryHandler;
@Test
public void testRetryFail(){
AtomicInteger i = new AtomicInteger(0);
Supplier<Integer> supplier = () -> {
int andIncrement = i.getAndIncrement();
if (andIncrement < 3) {
throw new TryExecption("DB not find", 408);
}
return andIncrement;
};
Integer retry = retryHandler.retry(supplier, 2, 1);
Assertions.assertNull(retry);
Assertions.assertEquals(3, i.get());
}
@Test
public void testRetrySuccess(){
AtomicInteger i = new AtomicInteger(0);
Supplier<Integer> supplier = () -> {
int andIncrement = i.getAndIncrement();
if (andIncrement < 2) {
throw new TryExecption("DB not find", 408);
}
return andIncrement;
};
Integer retry = retryHandler.retry(supplier, 2, 1);
Assertions.assertEquals(2, retry);
}
@Test
public void testRetryWhenCatchOtherException(){
AtomicInteger i = new AtomicInteger(0);
Supplier<Integer> supplier = () -> {
int andIncrement = i.getAndIncrement();
if (andIncrement < 2) {
throw new RuntimeException("Service error");
}
return andIncrement;
};
Thread currentThread = Thread.currentThread();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentThread.interrupt();
}).start();
Integer retry = retryHandler.retry(supplier, 3, 2);
Assertions.assertNull(retry);
Assertions.assertEquals(1, i.get());
}
}