Мне нужно сгенерировать уникальный код асинхронно с реактором проекта.
Сигнатура метода выглядит так:
public Mono<String> generateCode()
Таким образом, поток должен быть таким:
Мое текущее решение состоит в том, чтобы рекурсивно вызвать generateCode следующим образом:
Mono<String> generateCode() {
String code = generateCodeValue();
return emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt.map(c -> generateCode()).orElseGet(() -> Mono.just(code)));
}
Но мне это не нравится, потому что каждый вызов создает свой стек и это может привести к StackOverflowError.
Я знаю, вызовов должно быть очень большое количество, скорее всего этого не будет, но все же, мне нужно решение без рекурсии, как простой цикл while, но с асинхронным кодом.
Как я могу добиться этого с помощью реактора?




Вы можете вернуть ошибку 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 {}
Обратите внимание, однако, что повторная попытка повторит все ваши шаги. Итак, если у вас есть более сложный код, например:
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.
Хотя он выполнит свою работу, но мне любопытно, как повторить попытку, пока не будет выполнено НЕКОТОРОЕ УСЛОВИЕ (без ограничения повторных попыток)
@RodneyZ есть ли способ повторить только одну «предыдущую» операцию в цепочке?
Чтобы повторить попытку ДО ВЫПОЛНЕНИЯ НЕКОТОРОГО УСЛОВИЯ на неопределенный срок, вы должны:
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.
Спасибо, @RodneyZ, это именно то, что мне нужно!
Вы можете использовать любой вариант повтора - projectreactor.io/docs/core/release/api/reactor/core/publisher/…