Describe the bug
I'm trying to upgrade an spring boot/spring cloud config application to spring boot 2.4.2 and spring cloud 2020.0.1 to use the new spring.config.import property but having problem with the spring cloud config client configuration in combination with spring retry when the configuration is located in an profile-specific property file.
The application have the following two property files:
application.properties:
spring.config.import=optional:configserver:http://localhost:8888
application-fail.properties:
spring.config.import=configserver:http://localhost:8888
spring.cloud.config.fail-fast=true
spring.cloud.config.retry.max-attempts=15
When running without a spring config server., I'm observing the following behaviors:
When starting with the default profile, the application starts as expected with a log message like: Connect Timeout Exception on Url - http://localhost:8888. Will be trying the next url if available
When running with SPRING_PROFILES_ACTIVE=fail, the application terminates directly at startup with:
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:150)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:86)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:59)
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:102)
If the config in application-fail.properties is moved to application.properties, the application waits for the retry max-attempts before terminating as expected with:
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:150)
at org.springframework.cloud.config.client.ConfigClientRetryBootstrapper.lambda$null$2(ConfigClientRetryBootstrapper.java:58)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:209)
at org.springframework.cloud.config.client.ConfigClientRetryBootstrapper.lambda$null$3(ConfigClientRetryBootstrapper.java:57)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:83)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:59)
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:102)
Note the absence of org.springframework.retry.support.RetryTemplate in the first stack trace snippet.
Sample
I generated a spring initializer project with the above configuration that illustrate the behavior described above. It's available at https://github.com/perlan/config-retry
Comment From: kobynet
This probably relates to https://github.com/spring-cloud/spring-cloud-config/issues/1795
Comment From: v1nc3n4
Hi everyone, Just to add that the documentation is a bit ambiguous about the fail-fast and retry mechanisms.
- https://docs.spring.io/spring-cloud-config/docs/3.0.2/reference/html/#config-client-fail-fast
Documentation states omitting the optional:
prefix in the spring.config.import
property has a "similar functionality" than setting the spring.cloud.config.fail-fast
property to true
.
- https://docs.spring.io/spring-cloud-config/docs/3.0.2/reference/html/#config-client-retry
The section mentions the spring.cloud.config.fail-fast
property must be true
. But when reading the previous section, I personnally understood the spring.config.import
property without optional:
prefix was equivalent.
So my question is: are both properties really equivalent (what does mean "similar functionality")? It seems no despite the first section says the opposite. Feel free to correct me if I'm misunderstanding things. BR
Comment From: spencergibb
@v1nc3n4 Thanks for the detailed explanation. I'm not exactly sure how to handle this one. I'll add it to the list to chat with @philwebb about.
Comment From: spencergibb
A reminder that spring.config.import
doesn't behave like normal spring properties. All of them are processed by the boot config data infrastructure. One import in a profile-specific config file will not overwrite the one in the default file. With this behavior, the one in the default profile creates the object which holds the retry logic, but it doesn't have the fail fast property and hence no retry.
We can do two things on our side:
1- change how the retry it constructed so that the retry object isn't cached
2- allow properties like fail-fast
properties in the import statement spring.config.import=configserver:localhost:8888?fail-fast=true
and that wouldn't have the problems.
The second option is relatively simple and won't require and breaking API changes like the first option.
Comment From: hendisantika
I am trying to use: spring.config.import=optional:configserver:http://localhost:8888
.
But I have error:
Unable to load config data from 'optional:configserver:http://localhost:8888' at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences
Caused by: java.lang.IllegalStateException: File extension is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/'
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferencesForFile
Any idea? Thanks
Comment From: philwebb
@hendisantika That looks like you're either missing the Spring Cloud Config dependency or you have an old version.
Comment From: hendisantika
Hi @philwebb, no I am using the latest version which is 2020.0.2.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hendisantika.microservices</groupId>
<artifactId>config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Config Server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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>
</project>
Comment From: spencergibb
@hendisantika spring-cloud-starter-config not spring-cloud-config-server
Comment From: hendisantika
Hi @spencergibb , If I change into that lib the service won't come up.
Here the repo to reproduce the issue --> https://gitlab.com/microservice-samples/micro-services-spring-cloud-config/config-server
Thanks
Comment From: spencergibb
@hendisantika your issue is unrelated to this one. Please open a new issue
Comment From: hendisantika
OK.
Comment From: spencergibb
this will work in application-<profile>.{properties|yaml}
spring.config.import=configserver:http://configserver.example.com?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"
Comment From: hendisantika
I try like @spencergibb said:
spring.config.import=optional:configserver:http://localhost:8888?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"
But still error:
05:48:18.972 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Unable to load config data from 'optional:configserver:http://localhost:8888?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"'
Repo sample: https://gitlab.com/microservice-samples/micro-services-spring-cloud-config/config-server
Thanks
Comment From: spencergibb
@hendisantika it's not in 2020.0.2. It is in 2020.0.3-SNAPSHOT. 2020.0.3 will be released in the next day or two
Comment From: hendisantika
Still the same if I change into 2020.0.3-SNAPSHOT version.
Comment From: spencergibb
it's only for the client, not config server
Comment From: hendisantika
OIC. it's only for the client, not config server. OK Then. I though that is applicable for config server also.
But I try with client it's not working also:
06:55:49.980 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Unable to load config data from 'optional:configserver:http://localhost:8888?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"'
Here's the sample: https://gitlab.com/microservice-samples/micro-services-spring-cloud-config/bank-account-service
Comment From: BenTels
Is this definitely fixed? Because I am trying to use 2020.0.3 (so client 3.0.4), I have this configuration
spring: application: name: test-app cloud: config: fail-fast: true # retry: # max-attempts: 100 # multiplier: 1.1 # initial-interval: 10000 # uri: # - configserver:http://configserver:8088/ config: import: - configserver:http://localhost:8088/?fail-fast=true&max-attempts=100&max-interval=15000&multiplier=1.2&initial-interval=1100
and it is clearly not retrying....
Comment From: spencergibb
@BenTels yes. Please open a new issue with a sample. If you'd like us to spend some time investigating, please take the time to provide a complete, minimal, verifiable sample (something that we can unzip attached to the new issue or git clone, build, and deploy) that reproduces the problem.
Comment From: BenTels
@spencergibb
Hi. Thanks for responding.
If you'd like us to spend some time investigating, please take the time to provide [...]
I was working on an example for you, but it led me to the answer. I started out my PoC project (the one that was giving me problems) with the example from the centralized configuration guide for Spring Cloud Config Server. This is based on Spring Boot 2.4.3 . Turns out that something in Spring Cloud 2020.0.3 doesn't like Spring Boot 2.4.3 or the other way around, because upgrading to the parent pom for Boot 2.4.9 made the problem go away.
I don't expect a huge number of problems for you guys from this since Initialzr no longer offers Boot 2.4.3 as an option online (don't know about the CLI). But it might still be a good idea if someone updated the examples/guides like this one for example:
Comment From: spencergibb
Yes, a fix was required in boot 2.4.9