Skip to content

Commit 5805901

Browse files
Бацура Сергей АлександровичБацура Сергей Александрович
Бацура Сергей Александрович
authored and
Бацура Сергей Александрович
committed
Feat(deadline) add deadline property for client
1 parent a18aeeb commit 5805901

File tree

6 files changed

+252
-1
lines changed

6 files changed

+252
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.devh.boot.grpc.client.autoconfigure;
18+
19+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.context.annotation.Configuration;
22+
23+
import io.grpc.stub.AbstractStub;
24+
import lombok.extern.slf4j.Slf4j;
25+
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
26+
import net.devh.boot.grpc.client.deadline.DeadlineHelper;
27+
import net.devh.boot.grpc.client.inject.StubTransformer;
28+
29+
/**
30+
* The deadline auto configuration for the client.
31+
*
32+
* <p>
33+
* You can disable this config by using:
34+
* </p>
35+
*
36+
* <pre>
37+
* <code>@ImportAutoConfiguration(exclude = GrpcClientDeadlineAutoConfiguration.class)</code>
38+
* </pre>
39+
*
40+
* @author Sergei Batsura ([email protected])
41+
*/
42+
@Slf4j
43+
@Configuration(proxyBeanMethods = false)
44+
@AutoConfigureBefore(GrpcClientAutoConfiguration.class)
45+
public class GrpcClientDeadlineAutoConfiguration {
46+
47+
/**
48+
* Creates a {@link StubTransformer} bean that will add the call credentials to the created stubs.
49+
*
50+
* @param props The properties for deadline configuration.
51+
* @return The StubTransformer bean that will add the deadline from properties.
52+
* @see DeadlineHelper#deadlineStubTransformer(GrpcChannelsProperties)
53+
* @see AbstractStub#withDeadline(io.grpc.Deadline)
54+
*/
55+
@Bean
56+
StubTransformer deadlineStubTransformer(final GrpcChannelsProperties props) {
57+
return DeadlineHelper.deadlineStubTransformer(props);
58+
}
59+
60+
}

grpc-client-spring-boot-starter/src/main/java/net/devh/boot/grpc/client/config/GrpcChannelProperties.java

+30
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,33 @@
5353
@EqualsAndHashCode
5454
public class GrpcChannelProperties {
5555

56+
// --------------------------------------------------
57+
// Target Deadline
58+
// --------------------------------------------------
59+
60+
private Duration deadline = null;
61+
62+
/**
63+
* Gets the connection deadline.
64+
*
65+
* @return The connection deadline or null
66+
* @see #setDeadline(Duration)
67+
*/
68+
public Duration getDeadline() {
69+
return this.deadline;
70+
}
71+
72+
/**
73+
* Set the deadline for the stub. If nothing is configured then the deadline will not be used by default
74+
*
75+
* @param deadline The connection deadline or null.
76+
*
77+
* @see #setDeadline(Duration)
78+
*/
79+
public void setDeadline(Duration deadline) {
80+
this.deadline = deadline;
81+
}
82+
5683
// --------------------------------------------------
5784
// Target Address
5885
// --------------------------------------------------
@@ -477,6 +504,9 @@ public void copyDefaultsFrom(final GrpcChannelProperties config) {
477504
if (this == config) {
478505
return;
479506
}
507+
if (this.deadline == null) {
508+
this.deadline = config.deadline;
509+
}
480510
if (this.address == null) {
481511
this.address = config.address;
482512
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.devh.boot.grpc.client.deadline;
18+
19+
import static java.util.Objects.requireNonNull;
20+
21+
import java.util.concurrent.TimeUnit;
22+
23+
import io.grpc.Deadline;
24+
import io.grpc.stub.AbstractStub;
25+
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
26+
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
27+
import net.devh.boot.grpc.client.inject.StubTransformer;
28+
29+
public class DeadlineHelper {
30+
31+
/**
32+
* Creates a new {@link StubTransformer} that will assign the given deadline to the given {@link AbstractStub}.
33+
*
34+
* @param props The properties to assign the deadline.
35+
* @return The transformed stub.
36+
* @see AbstractStub#withDeadline(Deadline)
37+
*/
38+
public static StubTransformer deadlineStubTransformer(final GrpcChannelsProperties props) {
39+
requireNonNull(props, "properties");
40+
41+
return (name, stub) -> {
42+
GrpcChannelProperties channelProps = props.getChannel(name);
43+
if (channelProps != null && channelProps.getDeadline() != null) {
44+
return stub.withDeadline(Deadline.after(channelProps.getDeadline().toMillis(), TimeUnit.MILLISECONDS));
45+
} else {
46+
return stub;
47+
}
48+
};
49+
}
50+
51+
private DeadlineHelper() {}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Contains classes and utilities that help with the deadline.
3+
*/
4+
5+
package net.devh.boot.grpc.client.deadline;

tests/src/test/java/net/devh/boot/grpc/test/config/BaseAutoConfiguration.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.springframework.context.annotation.Configuration;
2121

2222
import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
23+
import net.devh.boot.grpc.client.autoconfigure.GrpcClientDeadlineAutoConfiguration;
2324
import net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration;
2425
import net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;
2526
import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration;
@@ -28,7 +29,7 @@
2829
@Configuration
2930
@ImportAutoConfiguration({GrpcCommonCodecAutoConfiguration.class, GrpcServerAutoConfiguration.class,
3031
GrpcServerFactoryAutoConfiguration.class, GrpcServerSecurityAutoConfiguration.class,
31-
GrpcClientAutoConfiguration.class})
32+
GrpcClientAutoConfiguration.class, GrpcClientDeadlineAutoConfiguration.class})
3233
public class BaseAutoConfiguration {
3334

3435
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package net.devh.boot.grpc.test.setup;
18+
19+
import static io.grpc.Status.DEADLINE_EXCEEDED;
20+
import static net.devh.boot.grpc.test.util.GrpcAssertions.assertStatus;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.junit.jupiter.api.Assertions.assertNotNull;
23+
import static org.junit.jupiter.api.Assertions.assertThrows;
24+
25+
import java.util.concurrent.ExecutionException;
26+
27+
import org.junit.jupiter.api.Test;
28+
import org.springframework.boot.test.context.SpringBootTest;
29+
import org.springframework.test.annotation.DirtiesContext;
30+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
31+
32+
import com.google.protobuf.Empty;
33+
34+
import io.grpc.Channel;
35+
import io.grpc.StatusRuntimeException;
36+
import io.grpc.internal.testing.StreamRecorder;
37+
import lombok.extern.slf4j.Slf4j;
38+
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
39+
import net.devh.boot.grpc.client.inject.GrpcClient;
40+
import net.devh.boot.grpc.test.config.BaseAutoConfiguration;
41+
import net.devh.boot.grpc.test.config.ServiceConfiguration;
42+
import net.devh.boot.grpc.test.proto.SomeType;
43+
import net.devh.boot.grpc.test.proto.TestServiceGrpc;
44+
45+
/**
46+
* These tests check the property {@link GrpcChannelProperties#getDeadline()}.
47+
*/
48+
public class DeadlineTests {
49+
50+
@Slf4j
51+
@SpringBootTest(properties = {
52+
"grpc.client.GLOBAL.address=localhost:9090",
53+
"grpc.client.GLOBAL.deadline=10s",
54+
"grpc.client.GLOBAL.negotiationType=PLAINTEXT",
55+
})
56+
@SpringJUnitConfig(classes = {ServiceConfiguration.class, BaseAutoConfiguration.class})
57+
@DirtiesContext
58+
static class SuccessfullyDeadlineTests extends AbstractSimpleServerClientTest {
59+
}
60+
61+
@Slf4j
62+
@SpringBootTest(properties = {
63+
"grpc.client.GLOBAL.address=localhost:9090",
64+
"grpc.client.GLOBAL.deadline=0s",
65+
"grpc.client.GLOBAL.negotiationType=PLAINTEXT",
66+
})
67+
@SpringJUnitConfig(classes = {ServiceConfiguration.class, BaseAutoConfiguration.class})
68+
@DirtiesContext
69+
static class UnsuccessfullyDeadlineTests {
70+
71+
@GrpcClient("test")
72+
protected Channel channel;
73+
@GrpcClient("test")
74+
protected TestServiceGrpc.TestServiceStub testServiceStub;
75+
@GrpcClient("test")
76+
protected TestServiceGrpc.TestServiceBlockingStub testServiceBlockingStub;
77+
@GrpcClient("test")
78+
protected TestServiceGrpc.TestServiceFutureStub testServiceFutureStub;
79+
80+
UnsuccessfullyDeadlineTests() {
81+
log.info("--- UnsuccessfullyDeadlineTests ---");
82+
}
83+
84+
@Test
85+
@DirtiesContext
86+
void testServiceStubDeadlineEnabledAndUnsuccessful() {
87+
log.info("--- Starting tests with successful call ---");
88+
final StreamRecorder<SomeType> streamRecorder = StreamRecorder.create();
89+
this.testServiceStub.normal(Empty.getDefaultInstance(), streamRecorder);
90+
91+
assertThrows(ExecutionException.class, () -> streamRecorder.firstValue().get().getVersion());
92+
assertNotNull(streamRecorder.getError());
93+
assertEquals(StatusRuntimeException.class, streamRecorder.getError().getClass());
94+
assertStatus(DEADLINE_EXCEEDED.getCode(), (StatusRuntimeException) streamRecorder.getError());
95+
assertStatus(DEADLINE_EXCEEDED.getCode(),
96+
assertThrows(StatusRuntimeException.class,
97+
() -> testServiceBlockingStub.normal(Empty.getDefaultInstance())));
98+
assertThrows(ExecutionException.class,
99+
() -> testServiceFutureStub.normal(Empty.getDefaultInstance()).get());
100+
log.info("--- Test completed ---");
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)