ошибки, возникающие во время весеннего пакетного планирования

Привет, ребята, я работаю над весенним пакетом с планированием (используя триггер cron), он работает, но со следующими ошибками:

  • давайте предположим, что значение cron запускает пакет каждые 10 секунд, когда я запускаю первый и после, например, 3 секунды, я запускаю еще один, spring не будет знать о промежутке в 3 секунды, и он запустит их оба, как я запустили их одновременно

вот мой код

это класс работы, которую я запущу

@Component
public class JobThread implements Runnable {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    @Lazy
    private Job job;

    public JobParameters jobParameters;

    private Logger log = Logger.getLogger(JobThread.class);

    public synchronized void runBatch() {

        jobParameters = new JobParametersBuilder().addLong("LaunchTime", System.currentTimeMillis())
                .addString("TenantID", BatchController.getCurrentTenant().get()).toJobParameters();

        try {
            JobExecution jobExecution = jobLauncher.run(job, jobParameters);
            log.info("Job's Status:::" + jobExecution.getStatus());
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
                | JobParametersInvalidException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        this.runBatch();

    }

}

контроллер, который будет вызывать задание

@RestController
@RequestMapping("tenant/batch")
public class BatchController {

    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    @Autowired
    private JobThread jobThread;

    private static ThreadLocal<String> currentTenant;

    @PostMapping("/schedule")
    public void setBatch(@RequestBody BatchBean cron) {

        currentTenant = new ThreadLocal<String>() {
            @Override
            protected String initialValue() {
                new TenantContext();
                return TenantContext.getCurrentTenant();
            }
        };

        //cron = "*/10 * * * * *";


        taskScheduler.schedule(taskExecutor.createThread(jobThread), new CronTrigger(cron.getCron()));

    }

Я надеюсь, что я был достаточно ясен. Спасибо заранее.


person Amine Ben Mansour    schedule 31.03.2020    source источник
comment
Ваш код ошибочен и опасен. вы сохраняете состояние в синглтонах и перезаписываете это состояние, никогда этого не делайте. Не воссоздавай свой ThreadLocal и не воссоздавай свой JobParamaters. Только последний останется. Так что это опасно. Также вы должны программировать интерфейсы, а не конкретные реализации. Создавать поток для исполняемого файла не нужно, так как ваш JobThread уже является Runnable.   -  person M. Deinum    schedule 31.03.2020


Ответы (1)


Проблема в том, что ваш код не является потокобезопасным и, следовательно, потенциально опасным. Также ваш ThreadLocal не будет работать, так как задание будет выполняться в другом потоке, и у него не будет доступа к ThreadLocal.

  1. Не пересоздавайте свой ThreadLocal в контроллере. Определите это один раз и оставьте так.
  2. Ваш JobThread - это синглтон, который сохраняет состояние (параметры), поэтому останется только последний.
  3. Программа для интерфейсов TaskScheduler вместо конкретных реализаций
  4. Не создавайте тему, так как ваш JobThread уже Runnable.
  5. Вместо того, чтобы ваш JobThread был одноэлементным, создайте новый по мере необходимости и передайте требуемые параметры.

Ваш JobThread должен выглядеть примерно так.

public class JobThread implements Runnable {

    private final Logger log = Logger.getLogger(JobThread.class);
    private final JobLauncher jobLauncher;
    private final Job job;
    private final String tenant;

    public JobThread(JobLauncher launcher, Job job, String tenant) {
      this.jobLauncher=launcher;
      this.job=job;
      this.tenant=tenant;
    }

    @Override
    public void run() {

        JobParameters jobParameters = new JobParametersBuilder()
                          .addLong("LaunchTime", System.currentTimeMillis())
                          .addString("TenantID", tenant);

        try {
            JobExecution jobExecution = jobLauncher.run(job, jobParameters);
            log.info("Job's Status:::" + jobExecution.getStatus());
        } catch (JobExecutionException e) {
            log.error(e.getMessage(), e);
        }
    }
}

Затем в вашем контроллере введите необходимые JobLauncer и Job. При необходимости создайте новый JobThread и передайте необходимую информацию.

@RestController
@RequestMapping("tenant/batch")
public class BatchController {

    @Autowired
    private TaskScheduler taskScheduler;
    @Autowired
    private JobLauncher jobLauncher;
    @Autowired
    @Lazy
    private Job job;

    @PostMapping("/schedule")
    public void setBatch(@RequestBody BatchBean cron) {

        //cron = "*/10 * * * * *";
        String tenant = TenantContext.getCurrentTenant();
        JobThread task = new JobThread(this.jobLauncher, this.job, tenant);        
        taskScheduler.schedule(task, new CronTrigger(cron.getCron()));
    }

И наконец, точность System.currentTimeMillis может отличаться в вашей ОС/Системе/Архитектуре. См. javadoc указанный метод.

person M. Deinum    schedule 31.03.2020
comment
Спасибо, сэр, за ваш ответ и за ваши заметки - person Amine Ben Mansour; 01.04.2020