即使步骤完成,FlowBuilder的Spring批处理作业也会失败

即使步骤完成,FlowBuilder的Spring批处理作业也会失败,spring,spring-batch,spring-bean,Spring,Spring Batch,Spring Bean,我有一个spring批处理作业,它成功地完成了这些步骤,但将整个批处理作业状态标记为失败。这项工作有两个步骤。第一步验证输入文件并为我们正在处理的文件类型设置一个变量。这发生在Tasklet和JobExecutionDecider中。然后,流生成器决定步骤2的运行时间。随着每个步骤的完成,一切都正常运行,但整个批处理状态设置为“失败”,而不是“完成” 如果我检查表BATCH_STEP_EXECUTION中步骤的状态,请从BATCH_STEP_EXECUTION中选择*FROM BATCH_STE

我有一个spring批处理作业,它成功地完成了这些步骤,但将整个批处理作业状态标记为失败。这项工作有两个步骤。第一步验证输入文件并为我们正在处理的文件类型设置一个变量。这发生在Tasklet和JobExecutionDecider中。然后,流生成器决定步骤2的运行时间。随着每个步骤的完成,一切都正常运行,但整个批处理状态设置为“失败”,而不是“完成”

如果我检查表BATCH_STEP_EXECUTION中步骤的状态,请从BATCH_STEP_EXECUTION中选择*FROM BATCH_STEP_EXECUTION,其中JOB_EXECUTION_ID=54;我看到这两个步骤都标记为已完成

知道为什么我的整个批处理作业被认为失败了吗

这是为批次状态返回的内容:

2018-07-26 15:21:38.132信息95001-[ask-scheduler-1]o.s.b.c.l.support.SimpleJoblancher:作业:[FlowJob:[name=ImportTemployes]]已完成,参数如下: [{input.file.name=/Users/aaronradich/Dev/posthire batch/target/classes/data/import/employees.csv,time=153264366885}]和以下状态:[失败]

这是相关代码。我猜这与FlowBuilder的配置方式有关:

@Bean
protected Step step1(FlatFileItemReader reader, FileValidationTasklet fileValidationTasklet) {
    return steps.get("step1").tasklet(fileValidationTasklet)
            .build();
}

@Bean
protected Step step2(FlatFileItemReader reader, EmployeeProcessor processor, EmployeeWriter writer) {
    return steps.get("step2")
            .<Employee, Employee>chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
}

@Bean
public Job importEmployees(@Qualifier("step1") Step step1, @Qualifier("step2") Step step2) {
    JobBuilder jobBuilder = jobBuilderFactory
            .get("importEmployees")
            .incrementer(new RunIdIncrementer());

    StepDecider fileDecider = new StepDecider();

    Flow flowFile = new FlowBuilder<Flow>("fileFlow")
            .start(fileDecider)
                .on(BatchConfig.STATE_DO_FILE_1)
                    .to(step2)
                .on(BatchConfig.STATE_DO_FILE_2)
                    // TODO: Add an additional Step for File Type 2 (maybe called stepF2, etc.)
                    .to(step2)
            .from(fileDecider)
                .on(BatchConfig.STATE_SKIP_FILE)
                    .end(BatchConfig.STATE_FAILED)
                .on("*")
                    .end(BatchConfig.STATE_COMPLETED)
            .build();

    /*
     * Complete Workflow:
     * 
     *           |--> (S2)
     *  S1 ---> -+
     *           |--> (S3)
     */
    FlowJobBuilder builder = jobBuilder
            .flow(step1)
            .next(flowFile)
            .end();

    return builder.build();
}
下面是一个TaskLet,它确定文件是否有效,并在JobContext中为我们正在处理的文件类型设置一个变量:

package com.sterlingts.posthire.batch.util;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class FileValidationTasklet implements Tasklet {

    private final String FILE_HEADER_1 = "EmployeeId,SSN,FirstName,MiddleName,LastName,Suffix,MaidenName,DOB,Gender,Country,Street,AptNo,City,Region,PostalCode,PhoneDay,PhoneDayExt,PhoneEve,PhoneEveExt,Email,Account,EmployeeStatus,HireDate,StartDate,TerminateDate,DLNumber,DLRegion,LastNameOnLicense,FirstNameOnLicense,MiddleNameOnLicense,JobPosition,BillCode";
    private final String FILE_HEADER_2 = "EmployeeId,SSN,FirstName,MiddleName,LastName";

    private static final Logger log = LoggerFactory.getLogger(FileValidationTasklet.class);

    private String inputFile;
    private String fileTypeCode;

    public FileValidationTasklet() {

    }

    public FileValidationTasklet(String inputFile) {
        this.inputFile = inputFile;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {        
        System.out.println("Input file is " + inputFile);

        if (this.isValidFile()) {
            // store the FileTypeCode in the jobExecutionContext so we can access it in other steps
            chunkContext
                    .getStepContext()
                    .getStepExecution()
                    .getJobExecution()
                    .getExecutionContext()
                    .put("FileTypeCode", this.fileTypeCode);
        } else {
            throw new Exception("File '" + inputFile + "' is not a valid file format!  Aborting import!");
        } 

        // set the exit status for the Tasklet to Completed so the overall job can get completed
        //chunkContext.getStepContext().getStepExecution().setExitStatus(ExitStatus.COMPLETED);
        chunkContext.getStepContext().getStepExecution().setStatus(BatchStatus.COMPLETED);

        // tell Batch to continue on to the next step and not repeat this one
        return RepeatStatus.FINISHED;
    }

    private Boolean isValidFile() {
        Boolean validFile = false;

        BufferedReader brFile;
        try {
            brFile = new BufferedReader(new FileReader(inputFile));
            String headerRow = brFile.readLine();

            // have noticed that sometimes the leading character from the readLine is a space
            headerRow = headerRow.trim();

            // strip CR and LF just in case the file originated from Windows and still has a CR or LF after the readLine
            headerRow = headerRow.replaceAll("\r", "").replaceAll("\n", "");

            // remove the leading byte-order mark (BOM) character
            headerRow = SpringIntegrationUtils.removeUTF8BOM(headerRow);

            if (headerRow.equals(FILE_HEADER_1)) {
                this.fileTypeCode = "1";
                validFile = true;
            } else if (headerRow.equals(FILE_HEADER_2)) {
                this.fileTypeCode = "2";
                validFile = true;
            }

        } catch (FileNotFoundException e) {
            log.error("File '" + inputFile + "' was not found!  Aborting!");
        } catch (IOException e) {
            log.error("Error validating header row of file '" + inputFile + "'!");
        }

        return validFile;
    }

}

增加了2个标签。
package com.sterlingts.posthire.batch.util;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class FileValidationTasklet implements Tasklet {

    private final String FILE_HEADER_1 = "EmployeeId,SSN,FirstName,MiddleName,LastName,Suffix,MaidenName,DOB,Gender,Country,Street,AptNo,City,Region,PostalCode,PhoneDay,PhoneDayExt,PhoneEve,PhoneEveExt,Email,Account,EmployeeStatus,HireDate,StartDate,TerminateDate,DLNumber,DLRegion,LastNameOnLicense,FirstNameOnLicense,MiddleNameOnLicense,JobPosition,BillCode";
    private final String FILE_HEADER_2 = "EmployeeId,SSN,FirstName,MiddleName,LastName";

    private static final Logger log = LoggerFactory.getLogger(FileValidationTasklet.class);

    private String inputFile;
    private String fileTypeCode;

    public FileValidationTasklet() {

    }

    public FileValidationTasklet(String inputFile) {
        this.inputFile = inputFile;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {        
        System.out.println("Input file is " + inputFile);

        if (this.isValidFile()) {
            // store the FileTypeCode in the jobExecutionContext so we can access it in other steps
            chunkContext
                    .getStepContext()
                    .getStepExecution()
                    .getJobExecution()
                    .getExecutionContext()
                    .put("FileTypeCode", this.fileTypeCode);
        } else {
            throw new Exception("File '" + inputFile + "' is not a valid file format!  Aborting import!");
        } 

        // set the exit status for the Tasklet to Completed so the overall job can get completed
        //chunkContext.getStepContext().getStepExecution().setExitStatus(ExitStatus.COMPLETED);
        chunkContext.getStepContext().getStepExecution().setStatus(BatchStatus.COMPLETED);

        // tell Batch to continue on to the next step and not repeat this one
        return RepeatStatus.FINISHED;
    }

    private Boolean isValidFile() {
        Boolean validFile = false;

        BufferedReader brFile;
        try {
            brFile = new BufferedReader(new FileReader(inputFile));
            String headerRow = brFile.readLine();

            // have noticed that sometimes the leading character from the readLine is a space
            headerRow = headerRow.trim();

            // strip CR and LF just in case the file originated from Windows and still has a CR or LF after the readLine
            headerRow = headerRow.replaceAll("\r", "").replaceAll("\n", "");

            // remove the leading byte-order mark (BOM) character
            headerRow = SpringIntegrationUtils.removeUTF8BOM(headerRow);

            if (headerRow.equals(FILE_HEADER_1)) {
                this.fileTypeCode = "1";
                validFile = true;
            } else if (headerRow.equals(FILE_HEADER_2)) {
                this.fileTypeCode = "2";
                validFile = true;
            }

        } catch (FileNotFoundException e) {
            log.error("File '" + inputFile + "' was not found!  Aborting!");
        } catch (IOException e) {
            log.error("Error validating header row of file '" + inputFile + "'!");
        }

        return validFile;
    }

}