spring-cloud / spring-cloud-circuitbreaker

Spring Cloud Circuit Breaker API and Implementations
Apache License 2.0
335 stars 110 forks source link

ReactiveResilience4JCircuitBreakerFactory not found #80

Closed InternetPseudonym closed 4 years ago

InternetPseudonym commented 4 years ago

During app startup, the following exception is thrown :

2020-09-16 10:11:01.663  WARN 12516 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xxxxxx' defined in class path resource [xxxxxxxx/ResilienceConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.gateway.route.RouteLocator]: Factory method 'xxxxxxx' threw exception; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory' available: There needs to be a circuit breaker implementation on the classpath that supports reactive APIs.
2020-09-16 10:11:01.684  INFO 12516 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-09-16 10:11:01.913 ERROR 12516 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

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

Description:

Method routeLocator in xxxxxxxxx required a bean of type 'org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory' that could not be found.

The following candidates were found but could not be injected:
    - Bean method 'springCloudCircuitBreakerHystrixFilterFactory' in 'GatewayHystrixCircuitBreakerAutoConfiguration' not loaded because @ConditionalOnClass did not find required class 'org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerAutoConfiguration'
    - Bean method 'springCloudCircuitBreakerResilience4JFilterFactory' in 'GatewayResilience4JCircuitBreakerAutoConfiguration' not loaded because @ConditionalOnBean (types: org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory; SearchStrategy: all) did not find any beans of type org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory

Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory' in your configuration.

Process finished with exit code 1

my configuration beans (inside of a class annotated with @Configuration):

    @Bean("config")
    public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {

        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)                
                .circuitBreakerConfig(  CircuitBreakerConfig
                                        .custom()
                                        .minimumNumberOfCalls(1)
                                        .slidingWindowType(SlidingWindowType.COUNT_BASED)
                                        .slidingWindowSize(1)
                                        .waitDurationInOpenState(Duration.ofMillis(100))
                                        .slowCallDurationThreshold(Duration.ofMinutes(1))
                                        .slowCallRateThreshold(1f)
                                        .failureRateThreshold(1f)
                        .build())
                .build());
    }

    @Bean
    public DiscoveryClientRouteDefinitionLocator
    discoveryClientRouteLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties props) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, props);
    }

    @Bean
    RouteLocator routeLocator(RouteLocatorBuilder rlb)
    {
        return  rlb
                .routes()
                .route(this::getRoute).build();
    }

    private Route.AsyncBuilder getRoute(PredicateSpec spec)
    {
        return spec
                .path("/**")
                .filters(this::getFilter)
                .uri("http://no/op");    //nicht relevant
    }

    private UriSpec getFilter(GatewayFilterSpec spec)
    {
        return spec
                .circuitBreaker(config -> config.setFallbackUri("redirect:/fallback"));
    }

the majority of my POM.xml :

 <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
InternetPseudonym commented 4 years ago

the workaround is to instantiate the factory manually :

@Bean
    public ReactiveResilience4JCircuitBreakerFactory factory()
    {
        return new ReactiveResilience4JCircuitBreakerFactory();
    }

I think this needs to be fixed - the spring context needs to be able to instantiate this factory by itself, as long as it is on the classpath

ryanjbaxter commented 4 years ago

It should be creates in this autoconfiguration https://github.com/spring-cloud/spring-cloud-circuitbreaker/blob/1.0.x/spring-cloud-circuitbreaker-resilience4j/src/main/java/org/springframework/cloud/circuitbreaker/resilience4j/ReactiveResilience4JAutoConfiguration.java

Could you put the code in a repo or attach it as a zip?

InternetPseudonym commented 4 years ago

problem was : i used spring-boot-parent instead of spring-cloud-parent .... maybe thats something which could be warned about in the documentation somewhere (for users which are used to including boot-parent)