2016-08-05 12 views
8

Używam Netflix Feign do wywoływania jednej operacji Microservice A do innej operacji Microservice B, która sprawdza kod za pomocą Spring Boot.Feign Netflix - Propaguj status i wyjątek za pomocą Microservices

Działanie Microservice B zgłasza wyjątek w przypadku niepowodzenia weryfikacji. Potem obsługiwane w Microservices i zwracają HttpStatus.UNPROCESSABLE_ENTITY (422), jak obok:

@ExceptionHandler({ 
     ValidateException.class 
    }) 
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) 
    @ResponseBody 
    public Object validationException(final HttpServletRequest request, final validateException exception) { 
     log.error(exception.getMessage(), exception); 
     error.setErrorMessage(exception.getMessage()); 
     error.setErrorCode(exception.getCode().toString()); 
     return error; 
    } 

tak, to kiedy Microservice dzwoni do B w interfejsie jako następny:

@Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE) 
@RequestLine("GET /other") 
void otherOperation(@Param("other") String other); 

@Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE) 
@RequestLine("GET /code/validate") 
Boolean validate(@Param("prefix") String prefix); 

static PromotionClient connect() { 

    return Feign.builder() 
     .encoder(new GsonEncoder()) 
     .decoder(new GsonDecoder()) 
     .target(PromotionClient.class, Urls.SERVICE_URL.toString()); 
} 

i walidacja nie powiedzie się zwraca błąd wewnętrzny 500 z następnej wiadomości:

{ 
    "timestamp": "2016-08-05T09:17:49.939+0000", 
    "status": 500, 
    "error": "Internal Server Error", 
    "exception": "feign.FeignException", 
    "message": "status 422 reading Client#validate(String); content:\n{\r\n \"errorCode\" : \"VALIDATION_EXISTS\",\r\n \"errorMessage\" : \"Code already exists.\"\r\n}", 
    "path": "/code/validate" 
} 

Ale muszę wrócić tak samo jak praca Microservice B.

Jakie byłyby najlepsze sposoby lub techniki propagowania statusu i wyjątków za pomocą mikroserwisów za pomocą Netflix Feign?

Odpowiedz

10

Można użyć udawaj ErrorDecoder

https://github.com/OpenFeign/feign/wiki/Custom-error-handling

Oto przykład

public class MyErrorDecoder implements ErrorDecoder { 

    private final ErrorDecoder defaultErrorDecoder = new Default(); 

    @Override 
    public Exception decode(String methodKey, Response response) { 
     if (response.status() >= 400 && response.status() <= 499) { 
      return new MyBadRequestException(); 
     } 
     return defaultErrorDecoder.decode(methodKey, response); 
    } 

} 

na wiosnę odebrać ErrorDecoder trzeba umieścić go na ApplicationContext:

@Bean 
public MyErrorDecoder myErrorDecoder() { 
    return new MyErrorDecoder(); 
} 
+1

Skąd mogłem wiedzieć, czy błąd pochodzi z otherOperation() lub validate()? Dzielę się Feign.builder(), więc chciałbym mieć ten sam ErrorDecoder, a moje kody i wiadomości nie będą takie same :( – Pau

+1

Myślę, że możesz użyć parametru 'methodKey' w metodzie' decode' .Zgodnie z dokumentem API powinien on zawierać '{ @link feign.Feign # configKey} metody java, która wywołała żądanie. np. {@code IAM # getUser()} 'Tak, to może dać ci wskazówkę dotyczącą kontekstu –

+0

Tak, dobra uwaga! To, czego chcę – Pau

0

Napisz swój zwyczaj maper wyjątków i zarejestruj go. Możesz dostosować odpowiedzi.

Kompletna przykładem jest here

public class GenericExceptionMapper implements ExceptionMapper<Throwable> { 

    @Override 
    public Response toResponse(Throwable ex) { 
     return Response.status(500).entity(YOUR_RETURN_OBJ_HERE).build(); 
    } 

} 
3

Shameless wtyczka dla małej biblioteki zrobiłem który używa refleksji dynamicznie rethrow sprawdzonych wyjątki (i niekontrolowany, jeżeli są one w interfejsie udawać) w oparciu o kod błędu zwrócony w treść odpowiedzi.

Więcej informacji na readme: https://github.com/coveo/feign-error-decoder

0

Co możemy zrobić to w następujący sposób:

wspólne słoik, który zawiera wyjątki z obu microservices.

1.) W mikroserwisach Konwertuj wyjątek do klasy DTO, powiedzmy ErrorInfo. Który będzie zawierał wszystkie atrybuty niestandardowego wyjątku z ciągiem wyjątektyp, który będzie zawierał nazwę klasy wyjątku.

2.) Gdy jest wpłynęło microservice B będzie obsługiwane przez ErrorDecoder w microservice B i będzie próbować utworzyć obiekt wyjątku od exceptionType jak poniżej:

@Override 
public Exception decode(String methodKey, Response response) {  

ErrorInfo errorInfo = objectMapper.readValue(details, ErrorInfo.class); 
Class exceptionClass; 

Exception decodedException; 

try { 

    exceptionClass = Class.forName(errorInfo.getExceptionType()); 

    decodedException = (Exception) exceptionClass.newInstance(); 

    return decodedException; 

} 

catch (ClassNotFoundException e) { 

    return new PlatformExecutionException(details, errorInfo); 

} 
    return defaultErrorDecoder.decode(methodKey, response); 
} 
Powiązane problemy