【问题标题】:Feign client and Spring retryFeign 客户端和 Spring 重试
【发布时间】:2018-04-19 11:19:53
【问题描述】:

我有一个使用 Spring Cloud Feign 客户端调用外部服务的 RESTful 服务

@FeignClient(name = "external-service", configuration = FeignClientConfig.class)
public interface ServiceClient {

    @RequestMapping(value = "/test/payments", method = RequestMethod.POST)
    public void addPayment(@Valid @RequestBody AddPaymentRequest addPaymentRequest);

    @RequestMapping(value = "/test/payments/{paymentId}", method = RequestMethod.PUT)
    public ChangePaymentStatusResponse updatePaymentStatus(@PathVariable("paymentId") String paymentId,
            @Valid @RequestBody PaymentStatusUpdateRequest paymentStatusUpdateRequest);

}

我在过去 3 个月的日志文件中注意到以下失败 3-4 次:

json.ERROR_RESPONSE_BODY:连接拒绝执行POST http://external-service/external/paymentsjson.message:发送付款 添加付款失败其他原因:{ERROR_RESPONSE_BODY=Connection 拒绝执行 POST http://external-service/external/payments, EVENT=ADD_PAYMENT_FAILURE,TRANSACTION_ID=XXXXXXX} {} json.EVENT:ADD_PAYMENT_FAILURE json.stack_trace:feign.RetryableException:连接被拒绝 执行 POST http://external-service/external/payments at feign.FeignException.errorExecuting(FeignException.java:67) 在 feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:104) 在 feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) 在 feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)

是否可以在 Feign 客户端上添加 Spring Retry。 我想用

注释 addPayment 操作
@Retryable(value = {feign.RetryableException.class }, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier=2))

但这是不可能的,我还有什么其他选择?

【问题讨论】:

标签: spring spring-boot spring-cloud spring-cloud-feign spring-retry


【解决方案1】:

您可以在FeignClientConfig 中添加Retryer

@Configuration
public class FeignClientConfig {

    @Bean
    public Retryer retryer() {
        return new Custom();
    }

}

class Custom implements Retryer {

    private final int maxAttempts;
    private final long backoff;
    int attempt;

    public Custom() {
        this(2000, 3);
    }

    public Custom(long backoff, int maxAttempts) {
        this.backoff = backoff;
        this.maxAttempts = maxAttempts;
        this.attempt = 1;
    }

    public void continueOrPropagate(RetryableException e) {
        if (attempt++ >= maxAttempts) {
            throw e;
        }

        try {
            Thread.sleep(backoff);
        } catch (InterruptedException ignored) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public Retryer clone() {
        return new Custom(backoff, maxAttempts);
    }
}

更新了基于Retryer.Default 的示例Retryer 示例配置。

【讨论】:

  • 您能指出显示自定义重试器的代码示例吗?如何仅为 feign.RetryableException 和最大尝试 = 3 以及重试之间的退避期 2 秒配置重试
  • 你可以实现自己的Retryer
【解决方案2】:

如果您使用的是功能区,您可以设置属性,您可以使用以下属性进行重试:

myapp.ribbon.MaxAutoRetries=5
myapp.ribbon.MaxAutoRetriesNextServer=5
myapp.ribbon.OkToRetryOnAllOperations=true

注意:“myapp”是您的服务 ID。

查看此Github implementation 以获取工作示例

【讨论】:

  • 只有 feign.RetryableException.class 需要重试,并且只需要外部服务的 feign 客户端。我的应用程序包含多个假装客户端。对于功能区设置,我们可以指定特定的 feign 客户端和异常类吗?
  • 对于这种特定情况,您需要使用 FeignConfig 并将其附加到您的 FeignClient 类并执行逻辑
【解决方案3】:

如果它可以帮助某人,请添加它。我正在使用 feign 重置连接,因为该端口上正在运行一些未知进程。 尝试更改端口。 Refer this to find the process running on a port

【讨论】:

    【解决方案4】:

    刚刚新建了一个构造函数Default

    @Configuration
    public class FeignClientConfig {
        @Bean
        public Retryer retryer() {
            return new Retryer.Default(100, 2000, 3);
        }
    }
    

    【讨论】:

      【解决方案5】:

      我准备了一篇关于使用 Spring Retry 和 Feign Client 方法的博客文章。您可以考虑查看Post。所有步骤均已在帖子中说明。

      【讨论】:

        【解决方案6】:

        这是我的配置。在 spring boot 2.2.0.RELEASE 中测试 OK 春云Hoxton.M3。

        feign.hystrix.enabled=true
        MY-SPRING-API.ribbon.MaxAutoRetries=2
        MY-SPRING-API.ribbon.MaxAutoRetriesNextServer=2
        MY-SPRING-API.ribbon.OkToRetryOnAllOperations=true
        MY-SPRING-API.ribbon.retryableStatusCodes=404,500
        
        feign.client.config.PythonPatentClient.connectTimeout=500
        feign.client.config.PythonPatentClient.readTimeout=500
        
        hystrix.command.PythonPatentClient#timeTest(String).execution.isolation.thread.timeoutInMilliseconds=5000
        

        java代码是:

        @FeignClient(name = "MY-SPRING-API",configuration = {PythonPatentConfig.class},fallbackFactory = FallBack.class)
        public interface PythonPatentClient 
        @RequestLine("GET /test?q={q}")
            void timeTest(@Param("appNo") String q);
        

        控制器是:

          @RequestMapping(value = "/test",method = {RequestMethod.POST,RequestMethod.GET})
            public Object test() throws InterruptedException {
                log.info("========important print enter test========");
                 TimeUnit.SECONDS.sleep(10L);
        

        pom.xml 附加添加:

        <dependency>
                    <groupId>org.springframework.retry</groupId>
                    <artifactId>spring-retry</artifactId>
           </dependency>
        

        可选:

        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
            </dependency>
        
        @EnableRetry
        @SpringBootApplication
        public class ApiApplication
        

        这是文件:

        https://docs.spring.io/spring-cloud-netflix/docs/2.2.10.RELEASE/reference/html/#retrying-failed-requests

        https://github.com/spring-projects/spring-retry

        https://github.com/spring-cloud/spring-cloud-netflix/

        【讨论】:

          【解决方案7】:

          我通过在 ServiceClient 之上创建一个包装器解决了这个问题

          @Configuration
          public class ServiceClient {
          
          @Autowired
          ServiceFeignClient serviceFeignClient;
          
          @Retryable(value = { ClientReprocessException.class }, maxAttemptsExpression = "#{${retryMaxAttempts}}", backoff = @Backoff(delayExpression = "#{${retryDelayTime}}"))
          
          public void addPayment( AddPaymentRequest addPaymentRequest){
              return serviceFeignClient.addPayment(addPaymentRequest);
           }    
          }
          

          【讨论】:

            猜你喜欢
            • 2020-11-26
            • 2018-08-22
            • 1970-01-01
            • 2021-10-22
            • 2020-02-03
            • 2021-09-27
            • 2019-07-27
            • 2016-05-11
            • 2017-01-22
            相关资源
            最近更新 更多