Spring batch Spring boot-如何按照计划重新启动作业

Spring batch Spring boot-如何按照计划重新启动作业,spring-batch,spring-boot,Spring Batch,Spring Boot,我正在使用spring-batch-2.2.5开发spring启动应用程序一个简单的应用程序-从数据库读取项目并写入文件。我在运行应用程序时遇到两个问题: 作业一次运行正常,但第二次(在60秒的固定延迟后)似乎运行正常,但表示步骤状态已完成 第二个问题是,我随机得到WriterNotOpenException:Writer必须打开才能写入。这种情况发生在第一次跑步时。一些项目已经写入,但随后发生异常 在org.springframework.batch.item.file.FlatFileIte

我正在使用spring-batch-2.2.5开发spring启动应用程序一个简单的应用程序-从数据库读取项目并写入文件。我在运行应用程序时遇到两个问题:

  • 作业一次运行正常,但第二次(在60秒的固定延迟后)似乎运行正常,但表示步骤状态已完成

  • 第二个问题是,我随机得到WriterNotOpenException:Writer必须打开才能写入。这种情况发生在第一次跑步时。一些项目已经写入,但随后发生异常

    在org.springframework.batch.item.file.FlatFileItemWriter.write(FlatFileItemWriter.java:255)~[spring-batch-infrastructure-2.2.5.RELEASE.jar:na] 在org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)~[spring-batch-core-2.2.5.RELEASE.jar:na] 在org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)~[spring-batch-core-2.2.5.RELEASE.jar:na] 在org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)~[spring-batch-core-2.2.5.RELEASE.jar:na]

  • 我确保JobParameters在每次运行时都有一个新的时间戳,但这似乎没有帮助

    代码如下:

        public ItemReader<DomainClass> reader() {
        ArrayList<DomainClass> records = service.findrecords()
        return new IteratorItemReader<DomainClass>(records)
    }
    
    @Bean
    public ItemProcessor<DomainClass, DomainClass> processor() {
        return new MyItemProcessor()
    }
    
    @Bean
    public FlatFileItemWriter<DomainClass> writer() {
        FlatFileItemWriter flatFileItemWriter = new FlatFileItemWriter()
            DelimitedLineAggregator t = new DelimitedLineAggregator(delimiter: ',')
                t.setFieldExtractor(new BeanWrapperFieldExtractor(names: ["id", "description", "type", "date"]))
            flatFileItemWriter.setLineAggregator(t)
            flatFileItemWriter.setResource(new FileSystemResource('output.txt'))
        return flatFileItemWriter
    }
    
    @Bean
    public Job  myJob(JobBuilderFactory jobs, Step s1) {
        Job job = jobs.get("myJob")
            .incrementer(new RunIdIncrementer())
            .flow(s1).end().
            .build()
    
        return job
    }
    
    @Bean
    public Step step1(StepBuilderFactory stepBuilderFactory, ItemReader<DomainClass> reader,
                                        ItemWriter<DomainClass> writer, ItemProcessor<DomainClass, DomainClass> processor) {
        logger.info "creating step1"
        return stepBuilderFactory.get("step1")
            .<DomainClass, DomainClass> chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
    }
    
    查看spring启动跟踪,似乎有两个线程正在尝试启动(main和pool-3-thread-1)。。不确定这是否也是一个问题:

    18:17:46.441 [pool-3-thread-1] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [FlowJob: [name=myJob]] launched with the following parameters: [{time=1397603866386}]
    18:17:46.463 [main] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [FlowJob: [name=myJob]] launched with the following parameters: [{run.id=2}]
    

    这里可能有3个问题,所以把它们分开可能会有帮助。我可以在这里把问题回复给你,以节省评论空间

    • 您在两个线程中有两个执行,因为一个来自
      @Scheduled
      执行(我根据线程ID猜测),另一个来自Spring Boot中实现的“启动单个作业”规则(您可以关闭该规则-请参阅,例如,设置“Spring.batch.job.enabled=false”)

    • 您似乎对第二次执行成功完成感到惊讶,但没有说明原因。这是个问题吗

    • 如果您的进程将要执行并发作业(看起来可能是),您应该使您的有状态组件
      @StepScope
      。基于异常,条目编写器看起来是一个很好的候选对象


    谢谢@Dave,我把它放在一起是因为,我认为它们是相互关联的。添加标志修复了问题1和3。但是,我很惊讶第二次执行成功完成。我需要再次运行相同的作业,因为处理的记录可能不同。进程不需要是并发的,因为现在如果我一次处理一条记录,这就足够了。为了安全起见,我认为您应该添加
    @StepScope
    。完成这份工作让你感到惊讶的是什么?我觉得这很正常。添加@StepScope就可以了。我很惊讶(相当不理解为什么),itemreader没有检索新记录,作业开始了,然后报告的步骤完成了。将StepScope添加到ItemReader工作!谢谢你,戴夫!如果它是有状态的,那么它仍然有第一次执行的内存,因此它可能认为它已经完成了所有输入记录的读取。
    18:17:46.441 [pool-3-thread-1] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [FlowJob: [name=myJob]] launched with the following parameters: [{time=1397603866386}]
    18:17:46.463 [main] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [FlowJob: [name=myJob]] launched with the following parameters: [{run.id=2}]