if (!externalFuture.getAttemptSettings().getRpcTimeout().isZero()) { currentCallContext = currentCallContext.withTimeout(externalFuture.getAttemptSettings().getRpcTimeout()); externalFuture.setAttemptFuture(new NonCancellableFuture<Void>()); if (externalFuture.isDone()) { return null; externalFuture.setAttemptFuture(transformed); } catch (Throwable e) { externalFuture.setAttemptFuture(ApiFutures.<Void>immediateFailedFuture(e));
@Override public void addListener(Runnable runnable, Executor executor) { pollingFuture.addListener(runnable, executor); }
@Override public ResponseT get() throws ExecutionException, InterruptedException { return (ResponseT) pollingFuture.get().getResponse(); }
@Override public ResponseT call() { try { // NOTE: unlike gax's AttemptCallable, this ignores rpc timeouts externalFuture.setAttemptFuture(new NonCancellableFuture<ResponseT>()); if (externalFuture.isDone()) { return null; } ApiFuture<ResponseT> internalFuture = callable.futureCall(request, callContext); externalFuture.setAttemptFuture(internalFuture); } catch (Throwable e) { externalFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } return null; } }
RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertNull(future.peekAttemptResult()); assertSame(future.getAttemptResult(), future.getAttemptResult()); assertFalse(future.getAttemptResult().isDone()); assertFalse(future.getAttemptResult().isCancelled()); future.setAttemptFuture(executor.submit(future)); exception = null; checks++; Future<String> attemptResult = future.getAttemptResult(); try { attemptResult.get(); assertNotNull(future.peekAttemptResult()); } catch (CancellationException e) { cancellationException = e; if (!future.cancel(true)) { failedCancelations++; assertTrue(future.isDone()); assertNotNull(cancellationException); assertTrue(future.getAttemptSettings().getAttemptCount() > 0); assertFutureCancel(future); localExecutor.shutdownNow();
void assertFutureSuccess(RetryingFuture<String> future) throws ExecutionException, InterruptedException, TimeoutException { assertEquals("SUCCESS", future.get(3, TimeUnit.SECONDS)); assertTrue(future.isDone()); assertFalse(future.isCancelled()); assertEquals("SUCCESS", future.peekAttemptResult().get(3, TimeUnit.SECONDS)); assertSame(future.peekAttemptResult(), future.peekAttemptResult()); assertTrue(future.peekAttemptResult().isDone()); assertFalse(future.peekAttemptResult().isCancelled()); assertEquals("SUCCESS", future.getAttemptResult().get(3, TimeUnit.SECONDS)); assertSame(future.getAttemptResult(), future.getAttemptResult()); assertTrue(future.getAttemptResult().isDone()); assertFalse(future.getAttemptResult().isCancelled()); String res = future.get(); ApiFuture<?> gottentAttempt = future.getAttemptResult(); ApiFuture<?> peekedAttempt = future.peekAttemptResult(); // testing completed immutability assertFalse(future.cancel(true)); assertFalse(future.cancel(false)); assertSame(gottentAttempt, future.getAttemptResult()); assertSame(peekedAttempt, future.peekAttemptResult()); assertSame(res, future.get()); assertTrue(future.isDone()); assertFalse(future.isCancelled()); }
if (!outerRetryingFuture.getAttemptSettings().getRpcTimeout().isZero()) { attemptContext = attemptContext.withStreamWaitTimeout( outerRetryingFuture.getAttemptSettings().getRpcTimeout()); .attemptStarted(outerRetryingFuture.getAttemptSettings().getOverallAttemptCount()); attemptContext); outerRetryingFuture.setAttemptFuture(innerAttemptFuture);
@Test public void testSuccessWithFailuresPeekGetAttempt() throws Exception { FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); RetryingExecutorWithContext<String> executor = getExecutor(getAlgorithm(FAST_RETRY_SETTINGS, 0, null)); RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertNull(future.peekAttemptResult()); assertSame(future.peekAttemptResult(), future.peekAttemptResult()); assertFalse(future.getAttemptResult().isDone()); assertFalse(future.getAttemptResult().isCancelled()); Exception exception = null; try { future.get(1L, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { exception = e; } assertNotNull(exception); future.setAttemptFuture(executor.submit(future)); assertFutureSuccess(future); assertEquals(5, future.getAttemptSettings().getAttemptCount()); }
/** * Submits an attempt for execution in the current thread, causing the current thread to sleep for * the specified by the {@link RetryingFuture#getAttemptSettings()} amount of time. As result, * this method completes execution only after the specified {@code retryingFuture} completes. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return returns completed {@code retryingFuture} */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { while (!retryingFuture.isDone()) { try { sleep(retryingFuture.getAttemptSettings().getRandomizedRetryDelay()); ResponseT response = retryingFuture.getCallable().call(); retryingFuture.setAttemptFuture(ApiFutures.immediateFuture(response)); } catch (InterruptedException | InterruptedIOException | ClosedByInterruptException e) { Thread.currentThread().interrupt(); retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } catch (Exception e) { retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } } return retryingFuture; }
/** * Submits an attempt for execution in a different thread. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return submitted attempt future */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { try { ListenableFuture<ResponseT> attemptFuture = scheduler.schedule( retryingFuture.getCallable(), retryingFuture.getAttemptSettings().getRandomizedRetryDelay().toMillis(), TimeUnit.MILLISECONDS); return new ListenableFutureToApiFuture<>(attemptFuture); } catch (RejectedExecutionException e) { return ApiFutures.immediateFailedFuture(e); } } }
outerRetryingFuture.getAttemptSettings().getGlobalSettings().getTotalTimeout();
@Override public boolean isDone() { return pollingFuture.isDone(); }
@Override public boolean cancel(boolean mayInterruptIfRunning) { return pollingFuture.cancel(mayInterruptIfRunning); }
@Override public ApiFuture<MetadataT> peekMetadata() { ApiFuture<OperationSnapshot> future = pollingFuture.peekAttemptResult(); synchronized (lock) { if (peekedAttemptResult == future) { return peekedPollResult; } peekedAttemptResult = future; peekedPollResult = ApiFutures.transform(peekedAttemptResult, metadataTransformer, directExecutor()); return peekedPollResult; } }
@Override public boolean isCancelled() { return pollingFuture.isCancelled(); }
@Override public ApiFuture<MetadataT> getMetadata() { ApiFuture<OperationSnapshot> future = pollingFuture.getAttemptResult(); synchronized (lock) { if (gottenAttemptResult == future) { return gottenPollResult; } gottenAttemptResult = future; gottenPollResult = ApiFutures.transform(gottenAttemptResult, metadataTransformer, directExecutor()); return gottenPollResult; } } }
RetryingFuture<String> future = executor.createFuture(callable, retryingContext); assertNull(future.peekAttemptResult()); assertSame(future.getAttemptResult(), future.getAttemptResult()); assertFalse(future.getAttemptResult().isDone()); assertFalse(future.getAttemptResult().isCancelled()); future.setAttemptFuture(executor.submit(future)); exception = null; checks++; Future<String> attemptResult = future.getAttemptResult(); try { assertFalse(attemptResult.cancel(true)); attemptResult.get(); assertNotNull(future.peekAttemptResult()); } catch (ExecutionException e) { exception = (CustomException) e.getCause(); } while (exception != null && checks < maxRetries + 1); assertTrue(future.isDone()); assertFutureSuccess(future); assertEquals(15, future.getAttemptSettings().getAttemptCount()); assertTrue("checks is equal to " + checks, checks > 1 && checks <= maxRetries); localExecutor.shutdownNow();
Exception exception = null; try { future.get(3, TimeUnit.SECONDS); } catch (CancellationException e) { exception = e; assertTrue(future.isDone()); assertTrue(future.isCancelled()); future.getAttemptResult().get(3, TimeUnit.SECONDS); } catch (CancellationException e) { exception = e; assertSame(future.getAttemptResult(), future.getAttemptResult()); assertTrue(future.getAttemptResult().isDone()); assertTrue(future.getAttemptResult().isCancelled()); try { future.peekAttemptResult().get(3, TimeUnit.SECONDS); } catch (CancellationException e) { exception = e; assertSame(future.peekAttemptResult(), future.peekAttemptResult()); assertTrue(future.peekAttemptResult().isDone()); assertTrue(future.peekAttemptResult().isCancelled()); ApiFuture<?> gottentAttempt = future.getAttemptResult(); ApiFuture<?> peekedAttempt = future.peekAttemptResult(); assertFalse(future.cancel(true));
if (!outerRetryingFuture.getAttemptSettings().getRpcTimeout().isZero()) { attemptContext = attemptContext.withStreamWaitTimeout( outerRetryingFuture.getAttemptSettings().getRpcTimeout()); .attemptStarted(outerRetryingFuture.getAttemptSettings().getOverallAttemptCount()); attemptContext); outerRetryingFuture.setAttemptFuture(innerAttemptFuture);
/** * Submits an attempt for execution in the current thread, causing the current thread to sleep for * the specified by the {@link RetryingFuture#getAttemptSettings()} amount of time. As result, * this method completes execution only after the specified {@code retryingFuture} completes. * * @param retryingFuture the future previously returned by {@link #createFuture(Callable, * RetryingContext)} * @return returns completed {@code retryingFuture} */ @Override public ApiFuture<ResponseT> submit(RetryingFuture<ResponseT> retryingFuture) { while (!retryingFuture.isDone()) { try { sleep(retryingFuture.getAttemptSettings().getRandomizedRetryDelay()); ResponseT response = retryingFuture.getCallable().call(); retryingFuture.setAttemptFuture(ApiFutures.immediateFuture(response)); } catch (InterruptedException | InterruptedIOException | ClosedByInterruptException e) { Thread.currentThread().interrupt(); retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } catch (Exception e) { retryingFuture.setAttemptFuture(ApiFutures.<ResponseT>immediateFailedFuture(e)); } } return retryingFuture; }