@Nullable private Deadline effectiveDeadline() { // Call options and context are immutable, so we don't need to cache the deadline. return min(callOptions.getDeadline(), context.getDeadline()); }
@Nullable private Deadline effectiveDeadline() { // Call options and context are immutable, so we don't need to cache the deadline. return min(callOptions.getDeadline(), context.getDeadline()); }
@Override public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { // Only add a deadline if no other deadline has been set. if (callOptions.getDeadline() == null && Context.current().getDeadline() == null) { callOptions = callOptions.withDeadlineAfter(duration.toMillis(), TimeUnit.MILLISECONDS); } return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) { }; } }
@Override public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { // Only add a deadline if no other deadline has been set. if (callOptions.getDeadline() == null && Context.current().getDeadline() == null) { callOptions = callOptions.withDeadlineAfter(duration.toMillis(), TimeUnit.MILLISECONDS); } return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) { }; } }
/** * Create an {@link CallOptions} that has a fail safe RPC deadline to make sure that unary * operations don't hang. This will have to be overridden for streaming RPCs like read rows. * <p> * The logic is as follows: * <ol> * <li> If the user provides a deadline, use the deadline</li> * <li> Else If this is a streaming read, don't set an explicit deadline. The * {@link com.google.cloud.bigtable.grpc.io.Watchdog} will handle hanging</li> * <li> Else Set a deadline of {@link #UNARY_DEADLINE_MINUTES} minutes deadline.</li> * </ol> * * @see com.google.cloud.bigtable.grpc.io.Watchdog Watchdog which handles hanging for streaming * reads. * * @return a {@link CallOptions} */ protected CallOptions getRpcCallOptions() { if (callOptions.getDeadline() != null || isStreamingRead()) { // If the user set a deadline, honor it. // If this is a streaming read, then the Watchdog will take affect and ensure that hanging does not occur. return getOperationCallOptions(); } else { // Unary calls should fail after 6 minutes, if there isn't any response from the server. return callOptions.withDeadlineAfter(UNARY_DEADLINE_MINUTES, TimeUnit.MINUTES); } }
Deadline newDeadline = grpcCallContext.callOptions.getDeadline(); if (newDeadline == null) { newDeadline = this.callOptions.getDeadline();
if (callOptions.getDeadline() != null) { deadlineMillis = callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS);
Deadline newDeadline = grpcCallContext.callOptions.getDeadline(); if (newDeadline == null) { newDeadline = this.callOptions.getDeadline();
@Override public void start(Listener<RespT> responseListener, Metadata headers) { final long timeout; if (callOptions.getDeadline() != null) { timeout = callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); } else { timeout = TIMEOUT_MILLISECONDS; } HeaderToken token = store.getHeader(timeout, TimeUnit.MILLISECONDS); if (!token.getStatus().isOk()) { unauthorized = true; responseListener.onClose(token.getStatus(), new Metadata()); return; } headers.put(AUTHORIZATION_HEADER_KEY, token.getHeader()); delegate().start(new UnAuthResponseListener<>(responseListener, token), headers); }
@Test public void testTimeoutToDeadlineConversion() { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); ArgumentCaptor<CallOptions> capturedCallOptions = ArgumentCaptor.forClass(CallOptions.class); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), capturedCallOptions.capture())) .thenReturn(mockClientCall); Duration timeout = Duration.ofSeconds(10); Deadline minExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); GrpcCallContext context = GrpcCallContext.createDefault().withChannel(mockChannel).withTimeout(timeout); GrpcClientCalls.newCall(descriptor, context).start(mockListener, new Metadata()); Deadline maxExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtLeast(minExpectedDeadline); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtMost(maxExpectedDeadline); }
Deadline newDeadline = Deadline.after(grpcContext.getTimeout().toMillis(), TimeUnit.MILLISECONDS); Deadline oldDeadline = callOptions.getDeadline();
@Test public void testTimeoutAfterDeadline() { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); ArgumentCaptor<CallOptions> capturedCallOptions = ArgumentCaptor.forClass(CallOptions.class); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), capturedCallOptions.capture())) .thenReturn(mockClientCall); // Configure a timeout that occurs after the grpc deadline Deadline priorDeadline = Deadline.after(5, TimeUnit.SECONDS); Duration timeout = Duration.ofSeconds(10); GrpcCallContext context = GrpcCallContext.createDefault() .withChannel(mockChannel) .withCallOptions(CallOptions.DEFAULT.withDeadline(priorDeadline)) .withTimeout(timeout); GrpcClientCalls.newCall(descriptor, context).start(mockListener, new Metadata()); // Verify that the timeout is ignored Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isEqualTo(priorDeadline); }
Deadline newDeadline = Deadline.after(grpcContext.getTimeout().toMillis(), TimeUnit.MILLISECONDS); Deadline oldDeadline = callOptions.getDeadline();
Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtLeast(minExpectedDeadline); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtMost(maxExpectedDeadline);
protected <ReqT,R> ListenableFuture<R> fuCall(MethodDescriptor<ReqT,R> method, ReqT request, CallOptions callOptions, long timeoutMs) { if(timeoutMs <= 0L) timeoutMs = defaultTimeoutMs; if(timeoutMs > 0L) { Deadline deadline = callOptions.getDeadline(); Deadline timeoutDeadline = Deadline.after(timeoutMs, MILLISECONDS); if(deadline == null || timeoutDeadline.isBefore(deadline)) { callOptions = callOptions.withDeadline(timeoutDeadline); } else if(deadline.isExpired()) { return Futures.immediateFailedFuture( Status.DEADLINE_EXCEEDED.asRuntimeException()); } } final CallOptions callOpts = callOptions; return sendViaEventLoop && !isEventThread.satisfied() ? Futures.submitAsync(() -> fuCall(method, request, callOpts), ses) : fuCall(method, request, callOpts); }
Deadline existingDeadline = callOptions.getDeadline();
if (!deadlineExceeded) { logIfContextNarrowedTimeout( effectiveDeadline, callOptions.getDeadline(), context.getDeadline()); if (retryEnabled) { stream = clientTransportProvider.newRetriableStream(method, callOptions, headers, context);
if (callOptions.getDeadline() == null) { span.setTag("grpc.deadline_millis", "null"); } else { span.setTag("grpc.deadline_millis", callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS));
/** * <p>createBackoff.</p> * * @return a {@link ExponentialRetryAlgorithm} object. */ private ExponentialRetryAlgorithm createRetryAlgorithm(ApiClock clock) { long timeoutMs = retryOptions.getMaxElapsedBackoffMillis(); Deadline deadline = getOperationCallOptions().getDeadline(); if (deadline != null) { timeoutMs = deadline.timeRemaining(TimeUnit.MILLISECONDS); } RetrySettings retrySettings = RetrySettings.newBuilder() .setJittered(true) // How long should the sleep be between RPC failure and the next RPC retry? .setInitialRetryDelay(toDuration(retryOptions.getInitialBackoffMillis())) // How fast should the retry delay increase? .setRetryDelayMultiplier(retryOptions.getBackoffMultiplier()) // What is the maximum amount of sleep time between retries? // There needs to be some sane number for max retry delay, and it's unclear what that // number ought to be. 1 Minute time was chosen because some number is needed. .setMaxRetryDelay(Duration.of(1, ChronoUnit.MINUTES)) // How long should we wait before giving up retries after the first failure? .setTotalTimeout(toDuration(timeoutMs)) .build(); return new ExponentialRetryAlgorithm(retrySettings, clock); }
boolean deadlineExceeded = effectiveDeadline != null && effectiveDeadline.isExpired(); if (!deadlineExceeded) { updateTimeoutHeaders(effectiveDeadline, callOptions.getDeadline(), context.getDeadline(), headers); if (retryEnabled) {