2017-09-05 1663 views
2

我在使用EntityManager完成@Async任务之前关闭关闭EntityManager /会话的弹簧启动应用程序出现问题。Spring Boot在关闭时关闭休眠会话 - 在完成@Async方法之前

有有关此问题的2类:

调度

,预定的方法保留的职位数量有限,并呼吁XYJobProcessor,做实际工作的@Async方法。

@Component 
public class XYJobProcessingTimer { 

    private final XYJobService  xyJobService; 
    private final XYJobProcessor xyJobProcessor; 

    //constructor skipped 

    @Scheduled(initialDelayString = "${initial_delay}", fixedDelayString = "${delay}") 
    public void performXYJobProcessing() { 
     final String ticket = UUID.randomUUID().toString(); 
     final int reservedJobs = xyJobService.findAndReserveReadyXYJobs(ticket); 

     if (reservedJobs > 0) { 
      final Collection<XYJob> xyJobs = xyJobService.readReservedJobs(ticket); 
      xyJobProcessor.process(xyJobs); 
     } 
    } 

} 

异步处理器

的@Async注释的方法调用访问的EntityManager该服务。

@Service 
public class XYJobProcessor { 

    private final XYJobService xyJobService; 

    // constructor skipped 

    @Async("xyJobProcessorExecutor") 
    public void process(final Collection<XYJob> jobs) { 
     // This service uses the EntityManager and takes some time depending o job count. 
     xyJobService.createXYJobsAndDelete(jobs); 
    } 

} 

配置

在运行@Async任务Executor的配置。创建的线程是非守护进程。

@Configuration 
public class AsyncExecutorConfiguration { 

    @Bean(name = "xyJobProcessorExecutor") 
    public Executor xyJobProcessorExecutor() { 
     final SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); 
     executor.setConcurrencyLimit(10); 
     executor.setThreadNamePrefix("Hasselhoff-"); 
     return executor; 
    } 

} 

的问题

当我关闭应用程序,弹簧会立即关闭EntityManager的会议 - 所有@Async的任务已经完成了。这导致以下异常:

2017-08-31 16:10:54.212 ERROR 12663 --- [Hasselhoff-12] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected error occurred invoking async method 'public void de.xy.services.XYJobProcessor.process(java.util.Collection)'.org.springframework.orm.jpa.JpaSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed! 
     at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333) 
     at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) 
     at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) 
     at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) 
     at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) 
     at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) 
     at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
     at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) 
     at de.xy.services.XYJobService$$EnhancerBySpringCGLIB$$6b9cb1ae.createXYJobsAndDelete(<generated>) 
     at de.xy.services.XYJobProcessor.process(XYJobProcessor.java:24) 
     at de.xy.services.XYJobProcessor$$FastClassBySpringCGLIB$$ccc40c8f.invoke(<generated>) 
     at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
     at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
     at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
     at org.springframework.core.task.SimpleAsyncTaskExecutor$ConcurrencyThrottlingRunnable.run(SimpleAsyncTaskExecutor.java:268) 
     at java.lang.Thread.run(Thread.java:748) 
Caused by: org.hibernate.SessionException: Session is closed! 
     at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:132) 
     at org.hibernate.internal.SessionImpl.getPersistenceContext(SessionImpl.java:2088) 
     at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:340) 
     at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) 
     at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) 
     at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465) 
     at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963) 
     at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) 
     at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) 
     at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147) 
     at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) 
     at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) 
     at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65) 
     at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61) 
     at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) 
     ... 17 common frames omitted 

有没有一种方法,使春季等待@Async执行完成它关闭的EntityManager过吗?或者这是一个错误?

+0

也许这个线程可以帮助:[如何在关机方式中关闭a-spring-boot-application-in-a-correct-way](https:// stackoverflow。com/questions/26547532/how-to-shutdown-a-spring-boot-application-in-a-correct-way) – Patrick

+0

感谢您的提示,但我已经优雅地关闭了应用程序。问题在于Spring在(仍在运行)@Async方法完成工作之前关闭了EntityManager,导致异常。 –

+2

使用像ThreadPoolTask​​Executor这样的其他执行器,并将waitForTasksToCompleteOnShutdown属性设置为true。 –

回答

0

感谢@ M.Deinum,我发现了如何避免此问题:

使用(而不是SimpleAsyncTaskExecutor)一ThreadPoolTaskExecutor并设置它的awaitTerminationSeconds属性结合waitForTasksToCompleteOnShutdown设置为true修复我的问题。

setAwaitTerminationSeconds的JavaDoc:

组在此执行程序应该在关机 块,以等待剩下的任务容器的其余部分之前他们的执行完成 的最大秒数继续关闭 。如果您的剩余任务可能需要访问由 容器管理的其他资源,则此功能特别有用。

这是我的问题的确切说明和解决方案。