web-dev-qa-db-fra.com

Feindre le client et réessayer au printemps

J'ai un service reposant appelant un service externe à l'aide du client 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);

}

J'ai remarqué l'échec suivant 3-4 fois au cours des 3 derniers mois dans mon fichier journal:

json.ERROR_RESPONSE_BODY: connexion refusée lors de l'exécution POST http: // service-externe/externe/paiements json.message: envoi du paiement, échec du paiement pour une autre raison: {ERROR_RESPONSE_BODY = Connexion refusée en cours d'exécution POST http: // service-externe/externe/paiements , ÉVÉNEMENT = ADD_PAYMENT_FAILURE, TRANSACTION_ID = XXXXXXX} {} json.EVENT: ADD_PAYMENT_FAILURE json. stack_trace: feign.RetryableException: connexion refusée lors de l'exécution POST http: // service externe/externe/paiements à feign.FeignException.errorExecuting (FeignException.Java:67) à feign.SynchronousMethodHandler.executeAndDecode (SynchronousMethodHandler.Java:104) à feign.SynchronousMethodHandler.invoke (SynchronousMethodHandler.Java:76) à feign.ReflectiveFeign $ FeignInvocationHandler.inve.13

Est-il possible d'ajouter Spring Retry sur un client Feign. Ce que je voulais annoter l'opération addPayment avec

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

Mais ce n'est pas possible, quelles autres options ai-je?

7
Satya

Vous pouvez ajouter un Retryer dans le 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);
    }
}

Mis à jour avec un exemple de configuration d'exemple Retryer basé sur le Retryer.Default.

9
Jeff

Si vous utilisez un ruban, vous pouvez définir des propriétés, vous pouvez utiliser les propriétés ci-dessous pour réessayer:

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

Remarque: "myapp" est votre identifiant de service.

Check out this Github implementation for example working

1
Yogi