简体   繁体   中英

Can Spring Retry be used with Spring Batch FlatFileItemReader

I have the following ItemReader :

import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class MyReader extends FlatFileItemReader<Holding> {

    @Autowired
    public MyReader(LineMapper<Holding> lineMapper, File loadFile) {
        setResource(new FileSystemResource(loadFile));
        final int NUMBER_OF_HEADER_LINES = 1;
        setLinesToSkip(NUMBER_OF_HEADER_LINES);
        setLineMapper(lineMapper);
    }

    @Override
    @Retryable(value=ItemStreamException.class, maxAttempts=5,  backoff=@Backoff(delay=1800000))
    public void open(ExecutionContext executionContext) throws ItemStreamException {
                super.open(executionContext);
    }
}

The file to be read (ie loadFile ) may or may not be available when running the job. If the file is not available, I want the reader to sleep ~30 minutes and then retry opening the file. If after five attempts, the file is not found it can fail as it normally would by throwing ItemStreamException .

Unfortunately, the above code does not attempt to retry opening the file. It throws ItemStreamException on the first call to open and does not retry open.

Can someone please explain how to do this? Note: I do have @EnableRetry on the SpringBootApplication class.

This one works. I made some small changes because I don't know your classes.

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath(
                "org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE",
        )
    }
}

apply plugin: 'java'
apply plugin: 'spring-boot'

tasks.withType(JavaCompile) {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

repositories {
    mavenCentral()
}

springBoot {
    mainClass = "test.MyReader"
}

dependencies {
    compile(
            'org.springframework.boot:spring-boot-starter',
            'org.springframework.boot:spring-boot-starter-aop',
            'org.springframework.retry:spring-retry',
    )
}

MyApplication.java

@EnableRetry
@SpringBootApplication
public class MyApplication implements CommandLineRunner {
    private final MyReader myReader;

    @Autowired
    public MyApplication(MyReader myReader) {
        this.myReader = myReader;
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        myReader.read();
    }
}

MyReader.java

@Service
public class MyReader {
    private static final String PATH = "a2";
    private final Logger logger = LoggerFactory.getLogger(MyReader.class);

    public MyReader() {

    }

    @Retryable(value = IOException.class, maxAttempts = 5, backoff = @Backoff(delay = 5000))
    public void read() throws IOException {
        final Resource resource = new FileSystemResource(PATH);
        logger.info("\n\nRead attempt: {}\n", resource);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
            final String content = reader.lines().collect(Collectors.joining(" "));
            logger.info("\n\nFile content: {}\n", content);
        }
    }
}

When you execute and file is there, you see in logs one "Read attempt" message and one "File content" message. I even added empty lines in there so it's hard to overlook now.

When file does not exists you will see five "Read attempt" messages and then exception thrown.

I changed retry time to 5 seconds. If you are fast enough you can start without file and then make some file in there and you will see it works. You should see couple of read attempts and finally the file content.

I can see you are struggling for couple of days with this issue already. Please do not spawn unnecessary questions, as they are not helping the community. For the future reference, try to stick to your one question, modifying it if need arises.

Moving from Spring Boot version 1.3.1.RELEASE to 1.4.0.RELEASE (and its corresponding auto versioned dependencies such as spring-boot-starter-batch ) resolved the issue. Retry works in 1.4.0.RELEASE as implemented in the OP. Does not work in 1.3.1.RELEASE. Here's the gradle file that is now being used:

buildscript {
    ext {
        // Previously using 1.3.1.RELEASE where retry functionality does not work
        springBootVersion = '1.4.0.RELEASE' 
    }
    repositories {
        mavenCentral()
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'

configurations {
   provided
}

sourceSets {
    main {
        compileClasspath += configurations.provided
    }
}

jar {
    baseName = 'load'
    version = '1.0'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-batch')
    compile('org.springframework.boot:spring-boot-configuration-processor')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-mail')
    compile('org.springframework.boot:spring-boot-starter-aop')
    compile('org.projectlombok:lombok:1.16.6')
    compile('org.hibernate:hibernate-validator:5.2.4.Final')
    compile('org.quartz-scheduler:quartz:2.2.3')
    runtime('javax.el:javax.el-api:2.2.4')
    runtime('org.glassfish.web:javax.el:2.2.4')
    runtime('net.sourceforge.jtds:jtds:1.3.1')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('org.springframework.batch:spring-batch-test')
}



eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.11'
} 

Note: Considered using JobExecutionDecider to retry step using the FlatFileItemReader . However, the ItemStreamException causes the entire job and application to terminate without the decider getting a chance to execute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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