обнаружение ошибок во время весеннего пакетного планирования - PullRequest
0 голосов
/ 31 марта 2020

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

  • давайте предположим, что значение cron запускает пакет каждые 10 секунд , когда я запускаю первую и после, например, 3 секунд, запускаю другую, пружина не будет знать о промежутке в 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()));

    }

Я надеюсь, что я достаточно ясен Заранее спасибо

1 Ответ

2 голосов
/ 31 марта 2020

Проблема в том, что ваш код не ориентирован на многопоточность и поэтому потенциально опасен. Также ваш 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 может отличаться в вашей ОС / системе / архитектуре. См. javado c указанного метода.

...