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.