Skip to content

Commit 5e0e110

Browse files
committed
feat(springboot openfeign): An OpenFeign Client for Dapr Invokes
A OpenFeign Client and it's AutoConfiguration using Dapr Invoke APIs. Splited into two librarys, dapr-openfeign-client is the pure client of OpenFeign, and dapr-spring-openfeign is the plugin of Spring Cloud OpenFeign. Currently only HTTP Invoke Method and Invoke Binding supported, and Invoke Binding is not always recommend to use this client, depends on what binding component is. Signed-off-by: lony2003 <zhangke200377@outlook.com>
1 parent 790e502 commit 5e0e110

File tree

5 files changed

+80
-15
lines changed

5 files changed

+80
-15
lines changed

dapr-spring/dapr-openfeign-client/src/main/java/io/dapr/feign/DaprInvokeFeignClient.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,23 @@ private Map<String, String> toHeader(Map<String, Collection<String>> header) {
332332
}
333333

334334
private Response.Body toResponseBody(Mono<byte[]> response, Request.Options options) throws IOException {
335-
byte[] result;
335+
byte[] result = new byte[0];
336336

337-
try {
338-
result = response.retry(retry).block(Duration.of(timeout,
339-
TimeUnit.MILLISECONDS.toChronoUnit()));
337+
for (int count = 0; count < retry; count++) {
338+
try {
339+
result = response.block(Duration.of(timeout,
340+
TimeUnit.MILLISECONDS.toChronoUnit()));
340341

341-
if (result == null) {
342-
result = new byte[0];
343-
}
342+
if (result == null) {
343+
result = new byte[0];
344+
}
344345

345-
} catch (RuntimeException e) {
346-
throw new IOException("Can not get Response", e);
346+
break;
347+
} catch (RuntimeException e) {
348+
if (retry == count + 1) {
349+
throw new IOException("Can not get Response", e);
350+
}
351+
}
347352
}
348353

349354

sdk-tests/src/test/java/io/dapr/it/spring/feign/DaprFeignIT.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package io.dapr.it.spring.feign;
22

3+
import io.dapr.client.DaprClient;
4+
import io.dapr.client.domain.HttpExtension;
35
import io.dapr.testcontainers.Component;
46
import io.dapr.testcontainers.DaprContainer;
57
import io.dapr.testcontainers.DaprLogLevel;
8+
import io.dapr.utils.TypeRef;
9+
import org.junit.jupiter.api.BeforeAll;
10+
import org.junit.jupiter.api.BeforeEach;
611
import org.junit.jupiter.api.Tag;
712
import org.junit.jupiter.api.Test;
813
import org.junit.jupiter.api.extension.ExtendWith;
@@ -12,18 +17,29 @@
1217
import org.springframework.test.context.junit.jupiter.SpringExtension;
1318
import org.testcontainers.containers.Network;
1419
import org.testcontainers.containers.PostgreSQLContainer;
20+
import org.testcontainers.containers.wait.strategy.Wait;
1521
import org.testcontainers.junit.jupiter.Container;
1622
import org.testcontainers.junit.jupiter.Testcontainers;
1723

24+
import java.util.Arrays;
25+
import java.util.Collections;
1826
import java.util.HashMap;
1927
import java.util.Map;
2028

2129
import static io.dapr.it.spring.data.DaprSpringDataConstants.STATE_STORE_NAME;
2230
import static io.dapr.it.testcontainers.DaprContainerConstants.IMAGE_TAG;
2331
import static org.junit.jupiter.api.Assertions.assertEquals;
2432

25-
@ExtendWith(SpringExtension.class)
26-
@SpringBootTest(properties = {"dapr.feign.enable=true"})
33+
@SpringBootTest(
34+
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
35+
classes = {
36+
DaprFeignTestApplication.class
37+
},
38+
properties = {
39+
"dapr.feign.enabled=true",
40+
"dapr.feign.retries=1"
41+
}
42+
)
2743
@Testcontainers
2844
@Tag("testcontainers")
2945
public class DaprFeignIT {
@@ -36,6 +52,9 @@ public class DaprFeignIT {
3652

3753
public static final String BINDING_NAME = "postgresbinding";
3854

55+
private static final int APP_PORT = 8080;
56+
private static final String SUBSCRIPTION_MESSAGE_PATTERN = ".*app is subscribed to the following topics.*";
57+
3958
@Container
4059
private static final PostgreSQLContainer<?> POSTGRE_SQL_CONTAINER = new PostgreSQLContainer<>("postgres:16-alpine")
4160
.withNetworkAliases("postgres-repository")
@@ -49,11 +68,26 @@ public class DaprFeignIT {
4968
private static final DaprContainer DAPR_CONTAINER = new DaprContainer(IMAGE_TAG)
5069
.withAppName("dapr-feign-test")
5170
.withNetwork(DAPR_NETWORK)
71+
.withComponent(new Component("pubsub", "pubsub.in-memory", "v1", Collections.emptyMap()))
5272
.withComponent(new Component(BINDING_NAME, "bindings.postgresql", "v1", BINDING_PROPERTIES))
5373
.withDaprLogLevel(DaprLogLevel.DEBUG)
74+
.withAppPort(APP_PORT)
75+
.withAppHealthCheckPath("/ready")
76+
.withAppChannelAddress("host.testcontainers.internal")
5477
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
5578
.dependsOn(POSTGRE_SQL_CONTAINER);
5679

80+
@BeforeAll
81+
public static void beforeAll(){
82+
org.testcontainers.Testcontainers.exposeHostPorts(APP_PORT);
83+
}
84+
85+
@BeforeEach
86+
public void beforeEach() {
87+
// Ensure the subscriptions are registered
88+
Wait.forLogMessage(SUBSCRIPTION_MESSAGE_PATTERN, 1).waitUntilReady(DAPR_CONTAINER);
89+
}
90+
5791
@Autowired
5892
PostgreBindingClient postgreBindingClient;
5993

@@ -66,9 +100,18 @@ public void invokeBindingTest() {
66100
}
67101

68102
@Test
69-
public void invokeMethodTest() {
103+
public void invokeSimpleGetMethodTest() {
70104
assertEquals("hello", testMethodClient.hello());
105+
}
106+
107+
@Test
108+
public void invokeSimplePostMethodTest() {
71109
assertEquals("hello", testMethodClient.echo("hello"));
72110
}
73111

112+
@Test
113+
public void invokeJsonMethodTest() {
114+
assertEquals("hello", testMethodClient.echoJson("hello").getMessage());
115+
}
116+
74117
}

sdk-tests/src/test/java/io/dapr/it/spring/feign/Result.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
package io.dapr.it.spring.feign;
22

33
public class Result {
4-
private final String message;
4+
private String message;
5+
6+
public Result() {}
57

68
public Result(String message) {
79
this.message = message;
810
}
911

12+
public void setMessage(String message) {
13+
this.message = message;
14+
}
15+
1016
public String getMessage() {
1117
return message;
1218
}

sdk-tests/src/test/java/io/dapr/it/spring/feign/TestMethodClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.dapr.it.spring.feign;
22

3+
import io.dapr.Topic;
34
import io.dapr.spring.openfeign.annotation.UseDaprClient;
45
import org.springframework.cloud.openfeign.FeignClient;
56
import org.springframework.web.bind.annotation.GetMapping;
@@ -10,13 +11,13 @@
1011
@UseDaprClient
1112
public interface TestMethodClient {
1213

13-
@GetMapping("/hello")
14+
@GetMapping(value = "/hello")
1415
String hello();
1516

1617
@PostMapping("/echo")
1718
String echo(@RequestBody String input);
1819

19-
@PostMapping(value = "/echoj", consumes = "text/plain", produces = "application/json")
20+
@PostMapping(value = "/echoj", produces = "application/json;charset=utf-8")
2021
Result echoJson(@RequestBody String input);
2122

2223
}

sdk-tests/src/test/java/io/dapr/it/spring/feign/TestRestController.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.dapr.it.spring.feign;
22

3+
import io.dapr.Topic;
34
import org.springframework.web.bind.annotation.GetMapping;
45
import org.springframework.web.bind.annotation.PostMapping;
56
import org.springframework.web.bind.annotation.RequestBody;
@@ -8,11 +9,20 @@
89
@RestController
910
public class TestRestController {
1011

12+
public static final String pubSubName = "pubsub";
13+
public static final String topicName = "mockTopic";
14+
15+
@GetMapping("/ready")
16+
public String ok() {
17+
return "OK";
18+
}
19+
1120
@GetMapping("/hello")
1221
public String hello() {
1322
return "hello";
1423
}
1524

25+
@Topic(name = topicName, pubsubName = pubSubName)
1626
@PostMapping("/echo")
1727
public String echo(@RequestBody String input) {
1828
return input;

0 commit comments

Comments
 (0)