Spring Cloud Gate Request Timeout Not working for path
Asked Answered
R

2

4

In Spring cloud Gateway request timeout for path in not working as expected.

I tried to specify global timeout, but its not working as expected.

I am trying to call a microservice A. In A microservice I have added an delay to 5 sec.

Now in path if I add response timeout as more than 5s, it should wait for the response, but currently circuit breaker is opened and currently its returning the fallback message in 1000ms

I have configured resilience4j circuit breaker in gateway.

I am not able to understand why response timeout for Path and global timeout not working.

application.yml

server:
  port: 9090
spring:
  cloud:
    gateway:
      routes:
        - id: ms1_1
          uri: http://localhost:9091/
          predicates:
            - Path=/ms1/**
        - id: ms2
          uri: http://localhost:9092/
          predicates:
            - Path=/ms2/**
          metadata:
            response-timeout: 20000
            connect-timeout: 20000
          filters:
            - RewritePath=/ms2/(?<path>.*), /$\{path}
            - name: RequestRateLimiter
              args: 
               redis-rate-limiter.replenishRate: 2000
               redis-rate-limiter.burstCapacity: 4000
               key-resolver: "#{@userRemoteAddressResolver}"
            - name: CircuitBreaker
              args:
                name: backendA
                fallbackUri: forward:/fallback/ms2
            - name: Retry
              args:
                retries: 3
                statues: INTERNAL_SERVER_ERROR
                backoff:
                  firstBackoff: 50ms
                  maxBackoff: 500ms
                  factor: 2
                  basedOnPreviousValue: true
      
                 
               
  application:
    name: gateway-service
    
  redis:
    host: localhost
    port: 6379
          
management:
  endpoints:
    web:
      exposure:
        include:
        - '*'
  endpoint:
    health:
      show-details: always
  
      

resilience4j.circuitbreaker:
  configs:
    default:
      register-health-indicator: true
      sliding-window-size: 10
      minimum-number-of-calls: 5 
      permitted-number-of-calls-in-half-open-state: 3
      automatic-transition-from-open-to-half-open-enabled: true
      wait-duration-in-open-state: 10s
      failure-rate-threshold: 50
      slow-call-rate-threshold: 50
      slow-call-duration-threshold: 60000ms
      recordExceptions:
        - java.lang.IllegalArgumentException
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
        - java.lang.Exception
        - java.net.UnknownHostException
        - org.springframework.web.reactive.function.client.WebClientResponseException
        - org.springframework.web.reactive.function.client.WebClientResponseException$NotFound
        - org.springframework.web.client.HttpClientErrorException$NotFound
        - java.net.ConnectException
        - io.netty.channel.AbstractChannel$AnnotatedConnectException

        
      ignoreExceptions:
        - java.lang.IllegalStateException
  instances:
    backendA:
      baseConfig: default
        

        

POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.BUILD-SNAPSHOT</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.portal</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.BUILD-SNAPSHOT</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <!-- needed for Resilience4j -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
           <groupId>io.github.resilience4j</groupId>
           <artifactId>resilience4j-spring-boot2</artifactId>
           <version>1.5.0</version>
       </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </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.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </pluginRepository>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>
Radiometer answered 20/11, 2020 at 18:46 Comment(3)
probably you are using TimeLimiterConfig with default value for timeoutDuration set to 1 sec. try to configure it.Bare
No i am using TimeLimiterConfig , i have also noticed that response-timeout: 20000 is not working, when its being used with circuit breakerRadiometer
It seems as the circuitBreaker uses a different timeout (default 1000ms) than the timeout defined for the gateway. You probably only need to define the timeout for resilience4j and you do not need the timeout for the gateway at all (you could still add it, but it is not really required then).Ruppert
R
3

I found that we need to define Timelimiter with Circuit Breaker, and default timeout is 1 Sec

@Bean
    public ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory(
            CircuitBreakerRegistry circuitBreakerRegistry) {
        ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory = new ReactiveResilience4JCircuitBreakerFactory();
        reactiveResilience4JCircuitBreakerFactory.configureCircuitBreakerRegistry(circuitBreakerRegistry);
        
        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofSeconds(1)).cancelRunningFuture(true)
                .build();
        reactiveResilience4JCircuitBreakerFactory.configure(builder -> builder.timeLimiterConfig(timeLimiterConfig).build(),"backendA","backendB");
        return reactiveResilience4JCircuitBreakerFactory;
    }
Radiometer answered 2/12, 2020 at 17:36 Comment(0)
A
0

For me I just used the following time-limiter configuration:

resilience4j:
  timelimiter:
    configs:
      default:
        timeout-duration: 5s
        cancel-running-future: false

or

@Bean
public TimeLimiterRegistry timeLimiterRegistry() {
    return TimeLimiterRegistry.of(TimeLimiterConfig.custom()
            .timeoutDuration(Duration.ofSeconds(5))
            .cancelRunningFuture(false)
            .build());
}

or

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
            .timeLimiterConfig(TimeLimiterConfig.custom()
                    .timeoutDuration(Duration.ofSeconds(5))
                    .cancelRunningFuture(false)
                    .build())
            .build());
}
Adiaphorism answered 21/4, 2024 at 18:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.