| /////////////////////////////////////////////////////////////// |
| * 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 |
| ---- |
| |