guava-retrying重试工具库: 什么时候重试

作为一个重试库,首先要解决的问题就是什么时候重试。为了使用guava-retrying,我们需要在pom.xml中加入依赖:

<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>19.0</version>
</dependency>

<dependency>
	<groupId>com.github.rholder</groupId>
	<artifactId>guava-retrying</artifactId>
	<version>2.0.0</version>
</dependency>


最常用的就是在方法抛出异常的时候重试,比如网络故障导致的IOException。java异常系统分为:runtime异常,checked异常和error,其中ERROR程序处理不了,不需要管;不过作为学习,我们可以测试下error的情况。下面这段代码我们定义了3个任务:分别抛出runtime异常、checked异常、error。
private static Callable<Void> runtimeExceptionTask = new Callable<Void>() {
	@Override
	public Void call() throws Exception {
		System.out.println("runtime was called.");
		throw new NullPointerException("runtime");
	}
};

private static Callable<Void> checkedExceptionTask = new Callable<Void>() {
	@Override
	public Void call() throws Exception {
		System.out.println("checked was called.");
		throw new IOException("checked");
	}
};

private static Callable<Void> errorTask = new Callable<Void>() {
	@Override
	public Void call() throws Exception {
		System.out.println("error was called.");
		throw new ThreadDeath();
	}
};



retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
		.retryIfException() // 抛出异常时重试
		.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
		.build();
try {
	retryer.call(checkedExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(runtimeExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(errorTask);
} catch (Exception e) {

}



retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。

Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
		.retryIfRuntimeException() // 抛出runtime异常时重试
		.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
		.build();
try {
	retryer.call(checkedExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(runtimeExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(errorTask);
} catch (Exception e) {

}


可以看到抛出error是不会进行重试的,当然也没有必要重试。不过通过retryIfExceptionOfType也可以在抛出error的时候进行重试。

Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
		.retryIfExceptionOfType(Error.class)// 只在抛出error重试
		.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
		.build();
try {
	retryer.call(errorTask);
} catch (Exception e) {

}

try {
	retryer.call(runtimeExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(checkedExceptionTask);
} catch (Exception e) {

}



retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常。

private static Callable<Void> nullPointerExceptionTask = new Callable<Void>() {
	@Override
	public Void call() throws Exception {
		System.out.println("nullPointerExceptionTask was called.");
		throw new NullPointerException();
	}
};

private static Callable<Void> illegalStateExceptionTask = new Callable<Void>() {
	@Override
	public Void call() throws Exception {
		System.out.println("illegalStateExceptionTask was called.");
		throw new IllegalStateException();
	}
};


public static void main(String[] args) {
	Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
			.retryIfExceptionOfType(IllegalStateException.class)
			.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
			.build();
	try {
		retryer.call(nullPointerExceptionTask);
	} catch (Exception e) {

	}

	try {
		retryer.call(illegalStateExceptionTask);
	} catch (Exception e) {

	}
}



如果我们希望NullPointerException和IllegalStateException发生的时候都重试,其余异常不重试,怎么办呢?有2种实现方式:添加多个retryIfExceptionOfType,通过Predicate。

Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
		.retryIfExceptionOfType(IllegalStateException.class)
		.retryIfExceptionOfType(NullPointerException.class)
		.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
		.build();
try {
	retryer.call(nullPointerExceptionTask);
} catch (Exception e) {

}

try {
	retryer.call(illegalStateExceptionTask);
} catch (Exception e) {

}

System.out.println("use guava Predicates.");

Retryer<Void> retryer1 = RetryerBuilder.<Void>newBuilder()
		.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),
				Predicates.instanceOf(IllegalStateException.class)))
		.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
		.build();

try {
	retryer1.call(nullPointerExceptionTask);
} catch (Exception e) {

}

try {
	retryer1.call(illegalStateExceptionTask);
} catch (Exception e) {

}


上面我们看到了重试条件都是在发生异常的时候,实际上有时候没有发生异常,但是仍然需要重试的场景也是有的,比如返回false我们希望重试,比如返回字符串符合特定格式我们希望重试,比如返回对象符合某些条件我们希望重试....这个时候我们可以通过retryIfResult实现。通过guava的Predicates,我们可以构建复杂的重试条件。

// 第一次返回false,第二处返回true
private static Callable<Boolean> booleanTask = new Callable<Boolean>() {
	private int count = 0;

	@Override
	public Boolean call() throws Exception {
		System.out.println("booleanTask was called.");
		if (count == 0) {
			count++;
			return false;
		} else {
			return true;
		}
	}
};

private static Callable<CharSequence> stringTask = new Callable<CharSequence>() {
	private int count = 0;

	@Override
	public CharSequence call() throws Exception {
		System.out.println("stringTask was called.");
		if (count == 0) {
			count++;
			return UUID.randomUUID() + "_error";
		} else {
			return UUID.randomUUID() + "_success";
		}
	}
};


public static void main(String[] args) {

	// 返回false重试
	Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
			.retryIfResult(Predicates.equalTo(false))
			.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
			.build();
	try {
		retryer.call(booleanTask);
	} catch (Exception e) {

	}

	System.out.println();

	// 以_error结尾才重试
	Retryer<CharSequence> retryer1 = RetryerBuilder.<CharSequence>newBuilder()
			.retryIfResult(Predicates.containsPattern("_error$"))
			.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
			.build();
	try {
		retryer1.call(stringTask);
	} catch (Exception e) {

	}

}



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值