When I have my application on tomcat or weblogic and having the following controller:
#ResponseBody
#RequestMapping("/loadByReceiptNo/{receiptNo}/{cashId}")
public Securities loadByReceiptNo(#PathVariable int receiptNo, #PathVariable int cashId) {
return myService.loadByReceiptNo(receiptNo, cashId);
}
calling
/loadByReceiptNo/1
or
/loadByReceiptNo/1/
cause the server hanging for too long and it needs a restart.
how should I avoid such a situation?
UPDATE
this url is being called by another machine and this url serves as webservice. Getting dump threat, I realized that this part of client stuck in deadlock:
conn.getResponseCode()
The temporal relief to this issue is using:
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
Any other solutions will be appreciated.
You are providing wrong URL - /loadByReceiptNo/1. You should also provide {cashId} and not just {receiptNo}. So your URL should be something like /loadByReceiptNo/1/1.
Reason being #Pathvariable cannot be null. You would probably want to do something like -
#ResponseBody
#RequestMapping(value={"/loadByReceiptNo/{receiptNo}/{cashId}","/loadByReceiptNo/{receiptNo}"})
public Securities loadByReceiptNo(#PathVariable Map<String, String> pathVariablesMap) {
if (pathVariables.containsKey("receiptNo") && pathVariables.containsKey("cashId")) {
myService.loadByReceiptNo(receiptNo, cashId);
} else {
//probably return error response
}
}
or write a new controller method altogether for just /loadByReceiptNo/{receiptNo}.
OR you can make cashId as #RequestParam(value="cashId ",required=false) and make it optional.
Either ways your current Mapping is incorrect. However these thing should not let you server hang. So either there is a deadlock or your service/dao call is taking too long. If that is the case I suggest use asynchronous processing like using activemq and not hold server threads. Just return after validation with error or success code and then process the request from the queue.
Related
I'm trying to communicate information between two micro services in Spring. One is sending a ResponseEntity with an Object in the body, but on the other side I can't seem to get the correct response. All the fields are null.
this is the controller of my first microservice
this is what is returned when called directly
this is the code inspection of the response before it's sent
Then I try to recuperate this response in another micro service.
This is the client
This is the call to the first API
This is the response I get
So I'm stuck there, not getting why my client can't access the data. I have set breakpoints in both of the application and the first one is correctly called.
You can find my code there : https://github.com/Shikatamo/B3Examples
I have tried for 3-4h, and I'm really stuck there. It looks like something really stupid from my part but I can't seem to put my finger on it. All help is greatly appreciated at this point.
Try to get rid of ResponseEntity in your client:
#Component
#FeignClient("CourseStudent")
public interface ICourseStudentClient {
#RequestLine("GET /{id}")
CourseStudents getOneById(#Param("id") Long id);
}
I am using jetty with spring boot, and implemented few rest calls, all the get methods are working fine in both the environment dev and qa , but post is always returning '405 Method Not Allowed', I checked everything like headers, body and other parameters everything seems correct.
I am using spring rest implementation, any ideas why its failing.
method Definition:
#RequestMapping(value ="/resub" ,method=RequestMethod.POST )
public ResponseEntity<?> resub(#RequestBody Subscription Subscription,HttpServletRequest request ){
try {
// call to other service methods
//}
} catch (Exception e) {
if(e instanceof HttpClientErrorException)
return commonUtil.getExceptionResponse(e.getMessage());
else
return commonUtil.getExceptionResponse("Unknown Error Occured"); }
}
This answer should really be a comment, but unfortunately I don't have 50 rep yet.
The first problem I notice is that you're closing the resub() function before it even gets to the catch statement.
That doesn't explain why you would get a 405 http status response though.
"The principal cause of this issue is either using the wrong method (not applicable to your case) or multiple handlers have been defined for the same verb/method, and one of the handlers is blocking the expected handler from processing the request. ... IIS processes handlers from first to last based on the order handler entries in the applicationHost.config and web.config files, where the first matching combination of path, verb, resource, etc., will be used to handle the request [1]."
Hope this helps, if not let me know and I can continue trying to help :)
[1] - https://www.asp.net/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications
I am currently using Spring Cloud and Feign to consume a Microservice in my application. Since it can happen, that a database connection or the like fails in a single service instance, making it return 500 HTTP status code, I want to make sure, that the next server is retried by the service's clients. Currently, Ribbon's retry mechanism works like a charm when the service is not running at all, however it still returns instantly an error when it receives a 500 status code, without any retry.
Is it possible to configure the Feign clients or their underlying Ribbon load balancers to retry the next server, if an instance returns a 500 response?
The configuration is pretty much the same as in this thread: Does Feign retry require some sort of configuration?
I would love to use an implementation like Ribbons' HttpResponseValidator (https://github.com/Netflix/ribbon/blob/master/ribbon/src/main/java/com/netflix/ribbon/http/HttpResponseValidator.java), but I couldn't find anything usable for Spring Cloud and its Feign/Ribbon integration
This question is very old and the solution was probably already found or wasn't possible at the time. Anyway, I think that answer might still help someone 8 ).
Please use this as a reference, this code is not intended for production use.
Feign allows you to configure errorDecoder - this is the place where magic happens.
Feign.Builder builder = Feign.builder()
.errorDecoder(new RetryOnScaleErrorDecoder())
Here is the implementation, I use that class to retry request on HTTP error 429 I get from AWS when service is scaling
public static class RetryOnScaleErrorDecoder implements ErrorDecoder {
#Override
public Exception decode(String methodKey, Response response) {
FeignException exception = errorStatus(methodKey, response);
// This is a terrible part please check how feign.codec.ErrorDecoder.RetryAfterDecoder is implemented for proper parsing of retry-after header
Collection<String> headers = response.headers().get("Retry-After");
String repeatAfterString = "0";
if (Objects.nonNull(headers)) {
repeatAfterString = Iterables.getFirst(headers, "0");
}
assert repeatAfterString != null;
Date repeatAfter = new Date(currentTimeMillis());
if (repeatAfterString.matches("^[0-9]+$")) {
try {
long deltaMillis = SECONDS.toMillis(Long.parseLong(repeatAfterString));
repeatAfter = new Date(currentTimeMillis() + deltaMillis);
} catch (NumberFormatException ignored) {
// TODO: logging
}
}
// That's the part where we decide to retry based on status code value
if (exception.status() == 429) {
return new RetryableException(
response.status(),
exception.getMessage(),
response.request().httpMethod(),
exception,
repeatAfter
);
}
return exception;
}
}
I think that in conjunction with Ribbon it will produce desired result.
Try to this config:
MY-SPRING-API.ribbon.retryableStatusCodes=404,500
This is the same question:
Feign client and Spring retry
document is :
https://docs.spring.io/spring-cloud-netflix/docs/2.2.10.RELEASE/reference/html/#retrying-failed-requests
I have a simple POJO that I annotated with REST annotations as follows:
#GET
#Path("/domains/{domainid}")
#Override
public Domain getDomain(#PathParam("domainid") UUID domainID) throws Exception {
logger.info("Retrieving domain "+ domainID);
Domain d = null;
try {
d = MyClient.getDomains().get(domainID.toString());
logger.debug("Returning "+d.getName());
} catch (Exception e) {
logger.error("Could not retrieve domain", e);
}
return d;
}
Note that the log statement including d.getName() can actually throw an NPE which is then caught and logged. That's not pretty but it's also not the point here.
Ultimately whether d has a value or not, I return it.
In the case of a null value, my client receives an HTTP 204 status code. This is what wget displays: HTTP request sent, awaiting response... 204 No Content
Oddly enough, my browsers don't budge an inch. They still display the previous page (I suppose it makes sense to stay put when no content is received). I would have expected a blank page.
Three questions:
is HTTP 204 the right response to be returned?
how can I control that via annotations? Via other configuration?
what is the standard REST best practice regarding null objects?
Thanks
EDIT
There is a great question on the very same topic here: Is it correct to return 404 when a REST resource is not found?
If the request is trying to GET/locate/find a resource, and it can't be found, traditionally, we should send a 404 Not Found. For further discussion see here.
That being said, I generally like to have my resource methods return Response, as it's easier to fine tune the response the way I want (a little - not much - more detail here). But seeing as how your method is overriding an interface contract (and returning a model object), JAX-RS gives us a nice hierarchy of exceptions that will get mapped to a particular response/status. The list can be seen here.
So in your particular case, if the resource can't be found, you can throw a WebApplicationException(Response.Status.NOT_FOUND) or a NotFoundException, and the exception will be mapped to a 404 Not Found. Something like
d = MyClient.getDomains().get(domainID.toString());
if (d == null) {
throw new NotFoundException(); // <-- JAX-RS 2.0
// or throw new WebApplicationException(Response.Status.NOT_FOUND);
// ^^ JAX-RS 1.x
}
The method will exit when the exception is thrown, and the client will receive a response with a 404 Not Found status.
Related Q&As
How to catch 404 (NotFoundException) without being dependant on a JAX-RS implementation?
Is it correct to return 404 when a REST resource is not found?
EDIT
In the first line I stated "If the request is trying to GET/locate/find a resource..", but really, this applies to almost all cases we are using URI templates, whether it is for a GET, POST, PUT, DELETE, whatever. Consider this example
#PUT
#Path("/customers/{id}")
public Response updateCustomer(#PathParam("id") long id, Customer customer) {
...
}
Here is a method that allows the client to update a customer via a PUT. The client should know the complete URI to the resource before trying to update it. If the {id} parameter (used for lookup) is not found say in a database, then the resource doesn't exist, and a 404 Not Found should also be returned to the client.
I'm writing a REST service with Spring Web 4.0.5 and one of called methods is sending e-mail (with javax mail). Sending mail takes some time, but I would like to be able to send HTTP response (no matter what response, e.g. 200) BEFORE this method finishes - so before the mail is sent. Is it even possible? Preferably without multithreading?
#RestController
#RequestMapping(value = "/mails", produces = "application/json")
public class RestMailService{
#Autowired
MailService mailService;
#RequestMapping(value="/test", method = RequestMethod.GET)
public void sendMail(){
mailService.sendMail();
}
}
I believe all possible solutions include multithreading. The thread will be either directly started by you or hidden behind messaging or something similar.
if you were to go with multi-threading after all please use some Executor instead of below suggested new Thread(...).start()
I would also note that returning HTTP 200 before the operation finishes may somewhat confuse the user as the code suggests the operation was successful where in fact the operation maybe didn't even start yet.