Нужен способ предотвратить распространение нежелательного параметра задания до следующего выполнения пакетного задания с весенней загрузкой - PullRequest
1 голос
/ 18 апреля 2019

Я запускаю пакетное приложение, используя пружинную загрузку 2.1.2 и пружинную загрузку 4.1.1. Приложение использует базу данных MySQL для источника данных метаданных Spring Batch.

Сначала я запускаю задание с помощью этой команды:

java -jar target/batchdemo-0.0.1-SNAPSHOT.jar -Dspring.batch.job.names=echo com.paypal.batch.batchdemo.BatchdemoApplication myparam1=value1 myparam2=value2

Обратите внимание, я передаю два параметра:

myparam1 = value1 myparam2 = значение2

Поскольку задание использует RunIdIncrementer, фактические параметры, используемые приложением, регистрируются как:

Задание: [SimpleJob: [name = echo]] выполнено со следующими параметрами: [{myparam2 = value2, run.id = 1, myparam1 = value1}]

Затем я снова запускаю работу, на этот раз отбрасывая myparam2:

java -jar target/batchdemo-0.0.1-SNAPSHOT.jar -Dspring.batch.job.names=echo com.paypal.batch.batchdemo.BatchdemoApplication myparam1=value1

На этот раз задание снова запускается с включенным param2:

Задание: [SimpleJob: [name = echo]] выполнено со следующими параметрами: [{myparam2 = value2, run.id = 2, myparam1 = value1}]

Это вызывает бизнес-логику, как если бы я снова передал myparam2 приложению.

Есть ли способ отбросить параметр задания и не передать его следующему экземпляру?

Код приложения:

package com.paypal.batch.batchdemo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableBatchProcessing
public class BatchdemoApplication {

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

    @Autowired
    JobBuilderFactory jobBuilder;

    @Autowired
    StepBuilderFactory stepBuilder;

    @Autowired
    ParamEchoTasklet paramEchoTasklet;

    @Bean
    public RunIdIncrementer incrementer() {
        return new RunIdIncrementer();
    }

    @Bean
    public Job job() {
        return jobBuilder.get("echo").incrementer(incrementer()).start(echoParamsStep()).build();
    }

    @Bean
    public Step echoParamsStep() {
        return stepBuilder.get("echoParams").tasklet(paramEchoTasklet).build();
    }
}

package com.paypal.batch.batchdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import org.springframework.stereotype.Component;

@Component
public class ParamEchoTasklet implements Tasklet {

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        LOGGER.info("ParamEchoTasklet BEGIN");
        chunkContext.getStepContext().getJobParameters().entrySet().stream().forEachOrdered((entry) -> {
            String key = entry.getKey();
            Object value = entry.getValue();
            LOGGER.info("Param {} = {}", key, value);
        });
        LOGGER.info("ParamEchoTasklet END");
        return RepeatStatus.FINISHED;
    }

    private Logger LOGGER = LoggerFactory.getLogger(ParamEchoTasklet.class);
}

Я отладил код весенней загрузки и загрузочный код, и вот что происходит. Строка JobParametersBuilder 273 добавляет параметры из самого последнего предыдущего экземпляра задания на карту nextParameters вместе с любыми параметрами, добавленными JobParametersIncrementer:

List<JobExecution> previousExecutions = this.jobExplorer.getJobExecutions(lastInstances.get(0));
if (previousExecutions.isEmpty()) {
    // Normally this will not happen - an instance exists with no executions
    nextParameters = incrementer.getNext(new JobParameters());
}
else {
    JobExecution previousExecution = previousExecutions.get(0);
    nextParameters = incrementer.getNext(previousExecution.getJobParameters());
}

Затем, поскольку я использую весеннюю загрузку, строка JobLauncherCommandLineRunner 213 объединяет предыдущие параметры с новыми параметрами, переданными для нового выполнения, в результате чего старый параметр передается в новое выполнение:

return merge(nextParameters, jobParameters);

Кажется невозможным снова запустить работу без параметра, если я что-то упустил. Может ли это быть ошибка в весенней партии?

1 Ответ

0 голосов
/ 01 мая 2019

Нормальное поведение для RunIdIncrementer, по-видимому, увеличивает идентификатор прогона для JobExecution и передает оставшийся предыдущий JobParameters.Я бы не назвал это ошибкой.

Имейте в виду, что идея RunIdIncrementer состоит в том, чтобы просто изменить один идентифицирующий параметр, чтобы разрешить повторное выполнение задания, даже если предыдущий запуск с тем же (прочее) параметры завершены успешно, а перезапуск не настроен.

Вы всегда можете создать настраиваемый инкремент, введя JobParametersIncrementer.

Другой альтернативой является использование JobParametersBuilder для создания объекта JobParameters, а затем используйте JobLauncher для запуска задания с этими параметрами.Я часто использую текущее системное время в миллисекундах, чтобы создать уникальность, если я запускаю задания, которые в противном случае будут иметь то же значение JobParameters.Вам, очевидно, придется выяснить логику для извлечения ваших конкретных параметров из командной строки (или где-либо еще) и перебора их для заполнения объекта JobParameters.

Пример:

public JobExecution executeJob(Job job) {
    JobExecution jobExecution = null;
    try {
        JobParameters jobParameters =
            new JobParametersBuilder()
                .addLong( "time.millis", System.currentTimeMillis(), true)
                .addString( "param1", "value1", true)
                .toJobParameters();
        jobExecution = jobLauncher.run( job, jobParameters );
    } catch ( JobInstanceAlreadyCompleteException | JobRestartException | JobParametersInvalidException | JobExecutionAlreadyRunningException e ) {
        e.printStackTrace();
    }
    return jobExecution;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...