仅使用Quartz运行一次作业

时间:2010-04-26 00:40:50

标签: java quartz-scheduler

有没有办法在Java中使用Quartz只运行一次作业?我知道在这种情况下使用Quartz是没有意义的。但事实是,我有多个工作,他们多次运行。所以,我正在使用Quartz。

这甚至可能吗?

7 个答案:

答案 0 :(得分:12)

您应该使用在特定时间触发而不重复的SimpleTrigger。 TriggerUtils有许多方便的方法来创建这类东西。

答案 1 :(得分:4)

是的,这是可能的!

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

答案 2 :(得分:3)

石英> 2.0,你可以让调度程序在工作完成后取消安排任何工作:

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

其中triggerKey是仅运行一次的作业的ID。在此之后,工作将不再被调用。

答案 3 :(得分:3)

以下是如何使用 Quartz 2.x 立即运行TestJob类的示例:

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 Job Scheduler TutorialsSimpleTriggers

答案 4 :(得分:2)

我不确定在Mono和Java中有多少相似的Quartz,但这似乎在.Net

TriggerBuilder.Create ()
        .StartNow ()
        .Build (); 

答案 5 :(得分:1)

我不得不问自己,尝试配置作业并添加检查是否已经按照Marko Lahma的答案中的建议进行检查是否有意义(因为将作业安排为一次运行会导致每次运行一次)我们启动应用程序)。我找到了CommandLineRunner应用程序的示例,这些示例对我而言并不十分有效,这主要是因为我们已经拥有一个ApplicationRunner,该应用程序已用于使用Quartz调度/ cron的其他作业。我对让Quartz使用SimpleTrigger初始化这项工作感到不满意,所以我不得不寻找其他东西。

使用以下文章中的一些想法:

我能够拼凑出一个可行的实现,可以执行以下操作:

  • 在计时器上通过Quartz运行现有作业
  • 以编程方式运行一次新作业(使用SimpleTrigger的单次Quartz作业不满足我的要求,因为它将在每个应用程序负载上运行一次)

我想到了以下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;
}
}

在我的一个配置类中,我添加了一个CommandLineRunner bean,该bean调用了我创建的自定义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;
    }
}

稍后,我可以通过CLI初始化这些作业,而不会影响我当前的Quartz计划作业,并且只要没有人多次通过CLI运行该命令,它就不会再运行。自从我接受ApplicationArguments之后,我必须对类型进行一些处理,然后将它们转换为String []。

最后,我可以这样称呼它:

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

结果是,仅当我调用该作业时,该作业才被初始化,并且它被我用于其他作业的CronTriggerFactoryBean触发器排除在外。

这里有几个假设,所以我尝试总结一下:

  • 该作业必须注册为JobDetailFactoryBean(例如:scheduler.setJobDetails(...)
  • 除了缺少scheduler.setTriggers(...)调用之外,所有内容基本上都与CronTriggerFactoryBean的工作相同
  • Spring知道在应用程序启动后执行CommandLineRunner类
  • 我将要传递给应用程序的参数硬编码为“ jobName”
  • 我假设所有作业的组名均为“ DEFAULT”;如果要使用不同的组,则在获取用于实际运行作业的JobKey时,需要对此进行调整
  • 没有什么可以阻止此作业通过CLI多次运行,但是它是使用SimpleTrigger方法在每个应用程序负载上触发的,因此对我来说更好;如果不可接受,也许使用StepListener和ExitStatus等可以阻止它执行两次

答案 6 :(得分:0)

另一种解决方案: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();
相关问题