Запуск задания только один раз с использованием кварца - PullRequest
6 голосов
/ 26 апреля 2010

Есть ли способ запустить задание только один раз, используя Quartz в Java? Я понимаю, что в этом случае нет смысла использовать Кварц. Но дело в том, что у меня есть несколько заданий, и они запускаются несколько раз. Итак, я использую Кварц.

Возможно ли это вообще?

Ответы [ 7 ]

12 голосов
/ 27 апреля 2010

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

4 голосов
/ 14 октября 2016

Да, это возможно!

JobKey jobKey = new JobKey("testJob");
JobDetail job = newJob(TestJob.class)
            .withIdentity(jobKey)
            .storeDurably()
            .build();
scheduler.addJob(job, true);
scheduler.triggerJob(jobKey); //trigger a job inmediately
3 голосов
/ 07 октября 2015

Вот пример того, как немедленно запустить класс TestJob с Quartz 2.x :

public JobKey runJob(String jobName)
{
    // if you don't call startAt() then the current time (immediately) is assumed.
    Trigger runOnceTrigger = TriggerBuilder.newTrigger().build();
    JobKey jobKey = new JobKey(jobName);
    JobDetail job = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
    scheduler.scheduleJob(job, runOnceTrigger);
    return jobKey;
}

см. Также Руководства по планированию заданий Quartz Enterprise & rarr; SimpleTriggers

3 голосов
/ 13 июня 2012

В кварце> 2.0 вы можете заставить планировщик отменять планирование любой работы после выполнения работы:

@Override
protected void execute(JobExecutionContext context)
            throws JobExecutionException {
    ...
    // process execution
    ...
    context.getScheduler().unscheduleJob(triggerKey);
    ...
}

где triggerKey - идентификатор задания, которое нужно запустить только один раз. После этого работа больше не будет называться.

2 голосов
/ 22 марта 2015

Я не уверен, насколько похож Quartz в Mono и Java, но, похоже, работает в .Net

TriggerBuilder.Create ()
        .StartNow ()
        .Build (); 
1 голос
/ 22 февраля 2019

Мне пришлось спросить себя, имеет ли смысл пытаться настроить задание и добавить проверки, если оно уже было выполнено, как это было предложено в ответе Марко Лахмы (поскольку планирование запуска задания один раз приводит к тому, что оно запускается один раз, каждый раз мы запускаем приложение). Я нашел примеры приложений CommandLineRunner, которые у меня не совсем работали, в основном потому, что у нас уже был ApplicationRunner, который использовался для других заданий, использующих Quartz scheduling / cron. Я не был доволен тем, что Quartz инициализировал эту работу с помощью SimpleTrigger, поэтому мне пришлось искать что-то еще.

Используя некоторые идеи из следующих статей:

Мне удалось собрать воедино работающую реализацию, которая позволяет мне делать следующее:

  • запускать существующие задания через Quartz, по таймеру
  • запускать новое задание, один раз программно (одноразовое задание Quartz с использованием SimpleTrigger не удовлетворяло моим требованиям, так как оно будет запускаться один раз при каждой загрузке приложения)

Я придумал следующий класс CommandLineRunner:

public class BatchCommandLineRunner implements CommandLineRunner {

@Autowired
private Scheduler scheduler;

private static final Logger LOGGER = LoggerFactory.getLogger(BatchCommandLineRunner.class);

public void run(final String... args) throws SchedulerException {

    LOGGER.info("BatchCommandLineRunner: running with args -> " + Arrays.toString(args));

    for (final String jobName : args) {

        final JobKey jobKey = findJobKey(jobName);
        if (jobKey != null) {

            LOGGER.info("Triggering job for: " + jobName);
            scheduler.triggerJob(jobKey);

        } else {

            LOGGER.info("No job found for jobName: " + jobName);
        }

    }
}

private JobKey findJobKey(final String jobNameToFind) throws SchedulerException {

    for (final JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals("DEFAULT"))) {

        final String jobName = jobKey.getName();

        if (jobName.equals(jobNameToFind)) {

            return jobKey;
        }
    }
    return null;
}
}

В одном из моих классов конфигурации я добавил bean-компонент CommandLineRunner, который вызывает созданный мной пользовательский CommandLineRunner:

@Configuration
public class BatchConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(BatchConfiguration.class);

    @Bean
    public BatchCommandLineRunner batchCommandLineRunner() {

        return new BatchCommandLineRunner();
    }

    @Bean
    public CommandLineRunner runCommandLineArgs(final ApplicationArguments applicationArguments) throws Exception {

        final List<String> jobNames = applicationArguments.getOptionValues("jobName");

        LOGGER.info("runCommandLineArgs: running the following jobs -> " + ArrayUtils.toString(jobNames));

        batchCommandLineRunner().run(jobNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));

        return null;
    }
}

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

Наконец, я могу назвать это так:

java -jar <your_application>.jar --jobName=<QuartzRegisteredJobDetailFactoryBean>

В результате задание инициализируется только при его вызове и исключается из моих триггеров CronTriggerFactoryBean, которые я использовал для других своих заданий.

Здесь делается несколько предположений, поэтому я попытаюсь обобщить:

  • задание должно быть зарегистрировано как JobDetailFactoryBean (например: scheduler.setJobDetails(...))
  • все по сути то же самое, что и работа с CronTriggerFactoryBean, за исключением отсутствующего scheduler.setTriggers(...) вызова
  • Spring знает, как выполнять классы CommandLineRunner после загрузки приложения
  • Я жестко закодировал параметр, передаваемый в приложение, в "jobName"
  • Я принял название группы "DEFAULT" для всех заданий; если вы хотите использовать разные группы, это нужно будет отрегулировать при получении JobKey, который используется для фактического запуска задания
  • нет ничего, что мешало бы запускать это задание несколько раз через CLI, но оно запускалось при каждой загрузке приложения с использованием подхода SimpleTrigger, так что это лучше для меня; если это неприемлемо, возможно, использование StepListener, ExitStatus и т. д. может помешать его выполнению дважды
0 голосов
/ 26 октября 2018

Другое решение: в SimpleSchedulerBuilder есть метод .withRepeatCount(0):

public final int TEN_SECONDS = 10;
Trigger trigger = newTrigger()
    .withIdentity("myJob", "myJobGroup")
    .startAt(new Date(System.currentMillis()+TEN_SECONDS*1000)
    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
      .withRepeatCount(0)
      .withIntervalInMinutes(1))
    .build();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...