What http codes are by default considered if we use #HystrixCommand - java

If we use the annotation #HystrixCommand with just 4 properties, namely, timeoutInMilliseconds, requestVolumeThreshold, errorThresholdPercentage and sleepWindowInMilliSeconds, then what HTTP response codes are considered by hystrix by default to trigger the timeout?
Is it possible to mention the HTTP response codes in any of the hystrix command properties on which you want to trigger the timeout?

Related

Specify server request timeout in Spring Boot & Spring WebFlux (Netty)

We are using Spring Boot in 2.4.2 with Spring WebFlux.
I want the Spring Boot application to terminate all requests to the application that take longer than say 3 seconds to process.
There is server.netty.connection-timeout, but that doesn't seem to do the trick.
Is there a way to specify such a server request timeout?
I was also facing the same issue i.e. even after configuring server.netty.connection-timeout request would get canceled. So, after some debugging found that timeout was getting set to '30000' by AsyncContext.
So, I configured the following property spring.mvc.async.request-timeout which change the timeout being set in AsyncContext and the request stopped getting canceled.
TL;DR:
Netty has no request timeout*. Add this WebFilter to set a request-timeout of 3 seconds using the reactor timeout on every request (here in kotlin, but in Java it works accordingly):
#Component
class RequestTimeoutWebFilter : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
return chain
.filter(exchange)
.timeout(Duration.ofSeconds(3))
}
}
* at least I could not find any information in the netty docs.
Detailed answer
The connection-timeout does not refer to the duration that a request is allowed to take for processing, but it refers to the time it takes for establishing the connection.
First, I could not find any spring configuration option that allows setting the request timeout for netty. Then I went through the netty documentation to find out that there is no concept of request timeouts on the http server (only on the http client).
Wondering about why such important feature would not be supported, I remembered that we often cannot apply the same concepts as in blocking servers for good reasons. Next, I remembered, that in the reactive world we do not directly implement the handling of the request, but how the handling is assembled - i.e. we hold a Mono<Void> that will handle the request. Hence, we can just look at reactor and how to timeout a Mono, which is very easy:
Mono.create(...)
.timeout(Duration.ofSeconds(3))
Next, we just need to figure out, how to apply this to all requests. This is easy as well, because we can just use a WebFilter to intercept all requests to apply our timeout (here in kotlin, but in Java it works accoringly):
#Component
class RequestTimeoutWebFilter : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
return chain
.filter(exchange)
.timeout(Duration.ofSeconds(3))
}
}
This effectively cancels a request within the set timeout with the following error:
2022-10-21 00:08:00.981 ERROR 6289 --- [ parallel-4] a.w.r.e.AbstractErrorWebExceptionHandler : [59dfa990-7] 500 Server Error for HTTP GET "/some/route"
java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 3000ms in 'source(MonoDefer)' (and no fallback has been configured)
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:295) ~[reactor-core-3.4.22.jar:3.4.22]
More tips and hints
To make the timeout configurable, we can use a custom config variable instead of the hard-coded duration.
To custimize the 500 status code we can either change the exception by providing a fallback to the timeout as 2nd argument and handle that exception in a controller advice - or we can just use reactors onErrorReturn.
The documentation for WebFilter actually states that they should be used to implement timeouts:
Contract for interception-style, chained processing of Web requests that may be used to implement cross-cutting, application-agnostic requirements such as security, timeouts, and others.
Still I think it is expected that spring provides such implementation out-of-the box that can be easily configured. Maybe we oversaw that it is there, but then I would argue it is too hard to find. ^^
Alternative solution path
As an alternative, we could use circuit breakers. However, those are implemented on the readers side and conceptually are used to protect the reading side against failure of the downstream - rather than protecting the internal processing within the downstream from running too long. They can only be applied to mimic a request timeout when applying them in a dedicated server (e.g. a spring cloud gateway server) that sits between the actual client and the actual service. When using Resilience4j as implementation, you can use TimeLimiter to achieve it.

Microservice feign infinite loop of invocations?

I am confused about how an infinite loop of feign calls might behave.
An example:
Assume I have 2 APIs, A & B.
if I call API A, which in turn calls API B via a feign HTTP call, which in turn calls API A again via feign, will it recognize this and break the call chain?
Quick flowchart of calls:
A -> B -> A -> B ... Repeat infinitely?
I have not tried this code, it is just an idea。
But I am assuming that spring-cloud-starter-feign will provide some methods to resolve this problem? Is this assumption correct?
#PostMapping(RestJsonPath.API_A)
ResponseEntity<byte[]> apiA();
#PostMapping(RestJsonPath.API_B)
ResponseEntity<byte[]> apiB();
Will it execute until it times out or hystrix will stop it?
TL;DR:
Feign will keep the connection open on the initial request from A to B until the pre-configured timeout kicks in. At this point, Feign will time out the request and if you have specified a Hystrix fallback, Spring will use your Hystrix fallback as the response.
Explanation:
spring-boot-starter-feign provides an abstraction layer for writing the HTTP request code. It will not handle potential loops or cycles in your code.
Here is an example spring boot feign client from their tutorials website for demonstration:
#FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class,
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
#RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
#RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(#PathVariable("postId") Long postId);
}
Notice first that this is an interface - all the code is auto generated by Spring at startup time, and that code will make RESTful requests to the urls configured via the annotations. For instance, the 2nd request allows us to pass in a path variable, which Spring will ensure makes it on the URL path of the outbound request.
The important thing to stress here is that this interface is only responsible for the HTTP calls, not any potential loops. Logic using this interface (which I can inject to any other Spring Bean as I would any other Spring Bean), is up to you the developer.
Github repo where this example came from.
Spring Boot Docs on spring-boot-starter-openfeign.
Hope this helps you understand the purpose of the openfeign project, and helps you understand that it's up to you to deal with cycles and infinite loops in your application code.
As for Hystrix, that framework comes in to play (if it is enabled) only if one of these generated HTTP requests fails, whether it's a timeout, 4xx error, 5xx error, or a response deserialization error. You configure Hystrix, as a sensible default or fallback for when the HTTP request fails.
This is a decent tutorial on Hystrix.
Some points to call out is that a Hystrix fallback must implement your Feign client interface, and you must specify this class as your Hysterix fallback in the #FeignClient annotation. Spring and Hystrix will call your Hystrix class automatically if a Feign request fails.

Is it possible to return a application/json from a Spring Integration http inbound-channel-adapter?

I have an inbound-channel-adapter that forwards message to router and router has one mapping property which calls service activator where I am trying to trigger one REST POST service which accepts input JSON and produce output JSON.
In this case, service activator reutrns null but since http has to return a response.(In inbound-channel-adapter, I am using status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"
I'm using spring-integration v4.3.6
No, it’s possible. Since this component is one-way, there is nothing to return - just only status code header. By default it is 200 OK.
If you would like to return something, you should consider to use HTTP Inbound Gateway instead.
Otherwise your question isn’t clear

Spring AMQP MessageProperties:all headers were removed during deadlettering

I have got a question about Spring AMQP Message:
During processing I was able to update headers of message properties in String AMQP Message with some specific values.
After DeadLettering of this message, all specific headers were disappeared/removed.
Is this behaviour correct ?
Looking forward to your response.
Regards, Anton.
spring-rabbit.version: 1.3.5.RELEASE
spring.version: 4.1.1.RELEASE
The broker knows nothing about your client-side consumer changes; the original message (with its orignal headers) is dead-lettered by the broker (with an x-death header added to indicate the reason - rejection, expiry etc).
In order to do what you want, you need to publish your modified message yourself rather than using dead-lettering.
See the RepublishMessageRecoverer for an example using Spring retry. You can make a custom recover, or simply catch the exception in your listener to republish.

Spring integration application and cache

Have spring integration application with inbound http gateway and outbound http gateway, between those i want to have cache, to avoid unnessesary requests. The only solution i have is to add interceptor with cache and router after it that routes cahced results back to reply channel, and non cached to outbound, but this solution seems tricky and ugly to me.
Interceptor with cache also works good when inbound gateway has same channel for request and reply, (when returns new message with same headers but different payload, its considered as reply) but its not the case I can use.
Any better ideas for this?
More elegant solution can be achieved with <request-handler-advice-chain>
and Spring Cache Advice.
So, your solution may be like this:
<int-http:outbound-gateway>
<int-http:request-handler-advice-chain>
<cache:advice>
<cache:caching cache="foo">
<cache:cacheable method="handle*Message" key="#a0.payload"/>
</cache:caching>
</cache:advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
Where handle*Message is handleRequestMessage method of HttpRequestExecutingMessageHandler. And exactly for this method Spring Integration applies his Advices (e.g. RequestHandlerRetryAdvice).
Here you should configure a cacheManager bean, choose cache name and determine a key for cache entry. In sample above #a0 is a Message object from handleRequestMessage arguments. So, you can specify any SpEL expression against message properties (payload and headers).
And the result of handleRequestMessage will be stored in the cache.
And when you provide the same parameters for HTTP reqeust, the result will be returned just from cache.

Categories