项目反应堆:如何重试具有不同论点的单声道直到满足某些条件

时间:2019-03-08 18:46:24

标签: java asynchronous project-reactor

我需要与Project Reactor异步生成唯一的代码。

方法签名如下:

public Mono<String> generateCode() 

所以流程应该是这样的:

  1. 生成随机代码
  2. 检查此代码是否存在于数据库中
  3. 如果存在,请重新生成代码(步骤1)并再次检查(步骤2)
  4. 如果代码是唯一的,请返回

我当前的解决方案是像这样递归调用generateCode:

 Mono<String> generateCode() {
    String code = generateCodeValue();
    return emailConfirmationRepository
        .findByCode(code)
        .flatMap(codeOpt -> codeOpt.map(c -> generateCode()).orElseGet(() -> Mono.just(code)));
  }

但是我不喜欢这样,因为每个调用都会创建自己的堆栈,这可能导致StackOverflowError。

我知道应该有大量的调用,这很可能不会发生,但是仍然,我需要一个没有递归的解决方案,像一个普通的while循环,但是需要异步代码。

如何使用电抗器实现这一目标?

3 个答案:

答案 0 :(得分:1)

但是请注意,该重试将重试您的所有步骤。因此,如果您有更复杂的代码,例如:

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。

答案 1 :(得分:1)

要重试它,直到无限期满足某些条件,您应该:

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。

答案 2 :(得分:0)

当给定代码存在时,您可以返回错误Mono,并使用retry运算符。

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 {}