Реактор проекта: как повторить моно с другим аргументом, пока не будет выполнено некоторое условие - PullRequest
0 голосов
/ 08 марта 2019

Мне нужно генерировать уникальный код асинхронно с реактором проекта.

Подпись метода выглядит следующим образом:

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 ]

1 голос
/ 10 марта 2019

Обратите внимание, однако, что повтор повторит все ваши шаги.Итак, если у вас есть более сложный код, такой как:

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" будут повторяться снова, включая doSomeExорогоOperation1 и doSomeDangerousOperation2.

1 голос
/ 11 марта 2019

Чтобы повторить попытку, пока НЕКОТОРЫЕ УСЛОВИЯ УСТАНОВЛЕНЫ на неопределенный срок, вы должны:

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

Спасибо @ александр-панкин.

0 голосов
/ 09 марта 2019

Вы можете вернуть ошибку 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 {}
...