/** * {@inheritDoc} * * <p>Ensures retries are only scheduled if the {@link StreamResumptionStrategy} in the {@code * ServerStreamingAttemptCallable} supports it. */ @Override public boolean shouldRetry( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings nextAttemptSettings) throws CancellationException { // Unwrap if (prevThrowable instanceof ServerStreamingAttemptException) { ServerStreamingAttemptException attemptExceptino = (ServerStreamingAttemptException) prevThrowable; prevThrowable = prevThrowable.getCause(); if (!attemptExceptino.canResume()) { return false; } } return super.shouldRetry(prevThrowable, prevResponse, nextAttemptSettings); } }
/** * Called when the outer {@link ResponseObserver} wants to prematurely cancel the stream. * * @see StreamController#cancel() */ private void onCancel() { StreamController localInnerController; synchronized (lock) { if (cancellationCause != null) { return; } // NOTE: BasicRetryingFuture will replace j.u.c.CancellationExceptions with it's own, // which will not have the current stacktrace, so a special wrapper has be used here. cancellationCause = new ServerStreamingAttemptException( new CancellationException("User cancelled stream"), resumptionStrategy.canResume(), seenSuccessSinceLastError); localInnerController = innerController; } if (localInnerController != null) { localInnerController.cancel(); } }
@Test @SuppressWarnings("ConstantConditions") public void testInitialRetry() { resumptionStrategy = new MyStreamResumptionStrategy(); ServerStreamingAttemptCallable<String, String> callable = createCallable(); callable.start(); MockServerStreamingCall<String, String> call = innerCallable.popLastCall(); // Send initial error FakeApiException initialError = new FakeApiException(null, Code.UNAVAILABLE, true); call.getController().getObserver().onError(initialError); // Should notify the outer future Throwable outerError = null; try { fakeRetryingFuture.getAttemptResult().get(1, TimeUnit.SECONDS); } catch (ExecutionException e) { outerError = e.getCause(); } catch (Throwable e) { outerError = e; } Truth.assertThat(outerError).isInstanceOf(ServerStreamingAttemptException.class); Truth.assertThat(((ServerStreamingAttemptException) outerError).hasSeenResponses()).isFalse(); Truth.assertThat(((ServerStreamingAttemptException) outerError).canResume()).isTrue(); Truth.assertThat(outerError.getCause()).isEqualTo(initialError); // Make the retry call callable.call(); call = innerCallable.popLastCall(); // Verify the request and send a response Truth.assertThat(call.getRequest()).isEqualTo("request > 0"); }
/** * {@inheritDoc} * * <p>The attempt settings will be reset if the stream attempt produced any messages. */ @Override public TimedAttemptSettings createNextAttempt( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings prevSettings) { if (prevThrowable instanceof ServerStreamingAttemptException) { ServerStreamingAttemptException attemptException = (ServerStreamingAttemptException) prevThrowable; prevThrowable = prevThrowable.getCause(); // If we have made progress in the last attempt, then reset the delays if (attemptException.hasSeenResponses()) { prevSettings = createFirstAttempt() .toBuilder() .setFirstAttemptStartTimeNanos(prevSettings.getFirstAttemptStartTimeNanos()) .setOverallAttemptCount(prevSettings.getOverallAttemptCount()) .build(); } } return super.createNextAttempt(prevThrowable, prevResponse, prevSettings); }
Truth.assertThat(((ServerStreamingAttemptException) outerError).hasSeenResponses()).isTrue(); Truth.assertThat(((ServerStreamingAttemptException) outerError).canResume()).isTrue(); Truth.assertThat(outerError.getCause()).isEqualTo(innerError);
/** * {@inheritDoc} * * <p>The attempt settings will be reset if the stream attempt produced any messages. */ @Override public TimedAttemptSettings createNextAttempt( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings prevSettings) { if (prevThrowable instanceof ServerStreamingAttemptException) { ServerStreamingAttemptException attemptException = (ServerStreamingAttemptException) prevThrowable; prevThrowable = prevThrowable.getCause(); // If we have made progress in the last attempt, then reset the delays if (attemptException.hasSeenResponses()) { prevSettings = createFirstAttempt() .toBuilder() .setFirstAttemptStartTimeNanos(prevSettings.getFirstAttemptStartTimeNanos()) .setOverallAttemptCount(prevSettings.getOverallAttemptCount()) .build(); } } return super.createNextAttempt(prevThrowable, prevResponse, prevSettings); }
/** * {@inheritDoc} * * <p>Ensures retries are only scheduled if the {@link StreamResumptionStrategy} in the {@code * ServerStreamingAttemptCallable} supports it. */ @Override public boolean shouldRetry( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings nextAttemptSettings) throws CancellationException { // Unwrap if (prevThrowable instanceof ServerStreamingAttemptException) { ServerStreamingAttemptException attemptExceptino = (ServerStreamingAttemptException) prevThrowable; prevThrowable = prevThrowable.getCause(); if (!attemptExceptino.canResume()) { return false; } } return super.shouldRetry(prevThrowable, prevResponse, nextAttemptSettings); } }
/** * Called when the outer {@link ResponseObserver} wants to prematurely cancel the stream. * * @see StreamController#cancel() */ private void onCancel() { StreamController localInnerController; synchronized (lock) { if (cancellationCause != null) { return; } // NOTE: BasicRetryingFuture will replace j.u.c.CancellationExceptions with it's own, // which will not have the current stacktrace, so a special wrapper has be used here. cancellationCause = new ServerStreamingAttemptException( new CancellationException("User cancelled stream"), resumptionStrategy.canResume(), seenSuccessSinceLastError); localInnerController = innerController; } if (localInnerController != null) { localInnerController.cancel(); } }
/** * Called when the current RPC fails. The error will be bubbled up to the outer {@link * RetryingFuture} via the {@link #innerAttemptFuture}. */ private void onAttemptError(Throwable throwable) { if (cancellationCause != null) { // Take special care to preserve the cancellation's stack trace. innerAttemptFuture.setException(cancellationCause); } else { // Wrap the original exception and provide more context for StreamingRetryAlgorithm. innerAttemptFuture.setException( new ServerStreamingAttemptException( throwable, resumptionStrategy.canResume(), seenSuccessSinceLastError)); } }
/** * Called when the current RPC fails. The error will be bubbled up to the outer {@link * RetryingFuture} via the {@link #innerAttemptFuture}. */ private void onAttemptError(Throwable throwable) { if (cancellationCause != null) { // Take special care to preserve the cancellation's stack trace. innerAttemptFuture.setException(cancellationCause); } else { // Wrap the original exception and provide more context for StreamingRetryAlgorithm. innerAttemptFuture.setException( new ServerStreamingAttemptException( throwable, resumptionStrategy.canResume(), seenSuccessSinceLastError)); } }