3

first I want to say that I have seen all the topics here on stackoverflow for my case but wasn't able to solve my problem anyway.

I need to run scheduled task every night to check weather the task was finished or not - I'm doing like this:

@Service
@Transactional
public class CronBackGroundProcess {

@Autowired
private CronJobService cronJobService;

@Scheduled(cron = "15 01 01 ? * *")
public void StartNightJob() {
    CronJobLog log = new CronJobLog();
    int count = 0;
    try {
        log.setStartTime(new Date());
        log.setStatus("Entered StartNightJob Function");
        cronJobService.saveCronJobLog(log);

        List<Task> Tasks = cronJobService.getActive_AND_InArreasTasks();
        log.setStatus("Grabbed List of tasks to Check");
        cronJobService.saveCronJobLog(log);

        for (Task Task : Tasks) {
            cronJobService.StartNightJobProcess(Task, true);
            count++;
        }
    } catch (Exception e) {
        CronJobLog log2 = new CronJobLog();
        log2.setStatus("Error Occurred " + new Date().toString() + e.getMessage());
        cronJobService.saveCronJobLog(log2);
    }

    log.setLoansChecked(count);
    log.setStatus("Finished");
    log.setEndDate(new Date());
    cronJobService.saveCronJobLog(log);
}
}

CronJobService itself is @Transactional and autowires several @Transactional services

@Service
@Transactional
public class CronJobService {

@Autowired
private ProductService productService;

@Autowired
private RepaymentService repaymentService;

@Autowired
private CronJobLogDAO cronJobLogDAO;


@Autowired
private TransferService transferService;

public String StartNightJobProcess(Account account, boolean makeTransfers) {

    do something....
            }
        }
    }

the process goes without errors and when all transactions must be committed I receive such error:

 org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:524) ~[spring-orm-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757) ~[spring-tx-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726) ~[spring-tx-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478) ~[spring-tx-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272) ~[spring-tx-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) ~[spring-tx-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:646) ~[spring-aop-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at ge.shemo.services.core.CronBackGroundProcess$$EnhancerByCGLIB$$30cdcf31.StartNightJob(<generated>) ~[spring-core-4.0.0.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_79]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [na:1.7.0_79]
at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_79]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) [na:1.7.0_79]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) [na:1.7.0_79]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79]
at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58) ~[hibernate-entitymanager-5.0.1.Final.jar:5.0.1.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515) ~[spring-orm-4.0.0.RELEASE.jar:4.0.0.RELEASE]
... 22 common frames omitted

I can't figure out why. Also If I launch same function from @Controller it works fine

@Controller
@RequestMapping("/test")
public class test {

@Autowired
private ClientService clientService;

@Autowired
private CronBackGroundProcess cronBackGroundProcess;

@RequestMapping(value = "/test")
@ResponseBody
public void test() throws Exception {
    try {

        cronBackGroundProcess.StartNightJob();
    } catch (Exception e) {
       String s = "sd";
    }
   }
}

So my question is why this function works from controller - commits everything as expected and not works from scheduled task(goes through all process without errors)?

Irakli
  • 973
  • 3
  • 19
  • 45
  • Is that the full stacktrace? – Kayaman Feb 12 '16 at 07:54
  • yes it full stack trace – Irakli Feb 12 '16 at 08:01
  • Your `Transaction marked as rollbackOnly` because there was an error happening just before, corrupting the connection. Look more closely in your logs to find the exception, even enable extra logging if neccessary (only neccessary if you caught that exception somewhere and have not printed it). – Gergely Bacso Feb 12 '16 at 08:13
  • I don't think it's error happening because when I launch same fucntion from @Controller everything works fine. – Irakli Feb 12 '16 at 08:18
  • 4
    Your code is flawed. You are catching an exception, which is never passed to the outside transaction, which still thinks it is ok to commit, but due to an exception it has already been marked for rollback. You should rethrow the exception and put the stuff that is after the catch in a finally block and make sure that that is written in a new transaction (as well as the start of the job). Or simply remove `@Transactional` from your `CronBackGroundProcess`. – M. Deinum Feb 12 '16 at 08:33
  • 1
    removed @Transactional from CronBackGroundProcess and I was able to catch the error but the error says the same as stack – Irakli Feb 12 '16 at 08:57
  • 1
    If you can then, put a debug break-point in org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) and then see what the actual exception is. – Pallav Jha Feb 12 '16 at 09:13
  • Tryed removing @Transactional from CronbackgroundProcess - that allowed me to catch the error but nothing ne win this error actually: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly. I tried to inspect all valiable marked as Autowired to make sure they are inicialised - and they are. – Irakli Feb 12 '16 at 10:25
  • @PallavJha I did as you said and found out that null point exeption is thrown by UserService -> SecurityContextHolder.getContext().getAuthentication().getPrincipal(). Can it be cause of there is no logged in user for this transaction? – Irakli Feb 12 '16 at 10:38
  • Your user will always be `null` as the holder gets filled when the user enters through the web interface. How should a background task know which user it is? – M. Deinum Feb 12 '16 at 10:41
  • just put another debug point there to see what is null. – Pallav Jha Feb 12 '16 at 10:45
  • OK - So I found the problem. The problem was that I was using same service for logged in user and the system - where I was logging who was making the changes - as System itself don't have user I was receiving error while getting current user from Spring Security. change the function and now everything is working. @PallavJha - Thank you I was able to find actual error from -> completeTra‌​sactionAfterThrowing fucntion as you offered. Thanks to all of you who helped me :) – Irakli Feb 12 '16 at 11:31
  • @JONIVar Upvote my comment, I would reach closer to 300 rep :-p. – Pallav Jha Feb 12 '16 at 11:59
  • @PallavJha I don't know how to upvote here. white down your comment down in answers and I will mark it. – Irakli Feb 12 '16 at 12:02
  • i believe an Exception is occured so JPA is marked transaction as rollback only. May be you can debug and find out what exception has raised. Use org.springframework.web.method.support.InvocableHandlerMethod class doInvoke method to know the what was the exact reason to rollback. – Sudhakar Feb 12 '16 at 12:44

2 Answers2

8

If you can then, put a debug break-point in org.springframework.transaction.interceptor.TransactionAspectSupport.completeTra‌​nsactionAfterThrowing(TransactionInfo txInfo, Throwable ex) and then see what the actual exception is.

Pallav Jha
  • 3,409
  • 3
  • 29
  • 52
  • the problem occours in developtment environment thats why break point are not viable – Sham Fiorin Aug 05 '19 at 13:38
  • I Added a breakpoint and noticed that one of the foreign keys was null... JPA didn't tell me that it was missing... I had the idea of adding the breaking point... :) Actually you can place break point in any environment with remote debugging :) – Marcello DeSales Aug 08 '21 at 20:46
1

You not need mark CronBackGroundProcess as @Transactional because in StartNightJob() method you not have access to db all access to DB as I guess you execute in CronJobService.

So remove @Transactional from CronBackGroundProcess and it must help.

Gwaeron
  • 81
  • 8