spring-cloud-kubernetes: A component required a bean named 'kubernetesConfigRetryInterceptor' that could not be found

Hi, I’m upgrading Spring Cloud from 2020.0.1 to 2021.0.0 and hit the following error when starting up the application.

Any idea what could have gone wrong?

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean named 'kubernetesConfigRetryInterceptor' that could not be found.


Action:

Consider defining a bean named 'kubernetesConfigRetryInterceptor' in your configuration.

I am using spring-cloud-starter-kubernetes-fabric8-all dependency and below is the sample configuration I have in bootstrap.properties (yes, it is using spring-cloud-starter-bootstrap).

spring.cloud.kubernetes.enabled=true
spring.cloud.kubernetes.discovery.enabled=true
spring.cloud.kubernetes.config.enabled=true
spring.cloud.kubernetes.config.sources[0].name=configmap1
spring.cloud.kubernetes.config.sources[0].namespace=dev
spring.cloud.kubernetes.config.sources[1].name=configmap2
spring.cloud.kubernetes.config.sources[1].namespace=dev

spring.cloud.kubernetes.reload.enabled=true
spring.cloud.kubernetes.reload.strategy=restart_context
spring.cloud.kubernetes.reload.monitoring-config-maps=false
spring.cloud.kubernetes.reload.mode=event

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 17 (14 by maintainers)

Commits related to this issue

Most upvoted comments

massive thank you for the sample! It is exactly what I had a hint for, initially.

There are a series of events that you got stuck into, I’ll try to explain.

So, the way we implement retry is via spring-retry, which in turn (simplified) is enabled via two annotations: @Retryable and @EnableRetry. In our kubernetes project we have a method (simplified again) like this:

@Retryable(interceptor="kubernetesConfigRetryInterceptor")
public PropertySource<?> locate(....) {....}

and there is a configuration that will provide @EnableRetry (I’ve only showed the relevant parts here):

@ConditionalOnKubernetesConfigOrSecretsRetryEnabled
@EnableRetry(proxyTargetClass = true)
static class RetryConfiguration {
      		@Bean("kubernetesConfigRetryInterceptor")
		public RetryOperationsInterceptor kubernetesConfigRetryInterceptorNoRetry() {
			return .....
		}
}

In plain english we say : you want retry enabled? Sure, please provide some flags (for the @ConditionalOnKubernetesConfigOrSecretsRetryEnabled annotation that is).

So we are “protected”: unless users request retry on demand (documentation has a lot more details) - we are good.


But, you bring consul into the dependencies 😃 and it messes this logic via its ConsulAutoConfiguration.RetryConfiguration. Notice that it also has @ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class }) and these dependencies are brought in transitively by spring-boot-starter-batch and spring-boot-starter-aop. Kind of crazy how the stars have aligned here, I admit.

Because it has this property : @ConditionalOnProperty(value = "spring.cloud.consul.retry.enabled", matchIfMissing = true), @EnableRetry happens, without our @ConditionalOnKubernetesConfigOrSecretsRetryEnabled being enable.

So we reach @Retryable(interceptor="kubernetesConfigRetryInterceptor") (remember that @EnableRetry has kicked in also), we need a kubernetesConfigRetryInterceptor bean, but because @ConditionalOnKubernetesConfigOrSecretsRetryEnabled is not active, the config that is supposed to provide that bean is not active either and voilà! Exception when starting the context.


The fact that you set spring.cloud.kubernetes.config.fail-fast=true means that you activate our config… and it works; though I do not quite agree that this is the correct solution. The correct solution is : “it depends” 😃

  • If you do not want retry on the consul side, put this spring.cloud.consul.retry.enabled=false in bootstrap.properties of your project. Though, I am kind of inclined to say that this is a bug in consul - do they really want to provide retry enabled by default? I would argue that this : @ConditionalOnProperty(value = "spring.cloud.consul.retry.enabled", matchIfMissing = true) should really be @ConditionalOnProperty(value = "spring.cloud.consul.retry.enabled") may be? Hard to say…

  • if you do want consul to retry, but you do not want spring kubernetes to retry, you should be adding two properties: spring.cloud.kubernetes.config.fail-fast=true and spring.cloud.kubernetes.config.retry.enabled=false.

  • if you want retry in both consul and kubernetes: spring.cloud.kubernetes.config.fail-fast=true and spring.cloud.kubernetes.config.retry.enabled=true - but this one is implicit.

@ryanjbaxter in the meanwhile - wdyt about consul config with auto-enabled retry?

@wind57: Here you go, https://github.com/vxavictor513/spring-cloud-kubernetes-issue-963-demo

Hope this helps. Let me know if anything else I can assist. 😃