Reputation: 9325
I need to generate unique code asynchronously with project reactor.
Method signature looks like this:
public Mono<String> generateCode()
So the flow should be like this:
My current solution is to call generateCode recursively like this:
Mono<String> generateCode() {
String code = generateCodeValue();
return emailConfirmationRepository
.findByCode(code)
.flatMap(codeOpt -> codeOpt.map(c -> generateCode()).orElseGet(() -> Mono.just(code)));
}
But I don't like this, because each call creates its own stack and this can lead to StackOverflowError.
I know, there should be a very large amount of calls, it most likely will not happen, but still, I need a solution without recursion, like a plain while loop, but with async code.
How can I achieve this with reactor?
Upvotes: 1
Views: 2650
Reputation: 94
To retry it UNTIL SOME CONDITION IS MET indefinitely you shall:
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 {}
Thanks @alexander-pankin.
Upvotes: 2
Reputation: 94
Note, though, that retry will retry all of your steps. So, if you have a more complicated code, like:
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 {}
Then all of your steps before "findByCode" will be repeated again, including doSomeExpensiveOperation1 and doSomeDangerousOperation2.
Upvotes: 3
Reputation: 3955
You could return error Mono
when given code exists and use retry
operator.
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 {}
Upvotes: 0