Scheduling
Scheduling add-on provides a simple API to schedule task in Seed.
Dependency
<dependency>
<groupId>org.seedstack.addons.scheduling</groupId>
<artifactId>scheduling</artifactId>
</dependency>
Show version
dependencies {
compile("org.seedstack.addons.scheduling:scheduling:3.3.1")
}
Declarative API
Create a Class
implementing Task
and add a
@Scheduled
annotation with a cron expression.
Your task will be detected and scheduled according to the annotation content at Seed startup:
@Scheduled("0/2 * * * * ?")
public class MyTask implements Task {
@Override
public void execute() throws Exception {
return calculateSomething();
}
}
As shown in above snippet, the default «value» attribute of @Scheduled
is used for cron expression.
If any other attribute is required, the annotation becomes for instance :
@Scheduled(value = "0/2 * * * * ?", taskName = "TASK1", exceptionPolicy = UNSCHEDULE_ALL_TRIGGERS)
exceptionPolicy
defines the behaviour on Task
’s exception. Refer to @Scheduled
JavaDoc for all its attributes.
Refer to Quartz Documentation for cron expression details.
Programmatic API
Inject the ScheduledTasks
interface and programmatically define a scheduled task (not necessarily at application
startup) with the following DSL:
Cron expression
@Inject
private ScheduledTasks scheduledTasks;
...
scheduledTasks.scheduledTask(MyTask.class)
.withTaskName("usefulTask")
.withCronExpression("0/2 * * * * ?")
.schedule();
The above cron expression implicitly defines a Trigger
that will fire accordingly.
With a Trigger
When a cron expression is not enough to define the expected triggering conditions, a Quartz Trigger
can be defined:
@Inject
private ScheduledTasks scheduledTasks;
...
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("myTrigger", "myTriggerGroup"))
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever())
.startAt(DateBuilder.futureDate(2,DateBuilder.IntervalUnit.SECOND))
.build();
scheduledTasks.scheduledTask(MyTask.class)
.withTrigger(trigger)
.withPriority(10)
.schedule();
Listeners
Create a Class
implementing TaskListener
in order to listen to the Task
execution. The Task
is bound to the
TaskListener
by declaring the Task
as the Type
parameter:
public class MyTaskListener implements TaskListener<MyTask> {
@Logging
private Logger logger;
@Inject
private ScheduledTasks scheduledTasks;
@Override
public void before(SchedulingContext schedulingContext) {
logger.info("Before MyTask");
}
@Override
public void after(SchedulingContext schedulingContext) {
logger.info("After MyTask");
}
@Override
public void onException(SchedulingContext schedulingContext, Exception e) {
logger.info("Something has gone wrong, unscheduling", e);
scheduledTasks
.scheduledTask(MyTask.class)
.unschedule(schedulingContext.getTriggerName());
}
}
Keep Code In Listeners Concise And Efficient. Performing large amounts of work is discouraged, as the thread that would be executing the job (or completing the trigger and moving on to firing another job, etc.) will be tied up within the listener.
Handle Exceptions. Every listener method should contain a try-catch block that handles all possible exceptions. If a listener throws an exception, it may cause other listeners not to be notified and/or prevent the execution of the job, etc.
Exception handling
When exception occurs during the task execution, you can choose to unschedule the Task or refire it immediately. You just have add an ExceptionPolicy to the Scheduled annotation.
@Scheduled(value = "0/2 * * * * ?", exceptionPolicy = UNSCHEDULE_ALL_TRIGGERS)
ExceptionPolicy can take the following values:
REFIRE_IMMEDIATELY
: Immediately re-execute the task. This option SHOULD BE USED VERY CAREFULLY as theTask
will be fired indefinitely until successful or the application crashes.UNSCHEDULE_FIRING_TRIGGER
: Unschedule theTrigger
firing theTask
. This option is convenient when aTask
fails due to a specific trigger.UNSCHEDULE_ALL_TRIGGERS
: Unschedule all triggers associated to theTask
.NONE
: Do nothing. Default value.
You can also choose to handle exception by yourself with a TaskListener. It will be possible to use the
UNSCHEDULE_ALL_TRIGGERS
option and then reschedule the Task
public class MyTaskListener implements TaskListener<MyTask> {
@Inject
private ScheduledTasks scheduledTasks;
@Override
public void onException(SchedulingContext schedulingContext, Exception e) {
logger.info("Something has gone wrong");
try {
// Fix the problem
// Reschedule
scheduledTasks
.scheduledTask(TimedTask.class)
.withTriggerName(schedulingContext.getTriggerName());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
Exception
handling in a TaskListener
is called asynchronously in order to be sure to apply the Task
’s
exception policy. Be careful in your implementation as it is impossible to know whether the Task
’s exceptionPolicy
or TaskListener
’s onException()
method is called first.