0

I'm trying to implement @Retryable and @Recover feature for my Database operation.

See below my sample code

@Retryable(value = {PriceUploadServiceException.class,RuntimeException.class}, maxAttempts = 3, backoff = @Backoff(10000))
@Transactional(value ="phoenixTxManager", propagation =Propagation.REQUIRED, rollbackForClassName ="PriceUploadServiceException")
public void insertUploadedData(UploadInsertReqDTO uploadInsertReq)
{
    //Doing some insertion and update operation
}
        
@Modifying
@Transactional(value ="phoenixTxManager", propagation =Propagation.REQUIRED, rollbackForClassName ="PriceUploadServiceException")
@Recover    
public void updatefailureStatus(RuntimeException ex,UploadInsertReqDTO uploadInsertReq)
{
    //Doing some delete operation, If all the retry attempts got failed
    logger.info("All Retry fails So Recover Invoked : "+uploadInsertReq.getSeqId());
                
    Optional<AsyncProcessEntity> optAsync = asyncProcessRepo.findById(uploadInsertReq.getSeqId());
    if(optAsync.isPresent()) 
    {                
         AsyncProcessEntity asynObj = optAsync.get();
         asyncProcessRepo.deleteById(asynObj.getAsyncProcessSeqId());
         asynObj.setProcessStatus(AppConstants.FAILED);
         phenixtEntityManager.persist(asynObj);
         phenixtEntityManager.flush();
    }
}

I have tried above logic in my code, that retry attempts working fine, But when I do delete and insert the records in @Recover method, I'm getting below exception. Even I removed @Transactional for @Recover method

    javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
        at com.sun.proxy.$Proxy193.persist(Unknown Source)
        at com.tcs.opt.priceupload.service.PriceUploadService.updatefailureStatus(PriceUploadService.java:339)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
        at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler.recover(RecoverAnnotationRecoveryHandler.java:73)
        at org.springframework.retry.interceptor.RetryOperationsInterceptor$ItemRecovererCallback.recover(RetryOperationsInterceptor.java:141)
        at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:512)
        at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:351)
        at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:180)
        at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:115)

Please help me to resolve this issue, or else tell me any other solution to achieve this functionality.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Kavi Chinna
  • 237
  • 2
  • 7
  • 18
  • I think the problem Is that `@Transactional` auto closes the session. When hitting `@Recover` method the current session is already closed. Therefore we need to open up another session. I have currently no IDE to test but you should check if the EntityManagerFactory can help. Further: Is phenixtEntityManager just normally injected? – Daniel Rafael Wosch May 19 '21 at 08:17
  • Yeah I have used Autowired to inject that phoenixEntityManager like @PersistenceContext(unitName = "phoenixEntityFactory") EntityManager phenixtEntityManager; – Kavi Chinna May 19 '21 at 08:28
  • Inside that @Recover method its deleting the record, but not inserting it again. – Kavi Chinna May 19 '21 at 08:38
  • Have you tried to use `asyncProcessRepo.save` to save the entity instead using the `entityManager` directly? Repository seems to fetch the entity therefore there should be an active session but the entityManager seems to lack of an active session. – Daniel Rafael Wosch May 19 '21 at 08:39

0 Answers0