1. Quartz
Task scheduler module using Quartz.
1.1. Usage
1) Add the dependency:
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-quartz</artifactId>
<version>3.5.5</version>
</dependency>
2) Install Quartz. Add SampleJob:
import io.jooby.quartz.QuartzModule;
{
install(new QuartzModule(SampleJob.class));
}
3) Creates SampleJob:
import io.quartz.Scheduled;
import org.quartz.Job;
public class SampleJob implements Job { (1)
@Scheduled("1m") (2)
public void execute(JobExecutionContext ctx) {
...
}
}
1 | Implements org.quartz.Job |
2 | Creates a trigger using the Scheduled annotation |
1.2. Jobs
A Job must implements org.quartz.Job
interface or org.quartz.InterruptableJob
as described in
Quartz documentation or if you prefer just annotates
an arbitrary method with the Scheduled annotation:
import io.quartz.Scheduled;
public class SampleJob {
@Scheduled("1m")
public void everyMinute() {
...
}
}
Jooby generates a job key using the class and method names:
-
SampleJob.everyMinute ⇒ group:
SampleJob
, name:everyMinute
This approach allows you to define multiple job methods:
import io.quartz.Scheduled;
public class SampleJob {
@Scheduled("1m")
public void everyMinute() {
...
}
@Scheduled("1h")
public void everyHour() {
...
}
}
A job method must follow these rules:
-
Must be a public method
-
Possible arguments: none (zero),
JobExecutionContext
orAtomicBoolean
. The atomic boolean is used to notify job method about interruption requests.
1.2.1. Job Factory
Job classes are required to have a default constructor (public and without arguments). For more complex uses cases when the job is required to interact with other application services you have two options:
-
Creates your own JobFactory
-
Uses a dependency injection module, like Guice
Here is an example and reflection-free JobFactory implementation:
{
Scheduler scheduler = QuartzModule.newScheduler(this);
scheduler.setJobFactory((bundle, sch) -> {
Class jobClass = bundle.getJobDetail().getJobClass();
if (jobClass == MyJob.class) {
return new MyJob(...);
}
});
install(new QuartzModule(MyJob.class));
}
This other example uses Guice as dependency provider:
import jakarta.inject.Inject;
{
install(new GuiceModule());
install(new QuartzModule(MyJob.class));
}
public class MyJob {
@Inject
public MyJob(SomeService someService) {
this.someService = someService;
}
}
1.3. Triggers
The Scheduled annotation supports simple and cron triggers as well as property references:
@Scheduled("1h")
@Scheduled("1h; repeat=3")
@Scheduled("1h; delay=5m")
@Scheduled("0 0/5 * * * ?")
@Scheduled("10 0/5 * * * ?")
@Scheduled("myjob.trigger")
The myjob.trigger
must be defined in your application property file. It could be a cron or simple
expression.
1.4. Jdbc JobStore
Quartz module uses a RAMStore
by default. To store job into database you need follow these steps:
1) Add the dependency:
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-hikari</artifactId>
<version>3.5.5</version>
</dependency>
2) Install Hikari and Quartz
import io.jooby.hikari.HikariModule;
import io.jooby.quartz.QuartzModule;
{
install(new HikariModule());
install(new QuartzModule(SampleJob.class));
}
3) Set database properties and jdbc store
db.url = "jdbc:mysql://localhost/mydb"
db.user = "myuser"
db.password = "mypassword"
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
1.5. Configuration
Configuration from properties files is fully supported, just need to add quartz properties to your application configuration file:
# Set number of threads to use, default is to use the number of available processor
org.quartz.threadPool.threadCount = 2
Checkout the Quartz configuration section to see a list of all available configuration properties.
Programmatic configuration is supported by providing your own Scheduler
:
{
Scheduler scheduler = QuartzModule.newScheduler(this);
// configure scheduler as you need it
install(new QuartzModule(scheduler, SampleJob.class));
}
1.5.1. Disable Jobs at Startup
Another nice feature of Quartz module is the ability to turn on/off jobs at start-up time. The turn on/off job is implementing by pausing (job off) and then resume (job ob) operations of scheduler.
org.quartz.jobs.SampleJob.execute.enabled = false
Now the job SampleJob.execute
will be paused at startup time.
1.6. REST API
This modules comes with a simple REST API (sort of) to manage job and triggers:
import io.jooby.quartz.QuartzApp
import io.jooby.quartz.QuartzModule;
{
install(new QuartzModule(SampleJob.class));
use("/scheduler", new QuartzApp());
}
The API supports all these operations:
GET /
GET /{group}/{name}
GET /{group}/{name}/trigger
Query parameters are added as JobDataMap parameters
GET /{group}/{name}/interrupt
As described in Quartz documentation it is a Job responsibility to decide when and how to abort an existing execution. So this operation all it is does is to call InterruptableJob.interrupt
method to notify about interrupt requests.
GET /{group}/{name}/pause
This operation doesn’t interrupt an existing running job, just pause future executions.
GET /{group}/{name}/resume
DELETE /{group}/{name}