Тайм-аут базы данных с длительным запуском пакета Spring

Учитывая, что у меня есть эта конфигурация Spring Batch для моего задания рабочего процесса, и я использую базу данных Sql Server для своих весенних пакетных таблиц:

public class MyConfiguration extends AbstractConfiguration {
   
    @Bean
    @Qualifier("pollStep")
    public Step pollStep() {
        return stepBuilderFactory.get("pollStep")
                                 .tasklet(filePollingTasklet())
                                 .listener(promoteContextListener())
                                 .build();
    }

    @Bean
    @StepScope
    private Tasklet filePollingTasklet() {
        return ((stepContribution, chunkContext) -> getStatus(stepContribution, chunkContext));
    }

    private RepeatStatus getStatus(StepContribution stepContribution, ChunkContext chunkContext) {
        //some code
        Map<String, Boolean> result = poller.pollForFile(myContext, sourceInfo);
        return RepeatStatus.FINISHED;
    }

}

Мое приложение опрашивает файл на удаленном сервере. Через 100 минут, когда он не может найти файл, poller.pollForFile() выдает исключение времени выполнения, и мой статус шага НЕИЗВЕСТЕН, и приложение завершает работу с исключениями:

c.m.s.j.SQLServerException: Connection reset at 
c.m.s.j.SQLServerConnection.terminate(SQLServerConnection.java:1667) at 
c.m.s.j.SQLServerConnection.terminate(SQLServerConnection.java:1654) at 
c.m.s.j.TDSChannel.write(IOBuffer.java:1805) at c.m.s.jdbc.TDSWriter.flush(IOBuffer.java:3581) at 
c.m.s.jdbc.TDSWriter.writePacket(IOBuffer.java:3482) at 
c.m.s.jdbc.TDSWriter.endMessage(IOBuffer.java:3062) at 
c.m.s.j.TDSCommand.startResponse(IOBuffer.java:6120) at 
c.m.s.j.TDSCommand.startResponse(IOBuffer.java:6106) at 
c.m.s.j.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:1756) at 
c.m.s.j.TDSCommand.execute(IOBuffer.java:5696) at 
c.m.s.j.SQLServerConnection.executeCommand(SQLServerConnection.java:1715) at 
c.m.s.j.SQLServerConnection.connectionCommand(SQLServerConnection.java:1761) at 
c.m.s.j.SQLServerConnection.rollback(SQLServerConnection.java:1964) at 
c.z.h.p.ProxyConnection.rollback(ProxyConnection.java:375) at 
c.z.h.p.HikariProxyConnection.rollback(HikariProxyConnection.java) at 
o.h.r.j.i.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:116) ... 50 common frames omitted Wrapped by: u003c#7f0e356au003e o.h.TransactionException: Unable to rollback against JDBC Connection at ...

Я думаю, что время подключения к базе данных сервера sql истекло и закрыто, а весенний пакет не может выполнять откат и обновления базы данных. В идеале я хочу, чтобы статус был FAILED, что происходит, когда я запускаю локально с H2, но в этом случае, какую стратегию или методы я могу использовать для решения этой проблемы? В сообщении о выходе нет ошибки из-за исключения, вызванного pollForFile(), вместо этого org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is org.hibernate.TransactionException: Unable to rollback against JDBC Connectionat

Есть ли способ решить эту проблему? Что, если бы я перешел от тасклета к ориентированному на фрагменты и выполнил логику опроса в методе read() ItemReader?


person M06H    schedule 11.05.2021    source источник


Ответы (1)


Ваше мышление правильное. Когда фиксация завершается неудачно, Spring Batch не может правильно обновить статус шага, который заканчивается на UNKNOWN вместо FAILED. Здесь есть открытая проблема: https://github.com/spring-projects/spring-batch/issues/1826. Хотя ваше исключение отличается, проблема та же. У меня была попытка исправить это здесь: https://github.com/spring-projects/spring-batch/pull/591, но я решил от него отказаться (более подробно о причинах вы можете узнать в том PR).

Чтобы обойти эту проблему, вам необходимо убедиться, что любое исключение (времени выполнения) обрабатывается в тасклете (или в модуле записи элементов в случае шага, ориентированного на фрагменты). В вашем случае вы можете увеличить время ожидания вашей транзакции и поймать исключение времени выполнения в тасклете (которое вы можете обернуть значимым исключением, которое вы повторно выбрасываете из тасклета, чтобы он не работал).

РЕДАКТИРОВАТЬ: добавить пример увеличения времени ожидания транзакции

@Bean
@Qualifier("pollStep")
public Step pollStep() {
   DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
   attribute.setTimeout(60 * 100);
   // set other transaction attributes
   return stepBuilderFactory.get("pollStep")
                            .tasklet(filePollingTasklet())
                            .transactionAttribute(attribute)
                            .listener(promoteContextListener())
                            .build();
}



person Mahmoud Ben Hassine    schedule 12.05.2021
comment
если я поймаю исключение во время выполнения, как я могу не выполнить шаг? мое соединение также было сброшено в этот момент. - person M06H; 12.05.2021
comment
моя проблема больше связана со стратегией работы со сбросом соединения, когда тасклет работает в течение длительного времени. - person M06H; 12.05.2021
comment
Вам нужно увеличить время ожидания вашей транзакции, я обновил ответ. Я считаю, что обновленный ответ отвечает на ваш вопрос, по крайней мере, я дал вам текущее положение вещей и обходной путь, поэтому, пожалуйста, примите ответ: stackoverflow .com/help/someone-answers. В противном случае дайте мне знать, чего не хватает, чтобы принять ответ. Спасибо. - person Mahmoud Ben Hassine; 17.05.2021
comment
Хотя я понимаю смысл перехвата исключения во время выполнения... не знаю, как увеличить время ожидания транзакции для этого конкретного случая. - person M06H; 17.05.2021
comment
Я добавил пример в ответ. - person Mahmoud Ben Hassine; 17.05.2021
comment
Спасибо... очень полезно - person M06H; 17.05.2021
comment
это не сработало. Я добавил тайм-аут, как указано выше, к моему шагу выполнения тасклета. Тасклет использует шаблон повтора, и задача выполняется в течение 90 минут. с указанной выше настройкой тайм-аута 100 минут я все равно получаю исключение: org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is org.hibernate.TransactionException: Unable to rollback against JDBC Connection - person M06H; 19.05.2021
comment
Что ж, в этом случае ваша проблема вызвана не тайм-аутом, как вы упомянули в своем описании: I think the sql server db connection is timed out and closed and spring batch is unable to perform rollback and db updates. Вам нужно проверить, что вызывает сброс вашего соединения: c.m.s.j.SQLServerException: Connection reset at .. - person Mahmoud Ben Hassine; 19.05.2021
comment
Мне пришлось решить эту проблему, переместив логику тасклета в ItemReader и сделав это как ориентированный на фрагменты и сохранив соединение. Не идеально, но это работает на данный момент. - person M06H; 21.05.2021