The Sling Com­mons Sched­uler Ser­vice is a Sling-provided mech­a­nism that is used to exe­cute jobs at pre­de­fined times–either peri­od­i­cally or at a set time. Is is based on the Quartz sched­ul­ing library and can there­fore make use of its syn­tax for defin­ing the exe­cu­tion times of jobs, mak­ing it pos­si­ble to pre­cisely indi­cate times like “at 6:32pm on every Sat­ur­day and Sun­day” or “at 2:30am on the first Fri­day of every month”. At the other end of the spec­trum, a sim­ple numeric value can be used to spec­ify the interval–in seconds–between each exe­cu­tion of the job.

More infor­ma­tion about the cron-like expres­sions used by Quartz can be found at http://​doc​jar​.com/​d​o​c​s​/​a​p​i​/​o​r​g​/​q​u​a​r​t​z​/​C​r​o​n​E​x​p​r​e​s​s​i​o​n​.​h​tml.

Inside CQ, an OSGi com­po­nent that imple­ments the java.lang.Runnable or the org.quartz.Job inter­face will be started if it has a con­fig­u­ra­tion prop­erty called either scheduler.expression (whose value must be a cron expres­sion) or scheduler.period (whose value must be a num­ber of seconds).

Thanks to OSGi anno­ta­tions, one can sim­ply define a sched­uled jobs using code like the following:

@Component(immediate=true)
@Service(interface=“java.lang.Runnable”)
@Property(name=“scheduler.expression” value=“0 0/10 * * * ?”, type=“String”)
pub­lic class MySched­uled­Job imple­ments java.lang.Runnable {
pub­lic void run() {
// code to exe­cute goes here
}
}

 

Notice that we spec­i­fied “immediate=true” in the @Component dec­la­ra­tion. This makes sure that the com­po­nent is acti­vated imme­di­ately when the bun­dle is reg­is­tered, a thing which is nec­es­sary for it to be prop­erly invoked by the scheduler.

The method run() of the above com­po­nent will be exe­cuted every hour at 0, 10, 20, 30, 40, and 50 min­utes, zero sec­onds. If we had sim­ply wanted an exe­cu­tion every 10 min­utes, we could have used the fol­low­ing anno­ta­tion instead:

@Property(name="scheduler.period" value="600", type="Long")

Con­cur­rent exe­cu­tion of the job, which might hap­pen if the pre­vi­ous exe­cu­tion has not yet fin­ished when a new one is sched­uled, can be pre­vented by set­ting the scheduler.concurrent prop­erty to false:

@Property(name="scheduler.concurrent", propertyPrivate=true, boolValue=false)

In a real-world sce­nario, we might want to be able to spec­ify the exe­cu­tion time using the CQ5 Web Con­sole. To do this, we need to mod­ify the dec­la­ra­tion of the prop­erty as follows:

@Component(immediate=true, metatype=true)