I am using spring boot to make a mock of one of our more complicated services. While all of the standard cases are easily done there is one that is causing me some troubles. It is theoretically possible for the application I am mocking to crash and close the connection without sending a response.
I tried several things to achieve this in spring boot without actually having my mock to crash. This includes throwing exceptions that go into an exception handler and from there do not properly response, however so far that either has generated an error response by spring or somehow resolved to an empty response.
Is there an option to have a method in a #Conroller to cause a closed connection without any response?
Closing the connection is the responsibility of HTTP specification and protocol. You cannot enforce it programmatically. Connection negotitation is happening between HTTP Client and HTTP Server.
Although you can try interrupting current Thread or setting header Connection: close, but you should not be messing around with that part of the processing of a Connection and Request. Your HTTP server can start behaving unexpectedly.
Try a different approach. If you need to simulate a closed connection you can programmatically allocate a new instance of HTTP server, send a request to it, put request processing on hold and kill an instance is a separate thread. I'm sure you'll find a better way for this, just get to the root of the problem from a different angle.
You can create method like this:
#ResponseBody
#RequestMapping("/your-url")
public String test() {
return null;
}
you can also change #Controller to #RestController and remove the #ResponseBody
Related
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.
I am using spring boot to make a mock of one of our more complicated services. While all of the standard cases are easily done there is one that is causing me some troubles. It is theoretically possible for the application I am mocking to crash and close the connection without sending a response.
I tried several things to achieve this in spring boot without actually having my mock to crash. This includes throwing exceptions that go into an exception handler and from there do not properly response, however so far that either has generated an error response by spring or somehow resolved to an empty response.
Is there an option to have a method in a #Conroller to cause a closed connection without any response?
Closing the connection is the responsibility of HTTP specification and protocol. You cannot enforce it programmatically. Connection negotitation is happening between HTTP Client and HTTP Server.
Although you can try interrupting current Thread or setting header Connection: close, but you should not be messing around with that part of the processing of a Connection and Request. Your HTTP server can start behaving unexpectedly.
Try a different approach. If you need to simulate a closed connection you can programmatically allocate a new instance of HTTP server, send a request to it, put request processing on hold and kill an instance is a separate thread. I'm sure you'll find a better way for this, just get to the root of the problem from a different angle.
You can create method like this:
#ResponseBody
#RequestMapping("/your-url")
public String test() {
return null;
}
you can also change #Controller to #RestController and remove the #ResponseBody
I have a microservices architecutre and few microservices have its own client in order for other services to easily use the service API.
In case when we need to return response to some service from our client we also can expect that something wrong might happens while client request and client could return some http status (for example 404(not found) in case if data isn't exist for a such request or 500(internal server error) in case of unexpected service error).
My question is which approach we should use for throwing exception from client?
Do we need to create a custom exceptions on client side and handle these in appropriate way? For example MyServiceBasicException, MyServiceResourceNotFoundException, MyServiceInternalServiceErrorException and so on?
Or we need to use already existing exceptions (for example from Spring ResourceNotFoundException that can be thrown in case if data isn't exist for a such request) or other libraries?
Which benefits have one and another approach?
Thanks in advance.
if you want to do some complex handling based on an exception type then you can extend one of the exceptions and do that. otherwise, if it's just for purposes of propagation i would say reuse.
I am developing a very simple REST web service with Eclipse, Tomcat7 and Jersey implementation, with a connection to MySQL.
Looking to the jersey documentation i know that every request create a new object of the root resource class. But i dont know if every request is independet, for example if one request have to wait a long time, the server will accept more request normaly?
The problem is :
I have 2 main classes, 1 class implements Jersey with annotations(Proxy.java), and other class that connects to a BD(Notificator.java), there is only one instance of this class (Singleton) in order to use only 1 Connection object. The classes who implements Jersey use this class. So, if one of the request is blocked , i dont know if the others will run because they are using the same (Notificator.java) instance.
The relation is N instances of(Proxy.java) uses the only one (Notificator.java) witch have one Connection to a MySQL.
Jersey is developed on top of servlets. There is a new thread for each of the incoming request. Your code is creating a bottleneck for all the threads as there is a contention for single available connection object. If you have multiple requests then only one request will be using that connection and others have to wait. If the wait is not too long then there is no problem. But if wait is more than the HTTP REQUEST TIMEOUT then your other requests may end up as TIMED OUT.
I understand that you may be having single connection bottleneck due to some business requriement/ complication. So in all such cases where we cannot process all the requests simulataneously and there can be variety of reasons for it, then we should create our web services as Asynchronous. Asynchronous web services work on the model of SUBMIT REQUEST-> REQUEST ACCEPTED(will be processed asynchronously) and JOB URL returned for polling-> CLIENT POLLS till the JOB IS NOT COMPLETED.
Hope it helps!
Try database connection pooling, more on this here:
http://en.wikipedia.org/wiki/Connection_pool
How to establish a connection pool in JDBC?
in my application (using spring),
i try to call a method from view using spring exposingBean. and when i try to invoke a method from view, it throw error. i try to catch with HandlerExceptionResolver, but no luck, i think it cannot handled by HandlerExceptionResolver because exception wasn't thrown to controller.
so i try another way to redirect the request when exception thrown. and i think aspect has possibility to do it. is it possible to redirected request when exception thrown from aspect?
As you rightly say, HandlerExceptionResolver will not be invoked when an exception is thrown from inside the view. These resolvers are very specifically targetted at controller exceptions.
Your best options here are to use either a HandlerInterceptor and override the afterCompletion method, which will contain the exception thrown by the view. You may be able to send a redirect from here, dependning on whether or not the response has already been committed by the view.
I don't see how aspects would help you here, either. Not the tool for this job.
However, my advice to you is to stop using exposed bean in your JSP. I realise that it's temptingly convenient, but this is the sort of trouble you get from using it. I advise that your controller assemble all the data required by the view, stick it in the model, and send it to the view. That way, there's less danger of the view triggering an exception, since it already has everything it needs.
Also, if you need to send a redirect, as you do, then you really need to do this before the view starts executing. Otherwise, the view layer may start writing out the HTTP response headers before the exception is thrown. If this happens, then you won't then be able to send a redirect instead - the response is "committed".