3

If you prefer using configuration properties to configured all @FeignClient, you can create configuration properties with default feign name. It's also possible to set these timeouts per specific client by naming the client. And, we could, of course, list a global setting and also per-client overrides together without a problem.

My client:

@FeignClient( contextId = "fooFeignClient", name = "foo-client", url = "${foo.url}",
    fallbackFactory = FooFallBackFactory.class,
    configuration = FooFeignConfiguration.class)

I'm trying to do this and I want foo-client.readTimeout to override default.readTimeout when I'm using foo-client:

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 3000
        readTimeout: 3000
        loggerLevel: full
      foo-client:
        connectTimeout: 3000
        readTimeout: 5000        
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: "false"
        isolation:
          strategy: "THREAD"
          thread:
            timeoutInMilliseconds: "3000"

But this is not happening. I'm not sure if Hystrix's timeoutInMilliseconds could be impacting, but from my tests, it's not interfering. I want the feign.readTimeout to be 5000 only for the foo-client, not for the other clients. But it looks like it is ignoring this foo-client configuration and using only the default configuration.

I know it's not a @Configuration class problem because the Feign documentation says that if we create both @Configuration bean and configuration properties, configuration properties will win.

Naty S.
  • 31
  • 1
  • 2

1 Answers1

2

As you have seen in the documentation, you can set timeouts per specific client. But you have only configured it for feign client, not for hystrix command. Remember that they have independent timeouts.

I would recommend to use a configuration class instead of editing your application.yml in order to handle multiples feign clients with hystrix. The following example sets up a Feign.Builder where timeouts are being injected for Feign client and Hystrix command.

# application.yml
microservices:
    foo:
        feign:
            url: xxxx
            connect-timeout: 5s
            read-timeout: 5s
        hystrix:
            enabled: true
            timeout: 5s
@FeignClient(name = "foo",
             url = "${microservice.foo.feign.url}",
             configuration = FooFeignConfiguration.class)
public interface FooFeignRepository {
}
@Configuration
@RequiredArgsConstructor
public class FooFeignConfiguration {
    
    @Value("${microservice.foo.hystrix.enabled:true}")
    private final Boolean hystrixEnabled;

    @DurationUnit(value = ChronoUnit.MILLIS)
    @Value("${microservice.foo.feign.connect-timeout:5000}")
    private final Duration feignConnectTimeout;
    
    @DurationUnit(value = ChronoUnit.MILLIS)
    @Value("${microservice.foo.feign.read-timeout:5000}")
    private final Duration feignReadTimeout;
    
    @DurationUnit(value = ChronoUnit.MILLIS)
    @Value("${microservice.foo.hystrix.timeout:5000}")
    private final Duration hystrixTimeout;

    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return (hystrixEnabled ?
            HystrixFeign.builder()
                .options(new Request.Options(
                    (int) feignConnectTimeout.toMillis(), 
                    (int) feignReadTimeout.toMillis()))
                .setterFactory((target, method) -> {
                    return new SetterFactory.Default()
                        .create(target, method)
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                            .withExecutionTimeoutInMilliseconds((int) hystrixTimeout.toMillis()));
                }):
            Feign.builder())
        .retryer(Retryer.NEVER_RETRY);
    }
}
BeardOverflow
  • 938
  • 12
  • 15
  • I did that and I keep getting 3000 ms timeout on the foo-client :( `feign.client.config.default.connectTimeout=3000` `feign.client.config.default.readTimeout=3000` `feign.client.config.foo-client.connectTimeout=3000` `feign.client.config.foo-client.readTimeout=5000` `hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000` `hystrix.command.foo-client.execution.isolation.thread.timeoutInMilliseconds=5000` – Naty S. Jul 27 '20 at 15:19
  • Your connect-timeout is lower than read-timeout. The first property constraints the time required to open the connection and the second property establishes the pending time to wait for an answer after the connection is opened. So, you are getting a timeout of 3000ms because unable to open your connection in first. – BeardOverflow Jul 27 '20 at 15:28
  • But the error I get is about read timeout: `feign.RetryableException: Read timed out executing POST` `Caused by: java.net.SocketTimeoutException: Read timed out` – Naty S. Jul 27 '20 at 16:30
  • I edited my answer, review it. I would recommend you a configuration class when you use multiples feign clients with hystrix. Still it's possible using a application.yml, but it's hard to maintain because hystrix needs the signature's method as command name (for example: ```FooFeignRepository#bar(String,String)```), while a feign builder can do this automatically. – BeardOverflow Jul 28 '20 at 22:25