Error handling with feign client - resilence4j - spring-boot

My spring boot app has a feign client that POST a payload to external endpoint.
There is requirement to audit all the calls, especially when any errors occurs in calling the endpoint (connection, unauthorized etc), after retry are exhausted. To audit,
need some information from original payload
http status
underlying exception message,
backup original payload for reference
endpoint
I tried below approaches (for error handling), but still unable to find a solution that covers all above
feign Fallbackfactory - it has handle to exception, but unable to effectively capture feign response/original payload
fallbackMethod with resilence4j - here i get access to original payload and exception, but again unable to capture actual response status (401, 503 etc)
CustomErrorDecoder - Here able to get access to feign Response, but then have to map response body (any request body/payload). Also have to map exception
Appreciate any suggestion/ advise?

Related

Feign is giving Exception code 0 instead of 503 when calling service unavailable

I am using feign client to call other microservice but when the calling service is down feign should give the exception of "503 service unavailable" but it giving exceptionCode = 0 with the message "Loadbalance does not have an available server to the client".
If the service is down, I want to hit the ErrorDecoder and retry the call, but Feign is giving 0 exception codes, so it cannot reach the error decoder.
What I am missing?
Check your service is registered with the discovery server.
Check your spring properties 'spring-application-name' is equal to feignClient annotation's value properties

How to handle 401 unauthorized error in Springboot app

I need to log 401 unauthorized errors in my Springboot application.
I wanted to log this for a certain end point in my app since its unauthorized error I know this attempt will be caught when invoking the api at the beginning itself.
Are there anyways I can keep track of this in spring boot?
I tried through WebSecurityConfig but didnt help.
I am using springboot 2.
Thanks in advance.
There are 2 ways I can think of, but probably there are more
use custom #ExceptionHandler method in your controller and make it sensitive to UnauthorizedException.class
Use Filter to introspect into request/response - and log whatever you want in case of response beeing 401.
You can get hold of the authentication entry point and handle some 401 logic in the http
security config:
.authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
log.warn(e.getMessage());
httpServletResponse.setStatus(401);
httpServletResponse.getWriter().print(e.getMessage());
})

What exceptions can be thrown by exchange() on WebClient?

I've implemented a service which makes ReST calls out to other services to implement part of its functionality. I'm using the reactive WebClient for this, something like:
webClient.post()
.uri(....)
.contentType(....)
.accept(....)
.header(....)
.syncBody(someRequestObject)
.exchange()
.flatMap(someResponseHandler::handleResponse)
.doOnError(throwable -> {
// do interesting things depending on throwable
})
.retry(1, this::somePredicateDependingOnThrowable);
Now... I handle HTTP statuses in someResponseHandler::handleResponse, but what I really want to know is, what other kinds of exception/error to expect from the exchange() - i.e.
what exceptions/errors do I get if I can't connect to the downstream service at all?
What exceptions/errors do I get if the connection attempt times out?
What exceptions/errors do I get if I can connect but then the request times out before I get a response?
None of these are HTTP status codes, obviously - but I can't find any documentation to tell me what I can look for. Am I just not looking in the right places? I've had a look through the documentation for the reactive WebClient, and I've had a look through the Reactor Netty Reference Guide, but no luck.
For background, this is important because we do HATEOAS-based service discovery - for some of these exceptions, I want to trigger rediscovery, for some of them, I don't.
I recommend testing your code that uses the WebClient to see how it handles the various scenarios you mentioned. You can test your code against something like MockWebServer easily from unit tests. MockWebServer can simulate most of the errors mentioned here.
Having said that, here's what I have seen in my testing when using WebClient with the ReactorClientHttpConnector. Other connectors may throw slightly different exceptions, but will likely share a super class in the exception class hierarchy as those mentioned below.
Unknown host
java.net.UnknownHostException
Connection refused (port not open on server)
java.net.ConnectException (or subclass)
reactor-netty throws io.netty.channel.AbstractChannel$AnnotatedConnectException
Connect timeout
If you have configured a connect timeout, then you will receive java.net.ConnectException (or subclass)
reactor-netty throws io.netty.channel.ConnectTimeoutException
SSL handshake errors
javax.net.ssl.SSLHandshakeException (or subclass)
Request body encoding error
This varies by the encoder being used, but generally will be org.springframework.core.codec.EncodingException (or subclass)
Some encoders also throw java.lang.IllegalStateException if encoding is configured incorrectly
Response body decoding error
This varies by the decoder being used, but generally will be org.springframework.core.codec.DecodingException (or subclass)
Some decoders also throw java.lang.IllegalStateException if decoding is configured incorrectly
Read Timeout
If using reactor-netty, and you configured a io.netty.handler.timeout.ReadTimeoutHandler, then io.netty.handler.timeout.ReadTimeoutException
If you use the .timeout operator somewhere in the reactive stream call chain, then java.util.concurrent.TimeoutException
Write Timeout
If using reactor-netty, and you configured a io.netty.handler.timeout.WriteTimeoutHandler, then io.netty.handler.timeout.WriteTimeoutException
Connection closed by server prematurely (before response completes)
java.io.IOException (or subclass)
reactor-netty throws reactor.netty.http.client.PrematureCloseException
Others
Any exceptions that occur during your someResponseHandler::handleResponse

Getting Error message as NULL while invoking a service in one spring boot application from another spring boot application using RestTemplate

AM trying to invoke a spring boot microservice from another application.
Here is my Server code, if any exception occurs
return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new com.test.models.ResponseEntity("Tenant details
not found"));
Here is my client code,
ResponseEntity<Object> uploadResponse =
restTemplate.exchange("http://TESTAPPLICATION/v1/object",
HttpMethod.POST, requestEntity, Object.class);
Am getting a response as
Caused by: org.springframework.web.client.HttpClientErrorException: 403 null
If I hit my endpoint from PostMan, am getting proper response message.
But from my client-side application am getting response message as null. Please let me know what is going wrong.
UPDATE:
Screenshot.
Client Responds with INTERNAL_SERVER_ERROR. But from my server iam responding 403.

Spring integration http outbound gateway logging errors

I have an integration flow where I'm reading messages from a jms channel and sending them through a REST api call using http-outbound-gateway.
Now when I get a 5xx Http server error I'd like to log the the URL of the service along with the response message.
I see that the RestTemplate instance already logs the URL and calls a ResponseErrorHandler which can be a custom implementation.
My problem is: the ResponseErrorHandler only receives a ClientHttpResponse as a parameter and I can't know the URL from that instance. What I need is to log the server error like: 'Error URL - Response ...'
How can I do that? I can't override RestTemplate's error handling and the ResponseErrorHandler doesn't have enough info.
Thank you very much.
Well, what I see there.
The HttpRequestExecutingMessageHandler (<int-http:outbound-gateway>) catches all underlying exceptions:
catch (Exception e) {
throw new MessageHandlingException(requestMessage, "HTTP request execution failed for URI ["
+ (realUri == null ? uri : realUri.toString())
+ "]", e);
}
Including the result of that DefaultResponseErrorHandler from the RestTemplate.
And as you see we use here for the MessageHandlingException uri as well as the requestMessage.
Further this exception will be delegated to that jms channel.
Why isn't that enough for you?
From other side you can add <request-handler-advice-chain> to the <int-http:outbound-gateway> with ExpressionEvaluatingRequestHandlerAdvice to get deal with that MessageHandlingException just in place: http://docs.spring.io/spring-integration/docs/latest-ga/reference/html/messaging-endpoints-chapter.html#expression-advice

Resources