简体   繁体   English

Spring 批量长时间运行tasklet数据库超时

[英]Spring batch long running tasklet database timeout

Given I have this Spring Batch configuration for my workflow job and I am using Sql Server database for my spring batch tables:鉴于我的工作流作业有这个 Spring 批处理配置,并且我正在为我的 spring 批处理表使用 Sql 服务器数据库:

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

}

My application polls for a file on remote server.我的应用程序轮询远程服务器上的文件。 After 100 mins when it can't find a file the poller.pollForFile() throws a runtime exception and my step status is UNKNOWN and the application exits with exceptions: 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 ...

I think the sql server db connection is timed out and closed and spring batch is unable to perform rollback and db updates.我认为 sql 服务器数据库连接已超时并关闭,并且 spring 批处理无法执行回滚和数据库更新。 Ideally, I want status to be FAILED which it is when I run locally with H2 but on this instance what strategy or techniques can I use to overcome this issue?理想情况下,我希望状态为 FAILED,即当我使用 H2 在本地运行时,但在这种情况下,我可以使用什么策略或技术来克服这个问题? The exit message doesnt have the error from exception thrown by pollForFile() , instead it is org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is org.hibernate.TransactionException: Unable to rollback against JDBC Connectionat退出消息没有pollForFile()抛出的异常错误,而是org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is org.hibernate.TransactionException: Unable to rollback against JDBC Connectionat org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is org.hibernate.TransactionException: Unable to rollback against JDBC Connectionat

Is there a way to fix this issue?有没有办法解决这个问题? What if I were to move from tasklet to chunk-oriented and perform the poll logic in read() method of ItemReader?如果我要从 tasklet 转移到面向块并在 ItemReader 的read()方法中执行轮询逻辑怎么办?

Your thinking is correct.你的想法是正确的。 When the commit fails, Spring Batch is unable to correctly update the step status which ends in UNKNOWN instead of FAILED .当提交失败时,Spring Batch 无法正确更新以UNKNOWN而不是FAILED结尾的步骤状态。 There is an open issue for that here: https://github.com/spring-projects/spring-batch/issues/1826 .这里有一个未解决的问题: https://github.com/spring-projects/spring-batch/issues/1826 While your exception is different, the problem is the same.虽然您的例外不同,但问题是相同的。 I had an attempt to fix that here: https://github.com/spring-projects/spring-batch/pull/591 but I decided to discard it (you can find more details about the reasons in that PR).我试图在这里解决这个问题: https://github.com/spring-projects/spring-batch/pull/591但我决定放弃它(您可以在该 PR 中找到有关原因的更多详细信息)。

To work around the issue, you need to make sure any (runtime) exception is handled in the tasklet (or in item writer in case of a chunk-oriented step).要解决此问题,您需要确保在 tasklet 中处理任何(运行时)异常(或在面向块的步骤的情况下在项目编写器中处理)。 In your case, you can increase the timeout of your transaction and catch runtime exception in the tasklet (which you can wrap in a meaningful exception that you re-throw from the tasklet to make it fail).在您的情况下,您可以增加事务的超时并在 tasklet 中捕获运行时异常(您可以将其包装在一个有意义的异常中,您可以从 tasklet 重新抛出该异常以使其失败)。

EDIT: add example of increasing transaction timeout编辑:添加增加事务超时的示例

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



声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM