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 (#1022)

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 authored Feb 20, 2024
1 parent c933f7f commit 8c30e06
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 8c30e06

Please sign in to comment.