Split retrying into more detailed modules#340
Conversation
5169d53 to
d5febfe
Compare
d5febfe to
9409a8d
Compare
akudiyar
left a comment
There was a problem hiding this comment.
Overall looks better than the current state, let's comb it out a bit
src/main/java/io/tarantool/driver/api/retry/RequestRetryPolicy.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RequestTimeoutOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RequestTimeoutOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RequestTimeoutOperation.java
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperationWithAttempts.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperationWithAttempts.java
Outdated
Show resolved
Hide resolved
| new RetryingAsyncOperation<>(this, operation, resultFuture, lastExceptionWrapper); | ||
| CompletableFuture.runAsync(() -> { | ||
| runAsyncOperation(operation, resultFuture, lastExceptionWrapper); | ||
| retryingAsyncOperation.run(); |
There was a problem hiding this comment.
Wouldn't it be better here to organize the code as
.runAsync(retryingAsyncOperation, executor).acceptEither(... global timeout future..., ...dummy callback...) ?
There was a problem hiding this comment.
The current variant does not schedule the global timeout future correctly, because the "run()" method is executed synchronously in the current thread
There was a problem hiding this comment.
And we need to start operation asynchronously because we need to start timer after starting of the task
There was a problem hiding this comment.
But you are first finishing the task here and then scheduling a timer. You need to run the main task asynchronously.
There was a problem hiding this comment.
But you are first finishing the task here and then scheduling a timer. You need to run the main task asynchronously.
I don't finish the task here, I just start it. Using acceptEither could give us the probability of completing the timeout task before the operation was started
There was a problem hiding this comment.
It should never happen really. Both tasks are scheduled with acceptEither.
There was a problem hiding this comment.
Yeah, it will wait for them until they both finish. But retryingAsyncOperation.run(); is not running of the operation, it's just starting of operation. Then the scheduler can start timeout before operation
There was a problem hiding this comment.
runAsync is not running the operation too, it just schedules it in the executor. We schedule both tasks and wait on both, which one finishes first:
https://www.concretepage.com/java/java-8/java-completablefuture-accepteither
Note, we may need to use supplyAsync instead of runAsync, depending on the callback.
There was a problem hiding this comment.
You already have a good example in your code BTW: https://github.com/tarantool/cartridge-java/pull/340/files#diff-8c78be7b6b292540e567ac6d0bd09e022bb23e553a11b407d95ed3dcb2709dbdR50
There was a problem hiding this comment.
This code will be cleaner, although I admit run()" is not "synchronous" in the way that we get the operation result first. But we may call the callback in whenComplete() there even before we start the timeout.
| } | ||
| return null; | ||
| }).exceptionally(ex -> { // if error has been happened in previous exceptionally section | ||
| public <R> CompletableFuture<R> wrapOperation(Supplier<CompletableFuture<R>> operation, Executor executor) { |
There was a problem hiding this comment.
It seems that this function can now be combined with the one in the base class and does not need a separate implementation
There was a problem hiding this comment.
It was combined if I remember it correcty
76958bb to
2721d58
Compare
akudiyar
left a comment
There was a problem hiding this comment.
Answered some of the comments
src/main/java/io/tarantool/driver/api/retry/RequestTimeoutOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperation.java
Outdated
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperation.java
Outdated
Show resolved
Hide resolved
| // start async operation running | ||
| CompletableFuture<T> operationFuture = operation.get(); | ||
| // start scheduled request timeout task | ||
| // it never completes correctly only exceptionally |
There was a problem hiding this comment.
We still need to either delete the comment (it is duplicated by the class Javadoc) or rewrite it to the timeout task can only be completed with an exception or canceled for example.
| CompletableFuture<T> requestTimeoutFuture = requestTimeoutOperation.get(); | ||
|
|
||
| operationFuture.acceptEither(requestTimeoutFuture, resultFuture::complete) | ||
| .exceptionally(ex -> { // if requestTimeout has been raised or operation return exception |
There was a problem hiding this comment.
But it will be the only one, instead of several unnecessary return null statements.
|
|
||
| if (policy.canRetryRequest(ex)) { | ||
| // retry it after delay | ||
| ScheduledFuture<?> delayFuture = TarantoolRequestRetryPolicies.getTimeoutScheduler() |
There was a problem hiding this comment.
Please add any description to the error. Otherwise, anyone will need to dig down the sources for the source code line.
| resultFuture.completeExceptionally(ex); | ||
| } | ||
| return null; | ||
| }).exceptionally(ex -> { // if error has been happened in previous exceptionally section |
There was a problem hiding this comment.
If try ... except is within a callback, it's a normal practice and even the only way in some cases (like for the checked exceptions).
src/main/java/io/tarantool/driver/api/retry/RetryingAsyncOperation.java
Outdated
Show resolved
Hide resolved
| new RetryingAsyncOperation<>(this, operation, resultFuture, lastExceptionWrapper); | ||
| CompletableFuture.runAsync(() -> { | ||
| runAsyncOperation(operation, resultFuture, lastExceptionWrapper); | ||
| retryingAsyncOperation.run(); |
There was a problem hiding this comment.
But you are first finishing the task here and then scheduling a timer. You need to run the main task asynchronously.
d1e379e to
1428b81
Compare
Closes #341 Co-authored-by: Alexey Kuzin <akudiyar@gmail.com>
|
@akudiyar please take a look on the PR. |
akudiyar
left a comment
There was a problem hiding this comment.
It seems that some changes that I was reviewing disappeared completely. so I think we need to merge this already. Nvm these comments, but let them be
| new RetryingAsyncOperation<>(this, operation, resultFuture, lastExceptionWrapper); | ||
| CompletableFuture.runAsync(() -> { | ||
| runAsyncOperation(operation, resultFuture, lastExceptionWrapper); | ||
| retryingAsyncOperation.run(); |
There was a problem hiding this comment.
You already have a good example in your code BTW: https://github.com/tarantool/cartridge-java/pull/340/files#diff-8c78be7b6b292540e567ac6d0bd09e022bb23e553a11b407d95ed3dcb2709dbdR50
| new RetryingAsyncOperation<>(this, operation, resultFuture, lastExceptionWrapper); | ||
| CompletableFuture.runAsync(() -> { | ||
| runAsyncOperation(operation, resultFuture, lastExceptionWrapper); | ||
| retryingAsyncOperation.run(); |
There was a problem hiding this comment.
This code will be cleaner, although I admit run()" is not "synchronous" in the way that we get the operation result first. But we may call the callback in whenComplete() there even before we start the timeout.
I haven't forgotten about:
Related issues:
Closes #341