Можно ли использовать Spring Retry с Spring Batch FlatFileItemReader

У меня есть следующие 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);
    }
}

Читаемый файл (т. Е. loadFile) может быть, а может и не быть доступен во время выполнения задания. Если файл недоступен, я хочу, чтобы читатель проспал ~ 30 минут, а затем снова попытался открыть файл. Если после пяти попыток файл не найден, он может потерпеть неудачу, как обычно, путем выброса ItemStreamException.

К сожалению, приведенный выше код не пытается повторить попытку открытия файла. Он выдает ItemStreamException при первом вызове открытия и не пытается открыть повторно.

Может кто-нибудь объяснить, как это сделать? Примечание. У меня есть @EnableRetry в классе SpringBootApplication.


person James    schedule 09.08.2016    source источник


Ответы (2)


Этот работает. Я внес небольшие изменения, потому что не знаю ваших классов.

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

Когда вы выполняете и файл есть, вы видите в журналах одно сообщение «Попытка чтения» и одно сообщение «Содержимое файла». Я даже добавил туда пустые строки, так что сейчас это трудно не заметить.

Если файл не существует, вы увидите пять сообщений «Попытка чтения», а затем возникнет исключение.

Я изменил время повтора на 5 секунд. Если вы достаточно быстры, вы можете начать без файла, а затем создать там какой-нибудь файл, и вы увидите, что он работает. Вы должны увидеть несколько попыток чтения и, наконец, содержимое файла.

Я вижу, вы уже несколько дней боретесь с этой проблемой. Пожалуйста, не создавайте лишних вопросов, так как они не помогают сообществу. В будущем постарайтесь придерживаться одного вопроса, изменив его, если возникнет необходимость.

person wst    schedule 10.08.2016
comment
Я также могу заставить Spring Retry работать за пределами FlatFileItemReader Spring Batch. В OP я спрашиваю, как заставить это работать в FlatFileItemReader Spring Batch. - person James; 10.08.2016

Переход с Spring Boot версии 1.3.1.RELEASE на 1.4.0.RELEASE (и соответствующих им автоматически версионных зависимостей, таких как spring-boot-starter-batch) решил проблему. Retry работает в 1.4.0.RELEASE, как это реализовано в OP. Не работает в 1.3.1.RELEASE. Вот файл Gradle, который сейчас используется:

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

Примечание. Возможно использование JobExecutionDecider , чтобы повторить шаг, используя FlatFileItemReader. Однако ItemStreamException приводит к завершению всего задания и приложения без возможности выполнения решающим устройством.

person James    schedule 10.08.2016