I'm trying to setup a timeout to my feign clients when they try to access to other of my services. In order to test my circuit breaker method. This is my basic setup. I'm using spring-boot 3.0.2 and spring cloud version 2022.0.1
I have a edge-service project this is the pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>e-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>e-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>netflix-candidates</id>
<name>Netflix Candidates</name>
<url>https://artifactory-oss.prod.netflix.net/artifactory/maven-oss-candidates</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
As you can see I have the spring-cloud-starter-openfeign dependency
This is my configuration in the application.properties
spring.application.name=edge-service
server.port=8080
feign.client.config.default.readTimeout=2000
Using this property feign.client.config.default.readTimeout=2000
it should be enough to set my readTimeout to 2 seconds. But for some reason is not working.
In my service where I'm calling to my FeignClient (ProxyServiceClient)
@Service
public class MovieServiceImpl implements MovieService {
private final Logger logger = LoggerFactory.getLogger(MovieServiceImpl.class);
@Autowired
private ProxyServiceClient proxyServiceClient;
@CircuitBreaker(name = "findHorroMovies", fallbackMethod = "findHorrorMoviesFallback")
public ResponseDTO findAllHorroMovies() {
ResponseDTO responseDTO = new ResponseDTO();
List<MovieCatalogDTO> horroMovies = proxyServiceClient.findByGenre(Genre.HORROR);
responseDTO.setMovieCatalogs(horroMovies);
responseDTO.setMessage("Buuuuuhhhh");
responseDTO.setSize(horroMovies.size());
return responseDTO;
}
public ResponseDTO findHorrorMoviesFallback(Exception e) {
logger.error(e.getMessage());
ResponseDTO responseDTO = new ResponseDTO();
List<MovieCatalogDTO> movieCatalogs = new ArrayList<>();
responseDTO.setMovieCatalogs(movieCatalogs);
responseDTO.setSize(0);
responseDTO.setMessage("Buuuuuhhh (cached)");
return responseDTO;
}
}
And in my ProxyService I'm setting a sleep time of 3 seconds to trigger the timeout in every request
@RestController
public class MovieCatalogControllerImpl implements MovieCatalogController {
@Autowired
private MovieCatalogService movieCatalogService;
@GetMapping("/movie-catalog")
public List<MovieCatalog> findByGenre(@RequestParam Optional<Genre> genre) throws InterruptedException {
Thread.sleep(3000);
if(genre.isPresent()) {
return movieCatalogService.findByGenre(genre.get());
}
return movieCatalogService.findAll();
}
}
I'm doing some tests but it keeps taking more than 2 seconds without closing the connection. I don't know what could I been doing wrong. Hope you can help me.
I tried to add in my application.properties file the property
feign.client.config.default.readTimeout=2000
to set the readTimeout in 2 seconds, but is not working...I don't know if it has to be something with the version of spring-boot or spring-cloud. Because I remember this approach used to work in older projects.
Okay, I found the solution. In the openfeign document there is an explanation where the default configuration in the application.properties has been changed
spring:
cloud:
openfeign:
client:
config:
feignName:
url: http://remote-service.com
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
defaultQueryParameters:
query: queryValue
defaultRequestHeaders:
header: headerValue
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
responseInterceptor: com.example.BazResponseInterceptor
dismiss404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
capabilities:
- com.example.FooCapability
- com.example.BarCapability
queryMapEncoder: com.example.SimpleQueryMapEncoder
micrometer.enabled: false
So I had to update this property
spring.cloud.openfeign.client.config.default.readTimeout=2000
instead of this
feign.client.config.default.readTimeout=2000
And that was the solution. I hope it can be helpful to someone facing the same problem as me :D.