У меня есть часть программного обеспечения, которая предназначена для проверки изменения статуса задач в сторонней системе, а затем загружает их в БД.
Один запуск выглядит так, как будто каждая операция является новой API Call
со случайным и долгая задержка (зависит от длины ответа):
- задача выполнена? -> Получить список подзадач -> для каждой подзадачи -> получить отчет
Проблема заключается в том, что иногда случается, что большое количество задач (> 30) завершается одновременно. Длительные задержки делают l oop последним вечно и заканчиваются:
2020-02-03 10:45:02.789 ERROR 1 --- [taskScheduler-2] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task
org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:753) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:712) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:631) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99) ~[spring-tx-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at io.mixeway.plugins.taskclient.scheduler.TaskScheduler$$EnhancerBySpringCGLIB$$eae5ab98.checkScanStatus(<generated>) ~[classes!/:0.9]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_232]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_232]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_232]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_232]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_232]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_232]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_232]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_232]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_232]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_232]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_232]
откатом каждого изменения, сделанного для числа загруженных задач. мой планировщик выглядит так:
@Scheduled(initialDelay=0,fixedDelay = 3000)
public void checkTaskStatus(){
List<Task> nsl = taskRepository.findByRunning(true);
try {
for (Task ns : nsl) {
if (taskApiCient.isTaskDone(ns)) {
taskApiCient.loadTask(ns);
ns.setRunning(false);
taskRepository.save(ns);
log.info("Loaded result for task of {}",ns.getName());
}
}
} catch (Exception ce){
log.debug("Connection refused for one of tasks {}", ce.getLocalizedMessage());
}
}
метод taskApiCient.loadTask(Task task)
, как я уже сказал, может быть выполнен в течение некоторого времени, так как он выполняет много вызовов API и обрабатывает ответы.
Возможно ли создать БД зафиксировать транзакцию после каждого lo oop или создать тайм-аут планировщика, чтобы при превышении тайм-аута она фиксировала каждую операцию и метод выхода?