Conversation
d534cf5 to
3b9d4ee
Compare
src/main/java/io/tarantool/driver/api/retry/RequestRetryPolicy.java
Outdated
Show resolved
Hide resolved
a89b1c5 to
759c9d2
Compare
321d835 to
774cd55
Compare
f01b530 to
aa5e6bf
Compare
src/main/java/io/tarantool/driver/api/retry/TarantoolRequestRetryPolicies.java
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/TarantoolRequestRetryPolicies.java
Show resolved
Hide resolved
src/main/java/io/tarantool/driver/api/retry/RequestRetryPolicy.java
Outdated
Show resolved
Hide resolved
| */ | ||
| public interface RequestRetryPolicy { | ||
|
|
||
| ScheduledExecutorService timeoutScheduler = |
There was a problem hiding this comment.
This field will be static and public, I believe we are not willing to do that
There was a problem hiding this comment.
There is a problem that we need this ScheduledExecutorService timeoutScheduler in the interface to use solutions like this one:
RequestRetryPolicy policy = throwable -> true;
src/main/java/io/tarantool/driver/api/retry/RequestRetryPolicy.java
Outdated
Show resolved
Hide resolved
5d450ea to
c7bd439
Compare
akudiyar
left a comment
There was a problem hiding this comment.
Not a full review (we need to fix at least one place first because the second is almost the same). I feel that the new code will be much easier to understand if it will have any comments regarding the logic. Currently, it is not clear what potential failure cases we are covering by what statement, which adds an additional future handler. Also, I have some doubts that this code will work as intended because we are not waiting anywhere on the modified futures after adding a handler to it.
| /** | ||
| * @author Artyom Dubinin | ||
| */ | ||
| final class DefaultTimeoutScheduler { |
There was a problem hiding this comment.
I believe we don't need a separate class-container for that. We already have TarantoolRequestRetryPolicies where we can put and access this private static variable.
There was a problem hiding this comment.
Moved to TarantoolRequestRetryPolicies
src/main/java/io/tarantool/driver/api/retry/RequestRetryPolicy.java
Outdated
Show resolved
Hide resolved
| } while (this.canRetryRequest(ex)); | ||
| throw new CompletionException(ex); | ||
| }, executor); | ||
| default <T> CompletableFuture<T> failAfterRequestTimeout(CompletableFuture<T> resultFuture) { |
There was a problem hiding this comment.
Same for this method - it may be an internal method of the new Runnable class
| return null; | ||
| } | ||
|
|
||
| while (ex instanceof ExecutionException || ex instanceof CompletionException) { |
There was a problem hiding this comment.
nit: This loop may be a part of some separate error handler. Not neccesasry now btw
| CompletableFuture<T> operationFuture = operation.get(); | ||
| CompletableFuture<T> requestTimeoutFuture = failAfterRequestTimeout(resultFuture); | ||
|
|
||
| operationFuture.acceptEither(requestTimeoutFuture, resultFuture::complete).exceptionally(ex -> { |
There was a problem hiding this comment.
What will happen when operationFuture completes normally?
There was a problem hiding this comment.
ALso I don't see who is waiting on the result future produced from acceptEither. Without that the desired effect will not be achieved
There was a problem hiding this comment.
What will happen when operationFuture completes normally?
resultFuture::complete
There was a problem hiding this comment.
ALso I don't see who is waiting on the result future produced from
acceptEither. Without that the desired effect will not be achieved
We don't need to wait this future, with waiting it will be the same synchronous stuff
| resultFuture.completeExceptionally(ex); | ||
| } | ||
| return null; | ||
| }).exceptionally(ex -> { |
There was a problem hiding this comment.
From where comes the exception that is handled here? What is the case for it?
There was a problem hiding this comment.
If previous exceptionally completed with exception like problem with incorrect user canRetryRequest, we'd go there
| final TimeoutException ex = new TimeoutException("Request timeout after " + requestTimeout); | ||
| return future.completeExceptionally(ex); | ||
| }, requestTimeout, TimeUnit.MILLISECONDS); | ||
| resultFuture.whenComplete((res, ex) -> scheduledFuture.cancel(false)); |
There was a problem hiding this comment.
I believe it will not work this way. whenComplete returns a new future on which we need to call join or get to invoke the effect. It doesn't change resultFuture itself.
There was a problem hiding this comment.
I believe it will not work this way. whenComplete returns a new future on which we need to call
joinorgetto invoke the effect. It doesn't change resultFuture itself.
We don't give a care what whenComplete return us, we should only know that resultFuture is completed. And with this knowledge we just cancel scheduledFuture cause it isn't needed already
| ScheduledFuture<?> delayFuture = getTimeoutScheduler().schedule(() -> { | ||
| runAsyncOperation(operation, resultFuture, lastExceptionWrapper); | ||
| }, getDelay(), TimeUnit.MILLISECONDS); | ||
| resultFuture.whenComplete((r, e) -> delayFuture.cancel(false)); |
There was a problem hiding this comment.
I believe it will not work this way. whenComplete returns a new future on which we need to call join or get to invoke the effect. It doesn't change resultFuture itself.
There was a problem hiding this comment.
We don't want to change resultFuture here. It's just cancel already started delayFuture, it's like optimization
There was a problem hiding this comment.
I've been thinking about it and here's what:
Returns a new CompletionStage with the same result or exception as this stage, that executes the given action when this stage completes.
WhenComplete returns the same result as resultFuture. We don't need to wait this whenComplete future.
| } | ||
|
|
||
| @Test | ||
| void testAsyncPerformance() { |
There was a problem hiding this comment.
We need to make a sync + async parallel test with the use of different threads
c13c011 to
d736235
Compare
akudiyar
left a comment
There was a problem hiding this comment.
I approve this as we discussed all the details verbally, with two conditions:
- CHANGELOG needs to be fixed
- #341 needs to be implemented right after that PR, because these two new methods in API are a bad change, the method contents are too complex for a new reader and the unit tests for this logic are lacking.
CHANGELOG.md
Outdated
| ### Features | ||
| - Add `fields` option to ProxySpace for controlling the result tuple fields ([#236](https://github.com/tarantool/cartridge-java/pull/236)) | ||
| - Parse metadata from crud response ([#272](https://github.com/tarantool/cartridge-java/pull/272)) | ||
| - Do not use sync calls instead of async in retrying ([#299](https://github.com/tarantool/cartridge-java/pull/299)) |
There was a problem hiding this comment.
This needs to be moved to unreleased
6d80a5d to
e6c3c57
Compare
We had synchronous get and sleep, now we use timeoutScheduler for these purposes. The retry is invoked by recursive method calls in the asynchronous calls section.
I haven't forgotten about:
Related issues:
Closes #299