/** * Returns a new stub with an absolute deadline. * * <p>This is mostly used for propagating an existing deadline. {@link #withDeadlineAfter} is the * recommended way of setting a new deadline, * * @since 1.0.0 * @param deadline the deadline or {@code null} for unsetting the deadline. */ public final S withDeadline(@Nullable Deadline deadline) { return build(channel, callOptions.withDeadline(deadline)); }
/** * Returns a new {@code CallOptions} with a deadline that is after the given {@code duration} from * now. */ public CallOptions withDeadlineAfter(long duration, TimeUnit unit) { return withDeadline(Deadline.after(duration, unit)); }
/** * Returns a new {@code CallOptions} with a deadline that is after the given {@code duration} from * now. */ public CallOptions withDeadlineAfter(long duration, TimeUnit unit) { return withDeadline(Deadline.after(duration, unit)); }
@Override public <RequestT> CallOptions create(MethodDescriptor<RequestT, ?> descriptor, RequestT request) { Deadline contextDeadline = Context.current().getDeadline(); if (contextDeadline != null) { return CallOptions.DEFAULT.withDeadline(contextDeadline); } else { return CallOptions.DEFAULT; } } }
@Override /** * Creates a {@link CallOptions} with a focus on {@link Deadlines}. Deadlines are decided in the following order: * <ol> * <li> If a user set a {@link Context} deadline (see {@link Context#getDeadline()}), use that</li> * <li> If a user configured deadlines via {@link CallOptionsConfig}, use it.</li> * <li> Otherwise, use {@link CallOptions#DEFAULT}.</li> * </ol> * */ public <RequestT> CallOptions create(MethodDescriptor<RequestT, ?> descriptor, RequestT request) { Deadline contextDeadline = Context.current().getDeadline(); if (contextDeadline != null) { return CallOptions.DEFAULT.withDeadline(contextDeadline); } else if (config.isUseTimeout() && request != null) { int timeout = isLongRequest(request) ? config.getLongRpcTimeoutMs() : config.getShortRpcTimeoutMs(); return CallOptions.DEFAULT.withDeadline(Deadline.after(timeout, TimeUnit.MILLISECONDS)); } else { return CallOptions.DEFAULT; } }
.callOptions .withCallCredentials(newCallCredentials) .withDeadline(newDeadline);
@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); }
.callOptions .withCallCredentials(newCallCredentials) .withDeadline(newDeadline);
callOptions = callOptions.withDeadline(newDeadline);
callOptions = callOptions.withDeadline(newDeadline);
GrpcCallContext.createDefault() .withChannel(mockChannel) .withCallOptions(CallOptions.DEFAULT.withDeadline(subsequentDeadline)) .withTimeout(timeout);
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); }
CallOptions callOpts = deadline != null ? baseCallOpts.withDeadline(deadline) : baseCallOpts; if(executor != null) callOpts = callOpts.withExecutor(executor); return Futures.catchingAsync(fuCall(method, request, callOpts, timeoutMs), Exception.class, t -> {
callOptions = callOptions.withDeadline(newDeadline);