Spring retry exception handling execution behavior - java

I am trying to get to the best way to wrap spring-retry #Retryable annotation around external service call. Here is my code:
#Retryable(exclude = HttpClientErrorException.BadRequest.class, value = RestClientException.class)
private ResponseEntity<Item> retrieveItemById(String id)
{
HttpHeaders headers = new HttpHeaders();
try {
return restTemplate.exchange(httpConnectionProperties.getBaseUrl() + "/items",
HttpMethod.GET, new HttpEntity<>(item, headers), Item.class, id);
}
catch (RestClientException e) {
log.error("Exception occurred while retrieving an item" , e);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
I have a few questions on what happens when a RestClientException occurs :
Is the catch block executed before retry kicks in or does the retry kicks in before the catch block execution? Do I need a recovery block?
Probably more of an exception handling question - Is there a way to differentiate between an actual retry worthy scenario (service momentarily down, network issues, I/O error etc.) vs exception occurring due to lack of presence of an item in the above case?

Since you are catching and "handling" the exception, retry is disabled; retry will only work if the method throws an exception.
To change the result (instead of throwing the exception to the caller when retries are exhausted, you need a #Recover method.
Not retryable exceptions will go straight there; you can have multiple #Recover methods for different exception types, or one generic one and you can check the exception type yourself.

Related

How to handle EJBException in cases where execution should continue

I have a question about how to handle EJBExceptions in some special cases.
General situation
In our application an EJB (3.0) DataAccessObjects(DAO) are responsible for all database access, these are used in other parts of the application.
Exceptions in the database layer are expected, for instance because of Optimistic Locking or Database constraint violations. The exceptions often thrown outside of the DOA class, because they occur on commit of the automatic JTA transaction. The calling class then receives this exception wrapped in an EJBException.
In most cases ignoring or logging and rethrowing the EJBException is best, as our JMS will trigger automatic retries for MessageDrivenBeans. In two cases, we don't want the exception to be propaged, as they have unwanted side effects.
Handling in JSF
In our JSF website we use the following pattern to display user friendly messages:
#ManagedBean
#ViewScoped
public class MyDataController {
#EJB
private MyDataDao myDataDao ;
public void addData(){
FacesMessage msg;
try {
Data data = new Data();
// Data gets filled
myDataDao.addData(data);
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Succes",
data.getName());
}
catch (EJBException e) {
LOGGER.warn("Failed to add data"newCompanyName, e);
if (ExceptionUtils.getRootCause(e) instanceof SQLIntegrityConstraintViolationException) {
msg = new FacesMessage(FacesMessage.SEVERITY_FATAL, "Failed",
data.getName());
}
else {
msg = new FacesMessage(FacesMessage.SEVERITY_FATAL,
"Failed to add data for unknown reason", data.getName());
}
}
}
}
Handling in Schedules tasks
In a related case, we call the database from a timed task (created using #Schedule). However this task is destroyed when (two consecutive?) exceptions occur while running it (at least in Weblogic). For us it is very important that this task keeps running even if exceptions during handling occur.
We have achieved this by catching and logging all EJBExceptions, as explained in this answer and in this answer. (Actually in our case we decided to catch all exceptions).
Problem
The above solutions mostly work as intended. However, we recently found that Errors are wrapped in an EJBException as well. For instance an OutOfMemoryError. In this case it caused the error to be swallowed, disabling the normal mechanism in Weblogic that would restart the application in case of an OutOfMemoryError.
Effectively this has downgraded Errors to Exceptions.
Question
The only solution I have is to check the recursively check the exception and its causes for instances of type Error, and if that is the case, rethrow the EJBException.
What is the correct way to handle the EJB exceptions in these situations?

Spring save record and send message rollbacks

I have a class:
#Service
#Transactional
class MyService{
#Autowired MyTableRepository repository;
#Autowired FacebookMessageSender sender;
public void updateTableAndSendMessage(MyTable m){
m.setProcessed(1);
repository.save(m);
sender.sendMessageToFacebook(m);
}
}
Somewhere in the code:
List<MyTable> list=repository.findByProcessed(0);
for(MyTable m:list){
myService.process(m);
}
So, I have the following:
In the quartz job I retrieve all records with processed flag set to 0. Then I pass it to service, then processed flag becomes 1 and system sends message to Facebook messenger (wherever). But, if there's a sql exception occurs, before or after 'process' method execution, transaction will be rolled back and flag will be still 0. So Facebook message will be sent on next job launch, and again and again. I tried to break it down to 2 methods, one saves flag other sends message. But then what if message was not sent and I will have to rollback the transaction? So it's like deadlock. I need prevent FB message from being send on other exception and rollback DB changes on FB sending failure. How to do that in spring-data, afaik transaction will be committed after method ends. Thanks
The following code structure should work:
Service class
#Service
class TaskService {
#Autowired TaskRepository repository;
#Autowired FacebookMessageSender sender;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendTaskNotification(Task task){
try {
task.setProcessed(1);
repository.save(task);
sender.sendMessageToFacebook(task);
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
}
Caller class
#Component
class TaskNotificationJob {
#Autowired TaskService service;
#Scheduled
#Transactional
public void sendTaskNotifications() {
for(Task task : repository.findByProcessed(0)) {
try {
service.sendTaskNotification(task);
}
catch (RuntimeException e) {
// Log the error, but don't rethrow the exception.
}
}
}
}
Explanation
a. Ensure that a Facebook message is not attempted if task cannot be saved
If a single task cannot be saved, an exception will be raised and the code will skip the part that attempts to send a Facebook message for the task. Therefore, this requirement is automatically met due to the way the code is structured.
b. Ensure that an error while sending a Facebook message rolls back the task
The lines catch(Throwable t) { throw new RuntimeException(t); } ensure that if any exception (including one that derives from Exception instead of RuntimeException) is thrown while either saving a task or sending a Facebook message for it, it gets re-thrown as a RuntimeException. This in turn will ensure that the #Transactional annotation surrounding the method will roll the database transaction back.
c. Ensure that an error while processing a task does not affect other tasks
Each task is processed in its own transaction (#Transactional(propagation = Propagation.REQUIRES_NEW)) so anything that gets committed before an error occurs, stays committed.
When an error occurs, the calling code catches it (catch (RuntimeException e)) so that the error does not bubble up to the transaction handler for the caller and caller is allowed to attempt and process remaining tasks, as required. Not having this catch clause would mean that the first RuntimeException raised in the service will also bubble up to the caller and will terminate the whole operation immediately, potentially leaving unprocessed tasks. It is important not to re-throw the caught exception at this point because re-throwing it would bubble it up and hence defeat the purpose of having the catch clause in the first place.

Exception in an MVC app and dealing with Hibernate Exception

I have the following controller in an MVC application with Spring and Hibernate:
#RequestMapping(value = { "/mypage"}, method = RequestMethod.POST)
public ModelAndView showPage(Model model, HttpServletRequest request) {
ModelAndView mv = new ModelAndView();
try {
// Here I call a Service and then a DAO, where I can get HibernateException
} catch (Exception ex) {
ex.printStackTrace();
}
mv.setViewName("mypage");
return mv;
I'm not sure the exceptions are handled correctly here.
First of all:
I don't throw any checked exception (HibernateException is also unchecked).
However I need to catch all the exceptions, because I want to show to the user the same page anyway with a notification error (instead of an error page).
In my DAO I didn't catch or rethrew any exceptions.
My questions are:
Is it fine to catch and deal with exceptions in that way?
Should I also catch HibernateException separately in the controller?
Should I do something more than just logging?
Should I also catch the exception in the DAO and then rethrow it? Should rethrow a different type of exception to the controller?
HibernateException encapsulates the actual root cause than can provide you enough information for you to generate meaningful user-friendly messages. Read the Exception Handling section of their documentation.
If the Session throws an exception, including any SQLException,
immediately rollback the database transaction, call Session.close()
and discard the Session instance. Certain methods of Session will not
leave the session in a consistent state. No exception thrown by
Hibernate can be treated as recoverable.
This means that other than catching the exception to transform it or wrap it into another kind of exception, catching the exception won't help you: using the session after won't work as expected anyway.
refer this

Spring Async method hides exceptions

I have a strange issue with Async methods.
If I run it in async way and its job throws some particular exception, it doesn't show it and simply stop the execution (no catch, no log).
I found it working with jasperreport.
This is the fault block code:
JasperPrint jp1=null;
try{
jp1 = JasperFillManager.fillReport(reportD1, params, new JRBeanCollectionDataSource(ingressi));
}catch(Exception e){
log.error(e);
e.printStackTrace();
throw e;
}
If this code is inside an Async annotated method it doesn't throw the exception and doesn't log (simply stops the execution).
If I remove the Async annotation, it throws this:
java.lang.ClassNotFoundException: org.apache.commons.collections.map.ReferenceMap
My trouble is not the exception itself, but why async method doesn't catch it?
Which method is #Async exactly? If you are running an asynchronous method you should always favour a Futureas result type. If you provide a void method, there's no way to transmit any sort of exception that would happen in the (asynchronous) thread.
There is catch for void method. Long story short: Spring Framework 4.1 allows you to register an exception handler for that kind of things, check SPR-8995. 4.1.RC1 will be available shortly if you want to try.

What's the simplest way to change from exception logging to exception handling in a Spring MVC app?

My Spring MVC app is full of methods that look like this:
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public final void foo(HttpServletRequest request, ModelMap modelMap){
try{
this.fooService.foo();
}
catch (Exception e){
log.warn(e.getMessage(), e);
}
}
Exceptions are caught and logged but not handled otherwise.
The fooService called above does the same thing, never throwing exceptions up to the controller but catching and logging them. So, actually this controller exception code will never get invoked.
What's the best and simplest approach to implement proper exception handling in my app?
Get rid of all catch statements if all they do is logging carelessly. catch is meant to handle the error, not hide it.
Once all these catches are removed, install one global exception resolver in Spring MVC (1, 2, 3, ...) Simply implement this trivial interface:
public interface HandlerExceptionResolver {
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
In your exception resolver you might simply log the exception once and let it go as unprocessed (return null), so that error mappings in web.xml will forward request to proper error page. Or you can handle exception yourself and render some error page. AFAIK in simplest case there is no need for register exception resolver, just define it as a Spring bean/annotate with #Service.
Remember, catch the exception only when you know what to do with. Logging is only for troubleshooting, it doesn't handle anything.
BTW this:
log.warn(e.getMessage(), e);
is not only a very poor exception handling, but it is also slightly incorrect. If your exception does not have a message, you will see mysterious null just before the stack trace. If it does, the message will appear twice (tested with Logback):
22:51:23.985 WARN [main][Foo] OMG! - this is the exception message
java.lang.IllegalStateException: OMG! - this is the exception message
at Foo.bar(Foo.java:20) ~[test-classes/:na]
...sometimes undesirable, especially when exception message is very long.
UPDATE: When writing your own exception logger consider implementing both org.springframework.web.servlet.HandlerExceptionResolver and org.springframework.core.Ordered. The getOrder() should return something small (like 0) so that your handler takes precedence over built-in handlers.
It just happened to me that org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver running prior to my handler returned HTTP 500 without logging the exception.

Categories

Resources