Describe the bug I'm using Spring Boot 3.1.4 and Spring Cloud 2022.0.4.
I've configured Spring Cloud Config to use discovery-first. I've put the spring.config.import=configserver:
statement in a sub-document of application.properties, activated using spring.config.activate.on-profile=!noconfigserver
. I also have a some-profile
profile active.
When fetching the some-profile
config, the service discovery is used; however, it also fetches the non-profile-specific config without using service discovery. This fails.
Sample
application.properties:
spring.application.name=demo
spring.cloud.config.uri=http://not-discovery:8888/
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=configuration-service
eureka.client.service-url.default-zone=http://eurekahost:8761
spring.profiles.active=some-profile
#---
spring.config.activate.on-profile=!noconfigserver
spring.config.import=configserver:
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.1.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-config-discovery-first-bug</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-config-discovery-first-bug</name>
<description>Demo project for Spring Config bug</description>
<properties>
<java.version>21</java.version>
<spring-cloud.version>2022.0.4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
The following logs are from using a configuration server registered at 127.0.0.1, and adding a not-discovery
entry to my hosts file, also pointing at 127.0.0.1 (added for the sake of getting these logs):
2023-10-17T11:59:46.656+01:00 INFO 24856 --- [demo] [ main] SpringConfigDiscoveryFirstBugApplication : The following 1 profile is active: "some-profile"
2023-10-17T11:59:46.675+01:00 INFO 24856 --- [demo] [ main] o.s.c.c.c.ConfigServerConfigDataLoader : Fetching config from server at : http://127.0.0.1:8888/
2023-10-17T11:59:46.675+01:00 INFO 24856 --- [demo] [ main] o.s.c.c.c.ConfigServerConfigDataLoader : Located environment: name=demo, profiles=[some-profile], label=null, version=63f3e2b6bd303329ef841d18f99585a5dcef1449, state=null
2023-10-17T11:59:46.675+01:00 INFO 24856 --- [demo] [ main] o.s.c.c.c.ConfigServerConfigDataLoader : Fetching config from server at : http://not-discovery:8888/
2023-10-17T11:59:46.675+01:00 INFO 24856 --- [demo] [ main] o.s.c.c.c.ConfigServerConfigDataLoader : Located environment: name=demo, profiles=[default], label=null, version=63f3e2b6bd303329ef841d18f99585a5dcef1449, state=null
You can see that it fetches config for the default
profile being active from http://not-discovery:8888/
.
This does not happen without the spring.config.activate.on-profile
property. I think the issue is that the bootstrapConfigClientProperties in ConfigServerConfigDataLocationResolver.loadProperties have not been initialised by the ConfigServerInstanceMonitor yet when it comes to create the ConfigClientProperties
for the non-profile-specific import, because that only happens when the import is processed, and the import is not processed before profile activation.
Comment From: ryanjbaxter
I don't really understand why you have things configured this way.
You can't specify a URI and then use service discovery lookup, you need to choose one or the other.
Comment From: pmahony893
Agreed - the spring.cloud.config.uri
property has no place if we're using discovery-first. I only added it to make it really clear in the logs that it isn't using service discovery.
Without that property, everything is the same, except you see the default localhost
in the logs instead of not-discovery
, which is still wrong, but perhaps less obviously so, as the correct address retrieved using service discovery is 127.0.0.1
, as I am running everything locally.
I added that config hoping to make the behaviour more obvious, but it seems I ended up confusing matters - apologies!
Comment From: ryanjbaxter
Is there a reason why the spring.config.import
statement is in a document activated by a profile when its required to be set when using discovery first configuration?
Comment From: pmahony893
Sometimes I want my application to fetch config from config server (e.g. when deployed). Sometimes I don't (e.g. when developing locally). My aim is to be able to switch this on or off depending on whether a profile is activated.
With the above application.properties
file, if I activate the noconfigserver
profile, then config is not fetched from config server. So far, so good. When I don't activate that profile, it is fetched - but incorrectly, as it uses discovery inconsistently.
Comment From: ryanjbaxter
With the above application.properties file, if I activate the noconfigserver profile, then config is not fetched from config server. So far, so good. When I don't activate that profile, it is fetched - but incorrectly, as it uses discovery inconsistently.
Sorry but this doesn't seem to align with the sample applicaiton.properties you supplied. There is no noconfigserver
profile specific document, there is a document that is activated as long as the profile is not noconfigserver
and when that document is NOT activated the config server will fail to start because there is no spring.config.import
.
I think one possible solution to this situation is just have one document and change spring.config.import
to optional:configsever:
so that if the config server is not available the application does not fail to start.
Comment From: pmahony893
Apologies, I've gone through several iterations before creating an issue here, and I missed something in my initial post. The following document should also be in application.properties
. The service does not fail to start with the noconfigserver
profile active when this is present.
#---
spring.config.activate.on-profile=noconfigserver
spring.cloud.config.enabled=false
The point is that the configserver:
import is in a profile-specific document. To me, this doesn't seem such a strange thing to do. It's even in a suggestion given by a member of the Spring Cloud team here, to get different behaviours between profiles.
I don't want to use optional:
because when my application is deployed, it must fetch its config from configserver, otherwise it will be running with incorrect configuration. I want it to fail to start in this case.