Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(defaultRequestTimeout) add defaultRequestTimeout property for the client #1132

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
28b073d
Feat(deadline) add deadline property for client
Aug 3, 2024
0da4da7
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 4, 2024
3b295c7
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 4, 2024
e14b9fe
Feat(deadline) changed zero deadline behavior, javadoc corrections
Sep 4, 2024
7505c7d
Feat(deadline) removed wasted DeadlineSetupClientInterceptor calls in…
Sep 4, 2024
42ebf40
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 5, 2024
809bc5b
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 5, 2024
a8bbe07
Feat(deadline) replaced bean deadlineStubTransformer with deadlineGrp…
Sep 5, 2024
5a219a7
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 5, 2024
2492865
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 5, 2024
dd26ff4
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 5, 2024
f365af7
Feat(deadline) add a test showing that the manually configured deadli…
Sep 5, 2024
650a978
Feat(timeout) changed the name of deadline property to timeout.
Sep 6, 2024
0ebcc0a
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 6, 2024
6ab4d0d
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 6, 2024
e6403b6
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 6, 2024
20dc197
Update grpc-client-spring-boot-starter/src/main/resources/META-INF/ad…
batsura-sa Sep 6, 2024
9db6998
Feat(timeout) constructor and test changed.
Sep 6, 2024
102d09e
Feat(timeout) changed the name of timeout property to defaultRequestT…
Sep 6, 2024
da2f32c
Update grpc-client-spring-boot-starter/src/main/java/net/devh/boot/gr…
batsura-sa Sep 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2016-2024 The gRPC-Spring Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.devh.boot.grpc.client.autoconfigure;

import static java.util.Objects.requireNonNull;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.MethodDescriptor;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
import net.devh.boot.grpc.client.inject.StubTransformer;
import net.devh.boot.grpc.client.interceptor.DeadlineSetupClientInterceptor;

/**
* The deadline autoconfiguration for the client.
*
* <p>
* You can disable this config by using:
* </p>
*
* <pre>
* <code>@ImportAutoConfiguration(exclude = GrpcClientDeadlineAutoConfiguration.class)</code>
* </pre>
*
* @author Sergei Batsura ([email protected])
*/
@Slf4j
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(GrpcClientAutoConfiguration.class)
public class GrpcClientDeadlineAutoConfiguration {

/**
* Creates a {@link StubTransformer} bean with interceptor that will call withDeadlineAfter with deadline from
* props.
*
*
* @param props The properties for deadline configuration.
* @return The StubTransformer bean with interceptor if deadline is configured.
* @see DeadlineSetupClientInterceptor#interceptCall(MethodDescriptor, CallOptions, Channel)
batsura-sa marked this conversation as resolved.
Show resolved Hide resolved
*/
@Bean
StubTransformer deadlineStubTransformer(final GrpcChannelsProperties props) {
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
requireNonNull(props, "properties");

return (name, stub) -> {
GrpcChannelProperties channelProps = props.getChannel(name);
if (channelProps != null && channelProps.getDeadline() != null
&& channelProps.getDeadline().toMillis() > 0L) {
return stub.withInterceptors(new DeadlineSetupClientInterceptor(channelProps.getDeadline()));
} else {
return stub;
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

import io.grpc.CallOptions;
import io.grpc.LoadBalancerRegistry;
import io.grpc.ManagedChannelBuilder;
import io.grpc.NameResolverProvider;
Expand Down Expand Up @@ -118,6 +119,34 @@ public void setAddress(final String address) {
this.address = address == null ? null : URI.create(address);
}

// --------------------------------------------------
// Target Deadline
// --------------------------------------------------

private Duration deadline = null;

/**
* Gets the default deadline for each new call.
*
* @return The connection deadline or null
* @see #setDeadline(Duration)
*/
public Duration getDeadline() {
return this.deadline;
}

/**
* Set the default deadline duration for new calls (on a per call basis). If nothing is configured then the deadline
* will not be used by default. If zero value is configured, the deadline will not be used.
batsura-sa marked this conversation as resolved.
Show resolved Hide resolved
*
* @param deadline The connection deadline or null.
*
* @see CallOptions#withDeadlineAfter(long, TimeUnit)
*/
public void setDeadline(Duration deadline) {
this.deadline = deadline;
}

// --------------------------------------------------
// defaultLoadBalancingPolicy
// --------------------------------------------------
Expand Down Expand Up @@ -480,6 +509,9 @@ public void copyDefaultsFrom(final GrpcChannelProperties config) {
if (this.address == null) {
this.address = config.address;
}
if (this.deadline == null) {
this.deadline = config.deadline;
}
if (this.defaultLoadBalancingPolicy == null) {
this.defaultLoadBalancingPolicy = config.defaultLoadBalancingPolicy;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2016-2024 The gRPC-Spring Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.devh.boot.grpc.client.interceptor;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.MethodDescriptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
* Deadline setup client interceptor that create new deadline instance from defaultDeadline.
*
* @author Sergei Batsura ([email protected])
*/
@Slf4j
@GrpcGlobalClientInterceptor
batsura-sa marked this conversation as resolved.
Show resolved Hide resolved
@RequiredArgsConstructor
public class DeadlineSetupClientInterceptor implements ClientInterceptor {

private final Duration defaultDeadline;

@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
final MethodDescriptor<ReqT, RespT> method,
final CallOptions callOptions,
final Channel next) {

if (defaultDeadline != null) {
batsura-sa marked this conversation as resolved.
Show resolved Hide resolved
return next.newCall(method,
callOptions.withDeadlineAfter(defaultDeadline.toMillis(), TimeUnit.MILLISECONDS));
} else {
return next.newCall(method, callOptions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@
"description": "Connection timeout at application startup. If set to a positive duration instructs a client to connect to GRPC-endpoint when GRPC stub is created.",
"defaultValue": 0
},
{
"name": "grpc.client.GLOBAL.deadline",
"type": "java.time.Duration",
"sourceType": "net.devh.boot.grpc.client.config.GrpcChannelProperties",
"description": "A deadline is used to specify a point in time past which a client is unwilling to wait for a response from a server"
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
},
{
"name": "grpc.client.GLOBAL.security.authority-override",
"type": "java.lang.String",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ net.devh.boot.grpc.client.autoconfigure.GrpcClientHealthAutoConfiguration
net.devh.boot.grpc.client.autoconfigure.GrpcClientMicrometerTraceAutoConfiguration
net.devh.boot.grpc.client.autoconfigure.GrpcClientSecurityAutoConfiguration
net.devh.boot.grpc.client.autoconfigure.GrpcDiscoveryClientAutoConfiguration
net.devh.boot.grpc.client.autoconfigure.GrpcClientDeadlineAutoConfiguration
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.springframework.context.annotation.Configuration;

import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
import net.devh.boot.grpc.client.autoconfigure.GrpcClientDeadlineAutoConfiguration;
import net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration;
import net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;
import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration;
Expand All @@ -28,7 +29,7 @@
@Configuration
@ImportAutoConfiguration({GrpcCommonCodecAutoConfiguration.class, GrpcServerAutoConfiguration.class,
GrpcServerFactoryAutoConfiguration.class, GrpcServerSecurityAutoConfiguration.class,
GrpcClientAutoConfiguration.class})
GrpcClientAutoConfiguration.class, GrpcClientDeadlineAutoConfiguration.class})
public class BaseAutoConfiguration {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2016-2024 The gRPC-Spring Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.devh.boot.grpc.test.setup;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.concurrent.ExecutionException;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import io.grpc.internal.testing.StreamRecorder;
import io.grpc.stub.StreamObserver;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
import net.devh.boot.grpc.test.config.BaseAutoConfiguration;
import net.devh.boot.grpc.test.config.ServiceConfiguration;
import net.devh.boot.grpc.test.proto.SomeType;

/**
* These tests check the property {@link GrpcChannelProperties#getDeadline()}.
*/
public class DeadlineTests {
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved

@Slf4j
@SpringBootTest(properties = {
"grpc.client.GLOBAL.address=localhost:9090",
"grpc.client.GLOBAL.deadline=1s",
"grpc.client.GLOBAL.negotiationType=PLAINTEXT",
})
@SpringJUnitConfig(classes = {ServiceConfiguration.class, BaseAutoConfiguration.class})
static class DeadlineSetupTest extends AbstractSimpleServerClientTest {
@Test
@SneakyThrows
@DirtiesContext
void testServiceStubDeadlineEnabledAndSuccessful() {
log.info("--- Starting test with unsuccessful and than successful call ---");
final StreamRecorder<SomeType> streamRecorder1 = StreamRecorder.create();
StreamObserver<SomeType> echo1 = this.testServiceStub.echo(streamRecorder1);
assertThrows(ExecutionException.class, () -> streamRecorder1.firstValue().get());

final StreamRecorder<SomeType> streamRecorder2 = StreamRecorder.create();
StreamObserver<SomeType> echo2 = testServiceStub.echo(streamRecorder2);
echo2.onNext(SomeType.getDefaultInstance());
assertNull(streamRecorder2.getError());
assertNotNull(streamRecorder2.firstValue().get().getVersion());
log.info("--- Test completed --- ");
}
}

@Slf4j
@SpringBootTest(properties = {
"grpc.client.GLOBAL.address=localhost:9090",
"grpc.client.GLOBAL.deadline=0s",
"grpc.client.GLOBAL.negotiationType=PLAINTEXT",
})
@SpringJUnitConfig(classes = {ServiceConfiguration.class, BaseAutoConfiguration.class})
static class ZeroDeadlineSetupTest extends AbstractSimpleServerClientTest {
}

}
Loading