Spring批处理长时间运行的tasklet数据库超时

如何解决Spring批处理长时间运行的tasklet数据库超时

鉴于我的工作流作业有此 Spring Batch 配置,并且我正在将 sql Server 数据库用于我的 Spring Batch 表:

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() 抛出运行时异常,我的步骤状态为 UNKNowN,应用程序退出并出现异常:

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 server db 连接超时并关闭,并且 spring 批处理无法执行回滚和 db 更新。理想情况下,我希望状态为 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

有没有办法解决这个问题?如果我要从 tasklet 移动到面向块并在 ItemReader 的 read() 方法中执行轮询逻辑怎么办?

解决方法

你的想法是正确的。当提交失败时,Spring Batch 无法正确更新以 UNKNOWN 而不是 FAILED 结尾的步骤状态。这里有一个未解决的问题:https://github.com/spring-projects/spring-batch/issues/1826。虽然您的例外情况不同,但问题是相同的。我曾尝试在此处解决此问题:https://github.com/spring-projects/spring-batch/pull/591 但我决定放弃它(您可以在该 PR 中找到有关原因的更多详细信息)。

要解决此问题,您需要确保在 tasklet 中处理任何(运行时)异常(或在面向块的步骤的情况下在项目编写器中)。在您的情况下,您可以增加事务的超时时间并在 tasklet 中捕获运行时异常(您可以将其包装在一个有意义的异常中,您可以从 tasklet 重新抛出该异常以使其失败)。

编辑:添加增加事务超时的示例

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



版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?