When retry is enabled in the config client by putting spring-retry
on the classpath, and connecting to the config server finally fails, the ConfigClientFailFastException
is not directly thrown from ConfigServerConfigDataLoader
. Instead, an ApplicationListener
on BootstrapContextClosedEvent
is registered that adds the exception to the application context from which it is picked up later by the auto-configured ConfigClientFailFastListener
.
This has the disadvantage that the actual throwing of the exception and the resulting application failure occur quite late in the application start-up. For example, if a @Configuration
class depends on config values provided by the config server, the application likely fails with a BeanCreationException
before the ApplicationStartedEvent
is triggered that the ConfigClientFailFastListener
listens on.
While the application does ultimately fail as intended, it does not fail fast. In particular, the log is not as helpful as expected as the logged warnings and errors do not refer to the effectively swallowed ConfigClientFailFastException
.
I have implemented a minimal example here: https://github.com/hpoettker/scc-sample
It contains the following class which provides a MessageProvider
which is just a dummy class:
@Configuration
public class ClientConfiguration {
@Value("${client.config.foo}")
private String message;
@Bean
public MessageProvider messageProvider() {
return new MessageProvider(message);
}
}
When the applications starts without a running config server, it will fail with the (abbreviated) log:
WARN 86577 --- [main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'client.config.foo' in value "${client.config.foo}"
ERROR 86577 --- [main] o.s.boot.SpringApplication : Application run failed
If spring-retry
is removed from the classpath, the following much more helpful log is provided:
[main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.cloud.config.client.ConfigClientFailFastException: Could not locate PropertySource and the resource is not optional, failing
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:193)
...
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8888/client/default": Connection refused; nested exception is java.net.ConnectException: Connection refused
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785)
...
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.pollConnect(Native Method)
...
Please consider to throw the ConfigClientFailFastException
earlier during start-up also with retry enabled to let the log clearly indicate when the config server could not be reached.
Comment From: dcheung2
I come across this commit which may be related. https://github.com/spring-cloud/spring-cloud-config/commit/e9fa34032b67301831dfe73882bb61b1b2330d43
However, make the spring.cloud.config.fail-fast=true
fail too late. That the spring still attempt to boot and may have started other component (e.g. tomcat / kafka client) before ConfigClientFailFastListener stop it.
ConfigClientFailFastListener is a POST started event. As a developer, I expect fail-fast mean to fail spring boot ASAP.