[英]Running a Job only once Using Quartz
Is there a way I could run a job only once using Quartz in Java? 有没有办法在Java中使用Quartz只运行一次作业? I understand it does not make sense to use Quartz in this case. 我知道在这种情况下使用Quartz是没有意义的。 But, the thing is, I have multiple jobs and they are run multiple times. 但事实是,我有多个工作,他们多次运行。 So, I am using Quartz. 所以,我正在使用Quartz。
Is this even possible? 这甚至可能吗?
You should use SimpleTrigger that fires at specific time and without repeating. 您应该使用在特定时间触发而不重复的SimpleTrigger。 TriggerUtils has many handy methods for creating these kind of things. TriggerUtils有许多方便的方法来创建这些东西。
In quartz > 2.0, you can get the scheduler to unschedule any job after work is done: 在quartz> 2.0中,您可以让调度程序在工作完成后取消计划任何作业:
@Override
protected void execute(JobExecutionContext context)
throws JobExecutionException {
...
// process execution
...
context.getScheduler().unscheduleJob(triggerKey);
...
}
where triggerKey is the ID of the job to run only once. 其中triggerKey是仅运行一次的作业的ID。 After this, the job wouldn't be called anymore. 在此之后,不再调用该作业。
Yes, it's possible! 是的,这是可能的!
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
Here is an example of how to run a TestJob
class immediately with Quartz 2.x : 以下是如何使用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;
}
see also Quartz Enterprise Job Scheduler Tutorials → SimpleTriggers 另请参见Quartz Enterprise Job Scheduler教程 → SimpleTriggers
I'm not sure how much similar is Quartz in Mono and Java but this seems working in .Net 我不确定在Mono和Java中有多少相似的Quartz,但这似乎在.Net中有效
TriggerBuilder.Create ()
.StartNow ()
.Build ();
I had to ask myself if it made sense to try to configure a job and add checks if it had been run already as suggested in Marko Lahma's answer (since scheduling a job to run once results in it being run once, every time we start the app). 我不得不问自己是否有意义尝试配置一个工作并添加检查是否已按照Marko Lahma的回答中的建议运行(因为安排一个工作运行一次导致它运行一次,每次我们开始应用程序)。 I found examples of CommandLineRunner apps which didn't quite work for me, mostly because we already had an ApplicationRunner which was used for other jobs which use Quartz scheduling / cron. 我发现CommandLineRunner应用程序的例子并不适用于我,主要是因为我们已经有一个ApplicationRunner用于其他使用Quartz scheduling / cron的作业。 I wasn't happy with having Quartz initialize this job using a SimpleTrigger, so I had to find something else. 我不满意Quartz使用SimpleTrigger初始化这个工作,所以我必须找到别的东西。
Using some ideas from the following articles: 使用以下文章中的一些想法:
I was able to piece together a working implementation which allows me to do the following: 我能够将一个工作实现拼凑在一起,这使我可以执行以下操作:
I came up with the following CommandLineRunner class: 我想出了以下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;
}
}
In one of my configuration classes I added a CommandLineRunner bean which calls the custom CommandLineRunner I created: 在我的一个配置类中,我添加了一个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;
}
}
Later, I am able to initiate these jobs via the CLI without affecting my current Quartz scheduled jobs, and as long as no one runs the command via CLI multiple times, it will never be run again. 稍后,我可以通过CLI启动这些作业,而不会影响我当前的Quartz预定作业,只要没有人通过CLI多次运行命令,它就永远不会再运行。 I have to do some juggling of types since I accept ApplicationArguments, and then convert them into String[]. 因为我接受ApplicationArguments,然后将它们转换为String [],我必须做一些类型的杂耍。
Finally, I am able to call it like this: 最后,我可以这样称呼它:
java -jar <your_application>.jar --jobName=<QuartzRegisteredJobDetailFactoryBean>
The result is that the job is initialized only when I call it, and it is excluded from my CronTriggerFactoryBean triggers which I used for my other jobs. 结果是只有在我调用它时才初始化作业,并且它被排除在我用于其他作业的CronTriggerFactoryBean触发器之外。
There are several assumptions being made here, so I'll try to summarize: 这里有几个假设,所以我将总结一下:
scheduler.setJobDetails(...)
) 该作业必须注册为JobDetailFactoryBean(例如: scheduler.setJobDetails(...)
) scheduler.setTriggers(...)
call 一切都与CronTriggerFactoryBean的工作基本相同,除了缺少scheduler.setTriggers(...)
调用 Another solution: There is a method .withRepeatCount(0)
in SimpleSchedulerBuilder: 另一种解决方案: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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.