2

Consider the following code snippet. (I am using Spring 3.1 and Hibernate 3.6)

@Override
@Transactional
public <T extends Termination> void progressToPendingStage(Class<T> entity,
        Long terminationId, String userName) throws Exception {

    Termination termination = findTerminationById(entity, terminationId);
    //TODO improvise such that email does not get sent if data is not saved
    if (termination.getStatus().equals(TerminationStatus.BEING_PREPARED.toString())) {
        termination.setStatus(TerminationStatus.PENDING.toString());
        termination.setSubmittedDate(new Date());
        termination.setSubmittedBy(userName);
        saveOrUpdateTermination(termination);
        //Send an email to SAS
        emailHelper.configureEmailAndSend(termination);
    }   

}

Unit tests for the above method indicate that email will be sent regardless that the saveOrUpdateTermination(termination) throws an exception or not. On further testing and some research I have uncovered that this behavior is the expected behavior. This is not what the business rules desire. An email should be sent only if the termination record was saved successfully. Any suggestions on how to make this behave in the desired manner? One way I can think of is to make the caller handle the exception thrown by the progressToPendingStage method and if no exception was thrown send an email. Am I on the right track or can we alter the way @Transaction behaves.

Khush
  • 853
  • 2
  • 8
  • 21
  • You can refer to [this link](http://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background) about spring transaction. – brucefeng Aug 27 '13 at 02:34
  • it looks like the email sender is not managed by the transaction manager in that case the email is sent before the surrounding transaction is commited – Arun P Johny Aug 27 '13 at 02:39
  • @ArunPJohny The email helper is annotated with @@Service annotation. Should I make the configureEmailAndSend() method @@Transactional as well? Is that what you are suggesting? Could you kindly provide more information please. – Khush Aug 27 '13 at 02:46
  • how is the mailer work.... is it sending the mail directly using a smtp client – Arun P Johny Aug 27 '13 at 02:46
  • @ArunPJohny The EmailHelper uses a custom created emailing API written in house. The email helper configures the email like created a body using XSLT transformation, fills the sender and receiver address and finally sends the email. – Khush Aug 27 '13 at 02:51
  • that is the problem because that mail sender is not an transactional resource, it doesn't wait for the transaction to complete to send the mail... I'm not an expert in this... but this is the problem here... I don't know a fix for this... somebody else may be able to help you... – Arun P Johny Aug 27 '13 at 02:57
  • You can check this. http://stackoverflow.com/questions/4087611/delaying-sending-of-mail-until-transaction-commits. – vivek Aug 27 '13 at 03:31
  • Most of the case any exception will cause active transaction to be rolled back and current method execution stops. I suspect your code inside saveOrUpdateTermination did not actually bubble the exception (maybe it captures it itself and continue normal execution) – gerrytan Aug 27 '13 at 03:55

1 Answers1

0

I have solved this issue by designing around the problem. Sending an Email was never meant to be part of the transaction. I created an object that performed post saving tasks. The object will catch the exception thrown upon saving the termination and if no exceptions were thrown I would then trigger an email to be sent out. One could also put this in an Spring Aspect which could be executed upon successfully returning after a successful save.

Lessons learn't: Don't include steps that don't belong in a method marked with @transaction. If its included in a transaction Spring will silently handle the exception and not throw the exception till the transaction is finished. In short if a method is annotated with @Transaction every line in that method will be execute even though a line in the middle of the method throws an exception.

Khush
  • 853
  • 2
  • 8
  • 21