2017-09-05 1660 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:

組在此執行程序應該在關機 塊,以等待剩下的任務容器的其餘部分之前他們的執行完成 的最大秒數繼續關閉 。如果您的剩餘任務可能需要訪問由 容器管理的其他資源,則此功能特別有用。

這是我的問題的確切說明和解決方案。