【发布时间】:2011-02-12 05:23:58
【问题描述】:
有没有一种方法可以让我在 Java 中使用 Quartz 只运行一次作业?我知道在这种情况下使用 Quartz 是没有意义的。但是,问题是,我有多个工作并且它们运行多次。所以,我正在使用 Quartz。
这可能吗?
【问题讨论】:
标签: java quartz-scheduler
有没有一种方法可以让我在 Java 中使用 Quartz 只运行一次作业?我知道在这种情况下使用 Quartz 是没有意义的。但是,问题是,我有多个工作并且它们运行多次。所以,我正在使用 Quartz。
这可能吗?
【问题讨论】:
标签: java quartz-scheduler
您应该使用在特定时间触发且不重复的 SimpleTrigger。 TriggerUtils 有很多方便的方法来创建这些东西。
【讨论】:
是的,有可能!
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
【讨论】:
在quartz > 2.0中,你可以让调度器在工作完成后取消调度任何工作:
@Override
protected void execute(JobExecutionContext context)
throws JobExecutionException {
...
// process execution
...
context.getScheduler().unscheduleJob(triggerKey);
...
}
其中 triggerKey 是只运行一次的作业的 ID。在此之后,该作业将不再被调用。
【讨论】:
这是一个如何使用 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 Tutorials → SimpleTriggers
【讨论】:
我不确定 Mono 和 Java 中的 Quartz 有多少相似之处,但这似乎在 .Net 中有效
TriggerBuilder.Create ()
.StartNow ()
.Build ();
【讨论】:
我不得不问自己,尝试配置作业并添加检查是否已按照 Marko Lahma 的回答中的建议运行是否有意义(因为安排作业运行一次会导致它每次运行一次我们启动应用程序)。我发现了一些对我来说不太适用的 CommandLineRunner 应用程序示例,主要是因为我们已经有一个 ApplicationRunner 用于其他使用 Quartz 调度/cron 的作业。我对让 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;
}
}
在我的一个配置类中,我添加了一个 CommandLineRunner 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 触发器之外。
这里有几个假设,所以我会尝试总结一下:
scheduler.setJobDetails(...))scheduler.setTriggers(...) 调用之外,一切都与使用 CronTriggerFactoryBean 的作业基本相同【讨论】:
另一种解决方案: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();
【讨论】: