Dans l'article précédent (https://qiita.com/totto357/items/90f9276697edec08a4ba), j'ai présenté comment créer un client HTTP en utilisant uniquement des annotations, mais dans le client HTTP réel, il est nécessaire de réessayer. il y a.
En fait, il peut y avoir de nombreux projets qui créent une classe de client HTTP avec RestTemplate
et y effectuent un nouveau traitement.
Réalisons ce processus de nouvelle tentative avec ʻOpen Feign`.
Le traitement des nouvelles tentatives ʻOpenFeign` peut être réalisé en implémentant deux interfaces.
ErrorDecoder
ʻErrorDecoder est une interface pour décider quel type d'exception
est lancé lorsqu'une réponse autre que les 200 est renvoyée dans une requête HTTP.
A titre d'exemple, implémentons une classe qui renvoie ʻIllegalArgumentExceptionquand
400`.
class IllegalArgumentExceptionOn404Decoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
if (response.status() == 400) {
throw new IllegalArgumentException("C'est 400.");
}
return new ErrorDecoder.Default().decode(methodKey, response);
}
}
En gros, je pense que vous pouvez changer le comportement en regardant response.status ()
.
Si vous lancez RetryableException dans decode
, ce qui suit` Retryer.continueOrPropagate «Est appelé.
Retryer
Retryer
est appelé lorsque RetryableException
est lancé, et est une interface pour gérer l'intervalle de relance et le nombre de fois.
La valeur par défaut Retryer
est Retryer.Default essaie 5 fois en 100 ms C'est censé être fait.
Si vous souhaitez uniquement modifier l'intervalle de relance et le nombre de fois, je pense que "Retryer.Default" est suffisant.
Spécifiez la classe d'exécution des deux interfaces ci-dessus dans ʻapplication.yml`.
feign:
client:
config:
{{yourFeignName}}:
errorDecode: com.example.feign.MyErrorDecoder
retryer: com.example.feign.MyRetryer
Définissez yourFeignName
sur celui spécifié dans FeignClient.name
.
Si vous séparez «FeignClient.name», vous pouvez séparer le processus de nouvelle tentative pour chaque «nom».
Ajoutons un processus de nouvelle tentative au précédent Exemple de météo.
MyErrorDecoder.java Dans cet exemple, il est tenté de réessayer lorsque «503» et «504».
package com.example.ofc.feign;
import org.springframework.web.client.RestClientException;
import feign.Response;
import feign.RetryableException;
import feign.codec.ErrorDecoder;
public class MyErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
RestClientException cause = new RestClientException(response.toString());
final int status = response.status();
if (status == 503 || status == 504) {
return new RetryableException(methodKey, cause, null);
}
return cause;
}
}
MyRetryer.java Je viens de modifier un peu Retryer.Default.
package com.example.ofc.feign;
import static java.util.concurrent.TimeUnit.SECONDS;
import feign.RetryableException;
import feign.Retryer;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyRetryer implements Retryer {
private final int maxAttempts;
private final long period;
private final long maxPeriod;
int attempt;
long sleptForMillis;
public MyRetryer() {
this(100, SECONDS.toMillis(1), 3);
}
public MyRetryer(long period, long maxPeriod, int maxAttempts) {
this.period = period;
this.maxPeriod = maxPeriod;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
// visible for testing;
protected long currentTimeMillis() {
return System.currentTimeMillis();
}
@Override
public void continueOrPropagate(RetryableException e) {
log.info("Réessayer le traitement");
if (attempt++ >= maxAttempts) {
throw e;
}
long interval;
if (e.retryAfter() != null) {
interval = e.retryAfter().getTime() - currentTimeMillis();
if (interval > maxPeriod) {
interval = maxPeriod;
}
if (interval < 0) {
return;
}
} else {
interval = nextMaxInterval();
}
try {
Thread.sleep(interval);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
throw e;
}
sleptForMillis += interval;
}
/**
* Calculates the time interval to a retry attempt. <br>
* The interval increases exponentially
* with each attempt, at a rate of nextInterval *= 1.5 (where 1.5 is the
* backoff factor), to the
* maximum interval.
*
* @return time in nanoseconds from now until the next attempt.
*/
long nextMaxInterval() {
long interval = (long) (period * Math.pow(1.5, attempt - 1));
return interval > maxPeriod ? maxPeriod : interval;
}
@Override
public Retryer clone() {
return new MyRetryer(period, maxPeriod, maxAttempts);
}
}
application.yml Spécifiez les deux classes d'implémentation ci-dessus.
server:
port: 8088
application:
name: open-feign-client
feign:
client:
config:
weather:
errorDecoder: com.example.ofc.feign.MyErrorDecoder
retryer: com.example.ofc.feign.MyRetryer
J'ai essayé de réaliser une nouvelle tentative de traitement avec ʻOpenFeign`. Il semble facile à réparer car il peut être réalisé sans toucher au client API lui-même.
Cliquez ici pour cet exemple https://github.com/totto357/open-feign-client-example