Skip to content

Commit

Permalink
fix(core): remove circular reference from CanaryJudgeTask, CompareJud…
Browse files Browse the repository at this point in the history
…geResultsTask, MetricSetMixerServiceTask, MonitorCanaryTask and RunCanaryTask classes identified during upgrade to spring boot 2.6.x

While upgrading spring boot 2.6.15 and spring cloud 2021.0.8, encountered below errors in kayenta-integration-tests module during test execution and 8 tests failed with similar error:
```
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
	at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
	...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisOrcaQueueConfiguration': Unsatisfied dependency expressed through method 'redisQueueObjectMapper' parameter 2; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'taskResolver' defined in class path resource [com/netflix/spinnaker/orca/config/OrcaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.spinnaker.orca.TaskResolver]: Factory method 'taskResolver' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'canaryJudgeTask' defined in URL [jar:file:/kayenta/kayenta-core/build/libs/kayenta-core.jar!/com/netflix/kayenta/canary/orca/CanaryJudgeTask.class]: Unsatisfied dependency expressed through constructor parameter 4; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'executionMapper' defined in URL [jar:file:/kayenta/kayenta-core/build/libs/kayenta-core.jar!/com/netflix/kayenta/canary/ExecutionMapper.class]: Unsatisfied dependency expressed through constructor parameter 4; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'executionLauncher' defined in URL [jar:file:/.m2/repository/io/spinnaker/orca/orca-core/sc202108-sb2615-SNAPSHOT/orca-core-sc202108-sb2615-SNAPSHOT.jar!/com/netflix/spinnaker/orca/pipeline/ExecutionLauncher.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'queueExecutionRunner' defined in URL [jar:file:/.m2/repository/io/spinnaker/orca/orca-queue/sc202108-sb2615-SNAPSHOT/orca-queue-sc202108-sb2615-SNAPSHOT.jar!/com/netflix/spinnaker/orca/q/QueueExecutionRunner.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'redisOrcaQueueConfiguration': Requested bean is currently in creation: Is there an unresolvable circular reference?
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:768)
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:720)
	at app//org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)
	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at app//org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at app//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at app//org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at app//org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
	at app//org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:920)
	at app//org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
	at app//org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
	at app//org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
	at app//org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:423)
	at app//org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
	at app//org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:148)
	at app//org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:141)
	at app//org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:90)
	... 88 more
```
And the logs were showing below details about circular reference:
```
2024-02-16 23:00:59.572 ERROR 833552 --- [    Test worker] o.s.b.d.LoggingFailureAnalysisReporter   :

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

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  redisOrcaQueueConfiguration
↑     ↓
|  taskResolver defined in class path resource [com/netflix/spinnaker/orca/config/OrcaConfiguration.class]
↑     ↓
|  canaryJudgeTask defined in URL [jar:file:/kayenta/kayenta-core/build/libs/kayenta-core.jar!/com/netflix/kayenta/canary/orca/CanaryJudgeTask.class]
↑     ↓
|  executionMapper defined in URL [jar:file:/kayenta/kayenta-core/build/libs/kayenta-core.jar!/com/netflix/kayenta/canary/ExecutionMapper.class]
↑     ↓
|  executionLauncher defined in URL [jar:file:/.m2/repository/io/spinnaker/orca/orca-core/sc202108-sb2615-SNAPSHOT/orca-core-sc202108-sb2615-SNAPSHOT.jar!/com/netflix/spinnaker/orca/pipeline/ExecutionLauncher.class]
↑     ↓
|  queueExecutionRunner defined in URL [jar:file:/.m2/repository/io/spinnaker/orca/orca-queue/sc202108-sb2615-SNAPSHOT/orca-queue-sc202108-sb2615-SNAPSHOT.jar!/com/netflix/spinnaker/orca/q/QueueExecutionRunner.class]
└─────┘

Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

```
Similar errors were reported for CanaryJudgeTask, CompareJudgeResultsTask, MetricSetMixerServiceTask, MonitorCanaryTask and RunCanaryTask classes, until fixed for each one of them.
In order to fix the issue, deferred the initialization by using @lazy annotation for above mentioned classes.
  • Loading branch information
j-sandy committed Feb 20, 2024
1 parent c933f7f commit 1d73441
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Slf4j
Expand All @@ -48,6 +49,7 @@ public class CanaryJudgeTask implements RetryableTask {
private final ObjectMapper objectMapper;
private final ExecutionMapper executionMapper;

@Lazy
@Autowired
public CanaryJudgeTask(
AccountCredentialsRepository accountCredentialsRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Slf4j
Expand All @@ -45,6 +46,7 @@ public class CompareJudgeResultsTask implements RetryableTask {
private final ObjectMapper objectMapper;
private final ExecutionMapper executionMapper;

@Lazy
@Autowired
public CompareJudgeResultsTask(
AccountCredentialsRepository accountCredentialsRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
Expand All @@ -47,6 +48,7 @@ public class MetricSetMixerServiceTask implements RetryableTask {
private final MetricSetMixerService metricSetMixerService;
private final ExecutionMapper executionMapper;

@Lazy
@Autowired
public MetricSetMixerServiceTask(
AccountCredentialsRepository accountCredentialsRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
Expand All @@ -68,6 +69,7 @@ public class MonitorCanaryTask implements Task, OverridableTimeoutRetryableTask
private final AccountCredentialsRepository accountCredentialsRepository;
private final ExecutionMapper executionMapper;

@Lazy
@Autowired
public MonitorCanaryTask(
ExecutionRepository executionRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/** Orca Task that tells Kayenta to execute a canary analysis / judgement */
Expand All @@ -47,6 +48,7 @@ public class RunCanaryTask implements Task {
private final ExecutionMapper executionMapper;
private final ObjectMapper kayentaObjectMapper;

@Lazy
@Autowired
public RunCanaryTask(
AccountCredentialsRepository accountCredentialsRepository,
Expand Down

0 comments on commit 1d73441

Please sign in to comment.