Spring batch - issue with explicitly setting the job as failed - spring

I am trying to set the status of job as failed in afterJob listener based on few conditions. But the job commits the changes and exits by marking job completed. Below is how I am setting the status. What could be wrong here?
jobExecution.addFailureException(e);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Incorrect data"));
jobExecution.setStatus(BatchStatus.FAILED);
Version: Spring Boot 2.7.0
public void afterJob(JobExecution jobExecution) {
String message = "Completed job.";
try {
//get context and batch
ExecutionContext executionContext = jobExecution.getExecutionContext();
//processing done here
} catch (Exception coe) {
jobExecution.addFailureException(coe);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Could not complete job"));
jobExecution.setStatus(BatchStatus.FAILED);
message = jobExecution.getExitStatus().getExitDescription();
} finally {
try {
//Database update here. When this fails, the Job is expected be marked FAILED, but its marked COMPLETED
throw new Exception("DB update failed"); //simulating exception
} catch (Exception e) {
System.out.println("Exception while saving final details to DB. This is printed");
jobExecution.addFailureException(e);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Could not complete job"));
jobExecution.setStatus(BatchStatus.FAILED);
}
}
}

Related

Catch optimistick lock exception hibernate spring boot

i'm trying to intercept an optimistick lock exception and throw another exception but it doesn't work in my case, the exception is catched but i still have error optimistick lock in my console.
//MY DAO
public Entity getEntitieSimple(...) throws CustomException{
Entity entity="my select";
}
//MY SERVICE
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public Entity recupererEntity() throws CustomException{
Entity entity =null;
try {
entity = dao.getEntitieSimple(...);
}catch (Exception exec){
throw new CustomException("custom message");
}
return entity;
}
#Transactional(propagation = Propagation.REQUIRED)
public void myUpdate() throws HibernateException{
try {
// entity update here
}catch (HibernateException exec){
log.error("OPTIMISTIC: "+ exec.getMessage());
throw new HibernateException("optimi update");
}
}
I'm getting this error evern after catching the exception:
ERROR - 29-09-2022 09:59:44.204 - http-nio-8090-exec-5 - 3933807 - null - c:96e7d7ca8f7d5637 - org.hibernate.internal.ExceptionMapperStandardImpl - HHH000346: Error during managed flush [Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.apicil.cosy.dop.domain.impl.Entity#1420]]
You have to catch ConcurrencyFailureException
private void updateStatus(UpdateOrderDto dto, OrdersStatusUpdaterService self) {
try {
updateStatusHelper(dto, self);
} catch (ConcurrencyFailureException ex) {
log.error("Concurrent modification error. Will try next time. orderId={}", dto.getId(), ex);
}
}

Aws xray segement executor not running in background

I have an api like this
#GetMapping("/async-test")
public String api2() throws InterruptedException {
log.info("Before async");
myService.myAsync();
log.info("after async");
return "nothing important";
}
And myService.myAsync implementation like this
#Async
public void myAsync() {
CompletableFuture.supplyAsync(() -> {
try {
log.info("before thread ....");
Thread.sleep(3000);
log.info("after thread ....");
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
log.info("before returning result ....");
return "Result of the asynchronous computation";
}, SegmentContextExecutors.newSegmentContextExecutor());
}
The issue here is that API waits for 3 seconds to reply when using SegmentContextExecutors.newSegmentContextExecutor(), but if I remove the segment executor, the function run in the background successfully, but for sure I lose the segment trace id for logging.
So what should be done to fix this ?
Tech stack
Spring boot v.2.7.2
Java 11
Aws x-ray v.2.11.2

Spring transaction: unexpected rollback behavior

I am doing a simple experiment for debugging purpose.
First I insert serveral records to database, and then I do a invalid data conversion which will throw DataIntegrityViolationException, but I will catch the exception.
I expected the records being successfully inserted into the db, since I catch the checked exception. But the whole thing is rolled back.
I do the experiment again using TransactionTemplate instead of using annotation, same result.
My questions are:
is this the expected behavior?
If anwser to No.1 is yes, then I catch the exception, how is it possible that spring knows an exception is thrown?
Here is my code:
public void insertValue() {
jdbcTemplate.execute("insert into people (person_id, name) values (4, 'asjkdhadsjkqhweqkewhkashdkahd')");
jdbcTemplate.execute("insert into people (person_id, name) values (5, 'tttqqq')");
}
// this should throw exception
public void truncateValue() {
jdbcTemplate.execute("alter table people alter column name varchar(7)");
}
public void jdbc_calls() {
insertValue();
try {
truncateValue();
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("Finish");
}
public void run() {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
transactionTemplate.execute(transactionStatus -> {
try {
jdbc_calls();
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
return null;
});
}
More about question No.2.
Here is the source code of TransactionTemplate.execute()
From my understanding, if I don't throw an exception, rollbackOnException won'r be triggered.
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
is this the expected behavior?
Yes, it is.
If anwser to No.1 is yes, then I catch the exception, how is it possible that spring knows an exception is thrown?
When an exception occurs, spring will mark your transaction as rollbackOnly.
So even when you catch your exception, at the end of your method, your transaction still rolled back.
In your case, I don't get why you use #Transaction since you want to commit regardless if exception occurs.
Edit
When you're using transaction with DB, the transaction invocation is delegated to EntityManager.
Look at AbstractEntityManagerImpl#handlePersistenceException:
#Override
public void handlePersistenceException(PersistenceException e) {
if ( e instanceof NoResultException ) {
return;
}
if ( e instanceof NonUniqueResultException ) {
return;
}
if ( e instanceof LockTimeoutException ) {
return;
}
if ( e instanceof QueryTimeoutException ) {
return;
}
try {
markForRollbackOnly();
}
catch ( Exception ne ) {
//we do not want the subsequent exception to swallow the original one
LOG.unableToMarkForRollbackOnPersistenceException(ne);
}
}
When exception occurs, the EntityManager mark your transaction as rollbackOnly before throws out the exception for you to catch.
After the exception is catched in your service, the AbstractPlatformTransactionManager will try to commit (because, as you know, no exception is detected there), but the EntityManager refuses to commit because its detect that the transaction marked as rollback-only.
If you read the exception, you will see something like:
javax.persistence.RollbackException: Transaction marked as rollbackOnly

EJB3.0 transaction fail inside a method in successive transaction taking place

I am processing three transaction inside a single method in stateless container managed bean .i want to persist three transaction while if one throws exception other two should complete their respective transaction ,error is that if first or any one is throwing exception other two are to executing please give some helpful suggestion
public void allocateSubjectToStudent(SubjectAllocatedToStudentDto dto)throws Exception {
logger.info("allocateSubjectToStudent method entry :");
List<Subject> coreList=dto.getCoreList();
Iterator<Subject> iterator=coreList.iterator();
while(iterator.hasNext()){
logger.info("inside while :");
SubjectAllocatedToStudentBo bo=new SubjectAllocatedToStudentBo();
bo.setBacthId(dto.getBacthId());
bo.setSemester(dto.getSemester());
bo.setStudentId(dto.getStudentId());
Subject subject=iterator.next();
bo.setSubjectName(subject.getSubjectName());
bo.setSubjectType(subject.getAbbreviation());
try{
manager.persist(bo);
}
catch(javax.persistence.PersistenceException e){
Throwable t = e.getCause();
while ((t != null) && !(t instanceof org.hibernate.exception.ConstraintViolationException)) {
t = t.getCause();
}//while
if (t instanceof org.hibernate.exception.ConstraintViolationException) {
throw new Exception("Core subject already allocated to student");
} //end of if
}//end of catch
}//end of while
List<Subject> departmentallist=dto.getDepartmentList();
Iterator<Subject> iterator1=departmentallist.iterator();
while(iterator1.hasNext()){
logger.info("inside while :");
SubjectAllocatedToStudentBo bo=new SubjectAllocatedToStudentBo();
bo.setBacthId(dto.getBacthId());
bo.setSemester(dto.getSemester());
bo.setStudentId(dto.getStudentId());
Subject subject=iterator1.next();
bo.setSubjectName(subject.getSubjectName());
bo.setSubjectType(subject.getAbbreviation());
try{
manager.persist(bo);
}
catch(javax.persistence.PersistenceException e){
Throwable t = e.getCause();
while ((t != null) && !(t instanceof org.hibernate.exception.ConstraintViolationException)) {
t = t.getCause();
}//while
if (t instanceof org.hibernate.exception.ConstraintViolationException) {
throw new Exception("InterDepartmental subject already allocated to student");
} //end of if
}//end of catch
}//end of while
List<Subject> electiveList=dto.getElectiveList();
Iterator<Subject> iterator2=electiveList.iterator();
while(iterator2.hasNext()){
logger.info("inside while :");
SubjectAllocatedToStudentBo bo=new SubjectAllocatedToStudentBo();
bo.setBacthId(dto.getBacthId());
bo.setSemester(dto.getSemester());
bo.setStudentId(dto.getStudentId());
Subject subject=iterator2.next();
bo.setSubjectName(subject.getSubjectName());
bo.setSubjectType(subject.getAbbreviation());
try{
manager.persist(bo);
}
catch(javax.persistence.PersistenceException e){
Throwable t = e.getCause();
while ((t != null) && !(t instanceof org.hibernate.exception.ConstraintViolationException)) {
t = t.getCause();
}//while
if (t instanceof org.hibernate.exception.ConstraintViolationException) {
throw new Exception("Elective subject already allocated to student");
} //end of if
}//end of catch
}//end of while
logger.info("allocateSubjectToStudent method exit :");
} //end of method
create three different method all with TranscationAttributeType REQUIRES_NEW
Please find below code snippet for EJB3 Bean
public void doYourWork()
{
a();
b();
c();
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void a()
{
try
{
//Do the first transaction here
}catch(Exception e)
{
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void b()
{
try
{
//Do the second transaction here
}catch(Exception e)
{
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void c()
{
try
{
//Do the third transaction here
}catch(Exception e)
{
}
}
Within a single method invocation there is only a single transaction active. To achieve what you want, you must perform the three operations in different transactions. This would require one more level of abstracttion.
public class MyFreshTransaction {
#TransactionAttribute(REQUIRES_NEW)
public void updateO() {
//do something
}
#TransactionAttribute(REQUIRES_NEW)
public void update1() {
//do something
}
#TransactionAttribute(REQUIRES_NEW)
public void update2() {
//do something
}
}
#Stateless
public class MyTransactionProcessor {
#EJB
private MyFreshTransaction freshTransaction;
public void processTransaction() {
try {
//The current transaction context will be suspended, and a new one invoked
//if the new one fails and is rollback, the current one is not affected.
//you can then handle the exception, by rethrowing the exception,in which case
//the current transaction will also be rolled back, or continue based on your logic.
freshTransaction.update0();
} catch (Exception ex ) {//handle}
try {
//The current transaction context will be suspended, and a new one invoked
//if the new one fails and is rollback, the current one is not affected.
//you can then handle the exception, by rethrowing the exception,in which case
//the current transaction will also be rolled back, or continue based on your logic.
freshTransaction.update1();
} catch (Exception ex ) {//handle}
try {
//The current transaction context will be suspended, and a new one invoked
//if the new one fails and is rollback, the current one is not affected.
//you can then handle the exception, by rethrowing the exception,in which case
//the current transaction will also be rolled back, or continue based on your logic.
freshTransaction.update2();
} catch (Exception ex ) {//handle}
}
}
Note that if any of the update transaction was successful, and the the parent transaction is rolled back, it will not affect the status of the 'child' transactions, as they had already been committed and their effects (if DB effects) will be committed too.
Read on Java EE Transactions Java EE Transactions

how to populate cvc-complex-type error information in mule

I have mule message filters to validate SOAP Request against schema,
my question is:
how to log error details of 'which element is have parse exception (cvc-complex-type). because catch block is always trowing exception details: "Message has been rejected by filter". how can i show exact exception?. so that user will enter correct data on request.
write a customfilterclass as a child of SchemaValidationfilter.
override accept method and throw soap fault.
public class CustomSchemaValidationFilter extends SchemaValidationFilter {
#Override
public boolean accept(MuleMessage muleMessage) {
return validateBody(muleMessage);
}
public boolean validateBody(MuleMessage message) throws Fault {
Source source = null;
try {
source = loadSource(message);
} catch (Exception e) {
throw getFaultObj(e);
}
try {
createValidator().validate(source);
} catch (SAXException e) {
throw getFaultObj(e);
} catch (IOException e) {
throw getFaultObj(e);
}
return true;
}
private Fault getFaultObj(Exception e) {
return new SoapFault(e.getMessage(), e, new QName(
DEFAULT_SCHEMA_LANGUAGE));
}
}
//and add in mule flow following tags to validate filter.
<custom-filter class="org.mule.module.xml.filters.CustomSchemaValidationFilter">
<spring:property name="schemaLocations" value="${approvalHistorySchemaLocation}" />
</custom-filter>**

Resources