blob: a5ab18d36e422d22dd208b96f1ac331b884e435e [file]
///////////////////////////////////////////////////////////////
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
///////////////////////////////////////////////////////////////
[[library-scheduler,Scheduler Library]]
= Scheduler =
[devstatus]
--------------
source=libraries/scheduler/dev-status.xml
--------------
The Scheduler library provides an easy way to schedule tasks either for one time execution, CRON expression intervals or a custom algorithm.
An optional Timeline allows you to browse past and future task runs.
include::../../build/docs/buildinfo/artifact.txt[]
== Logging ==
The SLF4J Logger used by this library is named "org.apache.zest.library.scheduler".
== Assembly ==
Use SchedulerAssembler to add the Scheduler service to your Application. This
Assembler provide a fluent api to programmatically configure configuration defaults and activate the
Timeline service assembly that allow browsing of past and future Task runs.
Here is a full example:
[snippet,java]
----
source=libraries/scheduler/src/test/java/org/apache/zest/library/scheduler/SchedulerTest.java
tag=assembly
----
== Configuration ==
SchedulerConfiguration defines configuration properties details:
[snippet,java]
----
source=libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/SchedulerConfiguration.java
tag=configuration
----
== Writing Tasks ==
To write a schedulable Task, compose an Entity with the Task type to be able to schedule it.
The Task contract is quite simple:
[snippet,java]
----
source=libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/Task.java
tag=task
----
Tasks have a mandatory name property and an optional tags property. These properties get copied in
each TimelineRecord created when the Timeline feature is activated.
The run() method of Tasks is wrapped in a UnitOfWork when called by the Scheduler.
Thanks to the UnitOfWork handling in Zest, you can split the work done in your Tasks in
several UnitOfWorks. See UnitOfWork strategy below.
Here is a simple example:
[snippet,java]
-----------
source=libraries/scheduler/src/test/java/org/apache/zest/library/scheduler/docsupport/SchedulerDocs.java
tag=1
-----------
== Scheduling Tasks ==
Tasks are scheduled using the Scheduler service. This creates a Schedule associated to
the Task that allows you to know if it is running, to change it's cron expression and set it's
durability.
All Schedules are durable. In other words, it will survive an Application restart, and your application should
not schedule it again, as the Schedules are when the SchedulerService is activated after bootstrap.
There are three ways to schedule a Task using the Scheduler service: once or with a cron
expression or providing your own Schedule instance.
=== Scheduling once ===
This is the easiest way to run a background Task once after a given initial delay in seconds.
[snippet,java]
-----------
source=libraries/scheduler/src/test/java/org/apache/zest/library/scheduler/docsupport/SchedulerDocs.java
tag=2
-----------
Since all Schedules are durable, this "once" can be far into the future, and still be executed if the application
has been restarted.
=== Scheduling using a cron expression ===
Cron expression parsing is based on the GNU crontab manpage that can be found here:
http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5 .
The following extensions are used:
- a mandatory field is added at the begining: seconds.
- a special string is added: @minutely
- a special character is added: ? to choose between dayOfMonth and dayOfWeek
The ? special char has the same behavior as in the Quartz Scheduler expression. The wikipedia page
http://en.wikipedia.org/wiki/CRON_expression
explains Quartz Scheduler expression, not simple cron expressions. You'll find there about the ? special
char and maybe that some other extensions you would like to use are missing in this project.
To sum up, cron expressions used here have a precision of one second. The following special strings can be used:
- @minutely
- @hourly
- @midnight or @daily
- @weekly
- @monthly
- @annualy or @yearly
== Overrun ==
If the Schedule is running when it is time to be executed, then the execution will be skipped. This means that
the Task must complete within its period, or executions will be skipped. The sideeffect of that is that this
reduces thread exhaustion.
When the Task execution is skipped, the overrun() property on the Schedule is incremented by 1.
== Durability ==
All Schedules are durable and the Task must be an Entity Composite. It also means that Tasks should be schedule
once and not on each reboot. The SchedulerService will load all Schedules on activation.
While the Task is running, the Schedule will be held in the UnitOfWork of the TaskRunner. This means that IF the
Schedule is updated, i.e. cancelled or directly manipulating Schedule properties, the UnitOfWork.complete() will fail.
And if the Task is executing within the same UnitOfWork, any changes made will not take place.
== UnitOfWork strategy ==
The TaskRunner creates a UnitOfWork and the Task is excuted within that UnitOfWork. This may be very convenient, but
as noted in Durability above, that UnitOfWork will fail if Schedule properties are updated while the Task is
running. To avoid that the Task's operations suffers from this, OR if the Task wants a Retry/DiscardOn strategy
different from the default one, then the Task can simply declare its own. such as;
[snippet,java]
-----------
source=libraries/scheduler/src/test/java/org/apache/zest/library/scheduler/docsupport/SchedulerDocs.java
tag=strategy
-----------
== Custom Schedules ==
It is possible to implement Schedule directly. It must be declared as an EntityComposite in the assembly, and be
visible from the SchedulerService. No other considerations should be necessary.
== Observing the Timeline ==
Timeline allow to browse in past and future Task runs. This feature is available only if you activate
the Timeline assembly in the SchedulerAssembler}, see above.
Once activated, Task success and failures are recorded. Then, the Timeline
service allow to browse in past (recorded) and in anticipated (future) Task runs.
Use the following in your code to get a Timeline Service injected:
[snippet,java]
-----------
source=libraries/scheduler/src/test/java/org/apache/zest/library/scheduler/docsupport/SchedulerDocs.java
tag=timeline
-----------
Here is the actual Timeline contract:
[snippet,java]
----
source=libraries/scheduler/src/main/java/org/apache/zest/library/scheduler/timeline/Timeline.java
tag=timeline
----