假装客户端和Spring重试

时间:2017-11-07 06:37:03

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

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

@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/payments json.message:发送付款   添加付款失败原因有其他原因:{ERROR_RESPONSE_BODY =连接   拒绝执行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)at   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))

但这不可能,我还有其他选择吗?

4 个答案:

答案 0 :(得分:6)

您可以在Retryer

中添加FeignClientConfig
@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

更新了示例Retryer.Default示例配置

答案 1 :(得分:1)

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

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

注意:" myapp"是你的服务ID。

查看此Github implementation了解工作示例

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我通过在 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);
 }    
}