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

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


	com.google.guava
	guava
	19.0



	com.github.rholder
	guava-retrying
	2.0.0


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

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

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



retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
Retryer retryer = RetryerBuilder.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) {

}
guava-retrying重试工具库: 什么时候重试_第1张图片


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

Retryer retryer = RetryerBuilder.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) {

}
guava-retrying重试工具库: 什么时候重试_第2张图片

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

Retryer retryer = RetryerBuilder.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) {

}
guava-retrying重试工具库: 什么时候重试_第3张图片


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

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

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


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

	}

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

	}
}
guava-retrying重试工具库: 什么时候重试_第4张图片


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

Retryer retryer = RetryerBuilder.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 retryer1 = RetryerBuilder.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) {

}
guava-retrying重试工具库: 什么时候重试_第5张图片

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

// 第一次返回false,第二处返回true
private static Callable booleanTask = new Callable() {
	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 stringTask = new Callable() {
	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 retryer = RetryerBuilder.newBuilder()
			.retryIfResult(Predicates.equalTo(false))
			.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止
			.build();
	try {
		retryer.call(booleanTask);
	} catch (Exception e) {

	}

	System.out.println();

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

	}

}
guava-retrying重试工具库: 什么时候重试_第6张图片


你可能感兴趣的:(分布式系统)