2017-09-05 18 views
2

Ich habe ein Problem mit einer Spring-Boot-Anwendung, die den EntityManager/die Sitzung beim Herunterfahren schließt, bevor @Async Aufgaben (die den EntityManager verwenden) beendet sind.Spring Boot schließt die Ruhezustand-Sitzung beim Herunterfahren - bevor die @ Async-Methoden fertig sind

Es gibt zwei Klassen relevant für dieses Problem:

Scheduler

Das geplante Verfahren eine begrenzte Anzahl von Arbeitsplätzen behält und ruft eine @Async Methode auf XYJobProcessor, das die eigentliche Arbeit erledigt.

@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 Processor

Die @Async kommentierten Methode ruft den Dienst, der die EntityManager zugreift.

@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); 
    } 

} 

Konfiguration

Die Konfiguration des Executor, die die @Async Aufgaben ausführt. Die erstellten Threads sind Nicht-Daemon.

@Configuration 
public class AsyncExecutorConfiguration { 

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

} 

Das Problem

Wenn ich die Anwendung herunterzufahren, Feder schließt die EntityManager Session sofort - bevor alle @Async Aufgaben beendet haben. Dies führt zu folgenden Ausnahme:

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 

Gibt es eine Möglichkeit Frühling zu machen wartet @Async Hinrichtung zu beenden, bevor es die EntityManager schließt? Oder ist das ein Fehler?

+0

Vielleicht könnte dieser Thread helfen: [how-to-Shutdown-a-Spring-Boot-Anwendung in einer richtigen Weise] (https: // stackoverflow.com/questions/26547532/how-to-shutdown-a-Spring-Boot-Anwendung-in-richtig-Weg) – Patrick

+0

Danke für den Tipp, aber ich bin bereits die Anwendung anmutig heruntergefahren. Das Problem ist, dass Spring den EntityManager schließt (noch läuft). @Async-Methoden haben ihre Arbeit beendet, was zu der Ausnahme führt. –

+2

Verwenden Sie einen anderen Executor wie den 'ThreadPoolTaskExecutor' und setzen Sie die Eigenschaft' waitForTasksToCompleteOnShutdown' auf 'true'. –

Antwort

0

Dank @ M.Deinum, fand ich heraus, wie das Problem zu vermeiden:

ein ThreadPoolTaskExecutor (statt SimpleAsyncTaskExecutor) Verwendung und es ist awaitTerminationSeconds Eigenschaft in Kombination mit waitForTasksToCompleteOnShutdown Satz true Behebungen meines Problem zu setzen.

Vom JavaDoc von setAwaitTerminationSeconds:

Stellen Sie die maximale Anzahl von Sekunden, dass dieser Executor Block beim Herunterfahren, um verbleibenden Aufgaben warten sollte deren Ausführung vor dem Rest des Behälters zu vervollständigen fährt fort, zu schließen. Dies ist besonders nützlich, wenn Ihre verbleibenden Aufgaben wahrscheinlich Zugriff auf andere Ressourcen benötigen, die ebenfalls vom Container verwaltet werden.

Dies ist die genaue Beschreibung und Lösung für mein Problem.

Verwandte Themen