Schedulers & Sling Jobs
Purpose: Run background and recurring work correctly: scheduler vs job semantics, clustering, and idempotency.
Who this page is for
| Audience | Why it matters to you |
|---|
| Backend engineers | Anything async or recurring |
Two mechanisms, different guarantees
| Scheduler (cron) | Sling Jobs |
|---|
| Trigger | Time-based | Event/demand-based (job queue) |
| Guarantee | Best effort — missed if instance down | At least once — persisted, retried |
| Use for | Cache warmup, periodic sync, cleanup | Work that must not be lost (send confirmation, sync one plan record) |
Scheduled task
@Component(service = Runnable.class)
@Designate(ocd = PlanSyncTask.Config.class)
public class PlanSyncTask implements Runnable {
@ObjectClassDefinition interface Config {
@AttributeDefinition String scheduler_expression() default "0 0 2 * * ?"; // 2am daily
@AttributeDefinition boolean scheduler_concurrent() default false;
}
@Override public void run() { /* sync plan data */ }
}
Job + consumer
// enqueue
jobManager.addJob("phi/plans/sync", Map.of("planId", "gold-hospital"));
// consume
@Component(service = JobConsumer.class,
property = JobConsumer.PROPERTY_TOPICS + "=phi/plans/sync")
public class PlanSyncConsumer implements JobConsumer {
@Override public JobResult process(Job job) {
// do work; return JobResult.OK / FAILED (retry) / CANCEL (no retry)
}
}
Operational rules
- Idempotency is mandatory — jobs are at-least-once; schedulers can double-fire around restarts.
- On author clusters/farms, ensure singleton execution where needed (job queues configured appropriately; schedulers with
scheduler.runOn semantics on 6.5 topologies). - Long work in small units: enqueue per-item jobs rather than one mega-job; the queue gives retry granularity.
- Watch queues at /system/console/slingevent when things back up.