Длинная проблема параллелизма l oop с доступом к БД, откатом и бесконечными транзакциями - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть часть программного обеспечения, которая предназначена для проверки изменения статуса задач в сторонней системе, а затем загружает их в БД.

Один запуск выглядит так, как будто каждая операция является новой 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 или создать тайм-аут планировщика, чтобы при превышении тайм-аута она фиксировала каждую операцию и метод выхода?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...