Giter VIP home page Giter VIP logo

Comments (6)

cppwfs avatar cppwfs commented on September 22, 2024 1

@hpoettker Thank you for the fantastic writeup. I'll work with the boot team on this issue. In the meantime I'll bump TaskRepositoryDatabaseInitializerDetector up by one until they resolve the issue.

from spring-cloud-task.

hpoettker avatar hpoettker commented on September 22, 2024

For reference, the log to the issue is the following:

WARN  --- [main] o.s.c.support.GenericApplicationContext  : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.cloud.task.configuration.TaskLifecycleConfiguration': Unsatisfied dependency expressed through constructor parameter 2: Error creating bean with name 'taskRepositoryInitializer': Circular depends-on relationship between 'taskRepositoryInitializer' and 'dataSourceScriptDatabaseInitializer'
ERROR --- [main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.cloud.task.configuration.TaskLifecycleConfiguration': Unsatisfied dependency expressed through constructor parameter 2: Error creating bean with name 'taskRepositoryInitializer': Circular depends-on relationship between 'taskRepositoryInitializer' and 'dataSourceScriptDatabaseInitializer'
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[timestamp-task:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[timestamp-task:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[timestamp-task:6.0.2]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[timestamp-task:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[timestamp-task:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[timestamp-task:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[timestamp-task:3.0.0-SNAPSHOT]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[timestamp-task:3.0.0-SNAPSHOT]
        at org.springframework.cloud.task.timestamp.TaskApplication.main(TaskApplication.java:45) ~[timestamp-task:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'taskRepositoryInitializer': Circular depends-on relationship between 'taskRepositoryInitializer' and 'dataSourceScriptDatabaseInitializer'
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[timestamp-task:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
        ... 20 common frames omitted

from spring-cloud-task.

hpoettker avatar hpoettker commented on September 22, 2024

The TaskRepositoryDatabaseInitializerDetector currrently has the same order as the DataSourceScriptDatabaseInitializerDetector. This was chosen intentionally as the latter also detects the BatchDataSourceScriptDatabaseInitializer, which serves a very comparable purpose.

The DependsOnDatabaseInitializationPostProcessor from DatabaseInitializationDependencyConfigurer declares a strict ordering between the database initializers by declaring bean dependencies for each initializer on the respective previous initializer. For initializers whose detectors have the same order, this strict ordering is ill-defined. Usually, this is not an issue as the initializers with detectors of the same order do not depend on each other logically.

The root cause of this issue is that the DependsOnDatabaseInitializationPostProcessor runs twice: Once during AOT processing and once during start-up of the native image. If the two detectors are loaded in different orders, this yields different orderings for the initializers which then leads to the observed circular dependency. Interestingly, I didn't manage to reproduce the issue in a Gradle build. Only the Maven build leads to a different order of class loading compared to the native image.

I think the root cause needs to be addressed in Spring Boot as the DataSourceScriptDatabaseInitializerDetector detects at least 5 initializers whose ordering is thus ill-defined and prone to the same issue.

For the upcoming release of Spring Cloud Task, a possible workaround is to change the order of TaskRepositoryDatabaseInitializerDetector. For example, it can be increased or decreased by one. As far as I can tell, it should have a different order than any other detector in the Spring portfolio either way.

from spring-cloud-task.

wilkinsona avatar wilkinsona commented on September 22, 2024

Thanks for the analysis, @hpoettker.

As far as I can tell, it should have a different order than any other detector in the Spring portfolio either way.

I'm not sure that this is true. The vast majority of detectors have an order of 0. I believe the only detector that doesn't is DataSourceScriptDatabaseInitializerDetector. It has very low precedence so that script-based initialization can be used in combination with higher-level migration tools such as Flyway or Liquibase. This is an edge case and I wonder if TaskRepositoryDatabaseInitializerDetector really needs a non-default order.

from spring-cloud-task.

hpoettker avatar hpoettker commented on September 22, 2024

@wilkinsona Thanks for the feedback!

And sorry for misphrasing. What I meant was that if the order is changed by 1, then it should have a unique order, which is good as a workaround.

I completely agree that it's not totally clear what the right order is. I was also wondering whether it was really intended that spring-projects/spring-boot#26692 affected e.g. the Batch Initializer.

from spring-cloud-task.

cppwfs avatar cppwfs commented on September 22, 2024

Resolved with the following commit. 8c450c4

from spring-cloud-task.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.