项目反应器:如何用不同的参数重试单声道直到满足某些条件
Project reactor: How to retry mono with different argument until some condition is met
我需要使用项目反应器异步生成唯一代码。
方法签名如下所示:
public Mono<String> generateCode()
所以流程应该是这样的:
- 生成随机码
- 检查数据库中是否存在此代码
- 如果存在,重新生成代码(第1步)并再次检查(第2步)
- 如果代码是唯一的,return它
我目前的解决方案是像这样递归调用 generateCode:
Mono<String> generateCode() {
String code = generateCodeValue();
return emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt.map(c -> generateCode()).orElseGet(() -> Mono.just(code)));
}
但我不喜欢这样,因为每次调用都会创建自己的堆栈,这可能会导致 WhosebugError。
我知道,应该有非常大量的调用,它很可能不会发生,但是,我仍然需要一个没有递归的解决方案,就像一个普通的 while 循环,但是有异步代码。
如何使用 reactor 实现此目的?
当给定代码存在并使用 retry
运算符时,您可能 return 错误 Mono
。
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(5);
}
class CodeAlreadyExistsException extends RuntimeException {}
不过请注意,重试将重试您的所有步骤。所以,如果你有更复杂的代码,比如:
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> doSomeExpensiveOperation1())
.flatMap(code -> doSomeDangerousOperation2())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(5);
}
class CodeAlreadyExistsException extends RuntimeException {}
然后您在 "findByCode" 之前的所有步骤将再次重复,包括 doSomeExpensiveOperation1 和 doSomeDangerousOperation2。
要无限期地重试直到满足某些条件,您应该:
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(CodeAlreadyExistsException.class::isInstance)
}
class CodeAlreadyExistsException extends RuntimeException {}
谢谢@alexander-pankin。
我需要使用项目反应器异步生成唯一代码。
方法签名如下所示:
public Mono<String> generateCode()
所以流程应该是这样的:
- 生成随机码
- 检查数据库中是否存在此代码
- 如果存在,重新生成代码(第1步)并再次检查(第2步)
- 如果代码是唯一的,return它
我目前的解决方案是像这样递归调用 generateCode:
Mono<String> generateCode() {
String code = generateCodeValue();
return emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt.map(c -> generateCode()).orElseGet(() -> Mono.just(code)));
}
但我不喜欢这样,因为每次调用都会创建自己的堆栈,这可能会导致 WhosebugError。
我知道,应该有非常大量的调用,它很可能不会发生,但是,我仍然需要一个没有递归的解决方案,就像一个普通的 while 循环,但是有异步代码。
如何使用 reactor 实现此目的?
当给定代码存在并使用 retry
运算符时,您可能 return 错误 Mono
。
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(5);
}
class CodeAlreadyExistsException extends RuntimeException {}
不过请注意,重试将重试您的所有步骤。所以,如果你有更复杂的代码,比如:
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> doSomeExpensiveOperation1())
.flatMap(code -> doSomeDangerousOperation2())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(5);
}
class CodeAlreadyExistsException extends RuntimeException {}
然后您在 "findByCode" 之前的所有步骤将再次重复,包括 doSomeExpensiveOperation1 和 doSomeDangerousOperation2。
要无限期地重试直到满足某些条件,您应该:
Mono<String> generateCode() {
return Mono.fromCallable(() -> generateCodeValue())
.flatMap(code -> emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt
.map(c -> Mono.<String>error(new CodeAlreadyExistsException()))
.orElseGet(() -> Mono.just(code))))
.retry(CodeAlreadyExistsException.class::isInstance)
}
class CodeAlreadyExistsException extends RuntimeException {}
谢谢@alexander-pankin。