1

I'm using Spring 3.2.13.RELEASE and I have a method (on a spring-managed bean) annotated with @Scheduled that runs but is not invoked via a proxy and therefore it fails when I try to access the transaction:

@Service
@Transactional
public class CoreEmailServiceImpl extends BaseEmailServiceImpl implements CoreEmailService {

    @Override
    @Transactional
    @Scheduled(cron = "0 0 5 * * *")
    public void sendDailySummaryEmail() {
      //.. stuff
      TransactionSynchronizationManager.registerSynchronization(...); // fails
    }

}

stack trace:

    [#|2016-02-03T05:00:00.386-0700|SEVERE|glassfish3.1.2|com.a.b.common.CoreEmailServiceImpl|_ThreadID=22570;_ThreadName=Thread-2;|Error sending email.
java.lang.IllegalStateException: Transaction synchronization is not active
        at org.springframework.transaction.support.TransactionSynchronizationManager.registerSynchronization(TransactionSynchronizationManager.java:291)
        at com.a.b.common.BaseEmailServiceImpl.sendEmail(BaseEmailServiceImpl.java:144)
        at com.a.b.common.BaseEmailServiceImpl.sendEmail(BaseEmailServiceImpl.java:95)
        at com.a.b.common.CoreEmailServiceImpl.sendDailySummaryEmail(CoreEmailServiceImpl.java:95)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
        at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
        at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

But when I invoke the method via a SpringMVC endpoint, it works correctly.

@Controller
@RequestMapping("/admin")
public class AdminController extends AbstractController {
@RequestMapping(value = "/job/daily-summary", method = RequestMethod.POST, produces = "application/json")


    @Autowired
    private AdminService adminService;

    @ResponseBody
    public ResponseBean runDailySummaryEmailJob() {         
        adminService.runDailySummaryEmailJob();
        return null;
    }
}


@Service
@Transactional(readOnly = true)
public class AdminServiceImpl extends DefaultServiceImpl implements AdminService {

    @Autowired
    private CoreEmailService coreEmailService;

    @Override
    public void runDailySummaryEmailJob() {
        coreEmailService.sendDailySummaryEmail();
    }
}

In a completely unrelated part of my project, I have another scheduled method on spring-managed bean that IS invoked via a proxy. The following lines from the two stack traces really outline the inconsistency I'm seeing between my two scheduled methods which both reside on spring managed beans:

  1. com.a.b.common.CoreEmailServiceImpl.sendDailySummaryEmail(CoreEmailServiceImpl.java:93)
  2. com.sun.proxy.$Proxy679.emailMonthlyAccountStatement(Unknown Source)

edit: I've updated spring to 3.2.16 with no luck.

edit: I've tried throwing the @scheduled annotation on the interface, i.e. CoreEmailService#sendDailySummaryEmail and it doesn't get triggered at ALL.

edit: Spring's ScheduledAnnotationBeanPostProcessor checks if a scheduled method belongs to a proxy via AopUtils.isJdkDynamicProxy(bean) and I've confirmed it returns true for all of my other scheduled methods except for this one in particular. Now trying to find out why...

edit: During initialization, I can confirm that the DefaultAopProxyFactory does in fact pick up the CoreEmailServiceImpl and create a dynamic proxy for it. Still unsure why the ScheduledAnnotationBeanPostProcessor doesn't detect this proxy.

mbosecke
  • 842
  • 10
  • 22
  • I tried updating spring to 3.2.16 to see if SPR-12709 had any effect but it did not help. – mbosecke Feb 03 '16 at 17:53
  • 2
    Sounds like it could an issue with proxies as described here: http://stackoverflow.com/a/12957545/485695 – gar Feb 03 '16 at 18:00
  • That answer implies that the intended behavior is for a scheduled method to be invoked natively and that it is up to me to call my proxies within that method. I can't find any documentation on this plus I just edited my original post to state that another part of my project has a scheduled method that IS invoked via proxy. – mbosecke Feb 03 '16 at 18:18

0 Answers0