AEM Sling Scheduler: Running Cron Jobs for Content Maintenance
AEM content rarely stays tidy by itself. Expired campaign pages, incomplete metadata, abandoned assets, and outdated redirects can accumulate across author and publish environments. A Sling Scheduler gives Java developers a controlled way to run recurring maintenance tasks without relying on a person to remember a weekly clean-up.
The useful pattern is simple: define an OSGi service, assign it a cron expression, give it narrowly scoped repository access, and make each execution safe to repeat. In an Australian implementation, the design also needs to account for daylight saving, distributed AEM instances, privacy obligations, and the timing of local publishing operations.
What Sling Scheduler actually runs
Sling Scheduler is a service for triggering Java code at a specified time or interval. In traditional AEM deployments, an OSGi component can implement Runnable, receive scheduler properties, and execute work through its run() method. The scheduler is appropriate for predictable maintenance such as finding expired pages, checking missing tags, rebuilding a small index, or removing temporary repository nodes.
A scheduled task should perform a bounded unit of work rather than attempting to process an entire repository in one pass. Query a limited number of paths, handle a defined batch size, record the result, and allow the next run to continue. This keeps Oak queries, heap usage, and authoring performance under control when an Australian retail campaign generates a large volume of content before a sale.
Cron expressions commonly use Quartz-style fields, including seconds. For example, 0 0 2 * * ? represents 2:00 each day. Confirm the expression supported by the AEM and Sling versions in use, and document whether the server interprets it in UTC or local time.
Designing a safe maintenance task
A maintenance job should be idempotent: running it twice must produce the same valid result as running it once. A page-expiry job might add an audit marker before moving content, while a metadata job should update only fields that are genuinely missing. Avoid operations that assume a previous run completed perfectly, because an instance restart or deployment can interrupt any execution.
Use a service user with the minimum required permissions. The job can obtain a service ResourceResolver through a subservice mapping, adapt it to a JCR Session or PageManager, and close it in a finally block or try-with-resources statement. Never depend on an administrator session embedded in scheduler code. Log the path, action, and outcome without writing personal information into the log.
Australian privacy requirements make this especially important. A clean-up routine that copies customer details into audit nodes or exports them for reporting may conflict with the Privacy Act 1988 and the Australian Privacy Principles. Retain only what the business needs, set a clear deletion policy, and separate technical diagnostics from personally identifiable content.
Writing the OSGi scheduler component
A basic component can declare its schedule through OSGi properties. The following example illustrates the approach for a daily job:
@Component(
service = Runnable.class,
property = {
"scheduler.expression=0 0 2 * * ?",
"scheduler.concurrent=false",
"scheduler.name=content-maintenance"
}
)
public class ContentMaintenanceJob implements Runnable {
@Override
public void run() {
// Obtain a service resolver, process a bounded batch,
// and close the resolver after the work completes.
}
}
The scheduler.concurrent=false setting helps prevent overlapping executions within the same scheduler instance. It is not a complete cluster lock, however. If several AEM publishers run the component, each may trigger it. Add an explicit leader strategy, a distributed lock, or a design that makes duplicate execution harmless.
Production code should move repository work into a separate service rather than placing everything inside run(). That makes the business operation easier to unit test and allows the scheduler to handle timing, metrics, exception boundaries, and operational logging. Catch expected repository exceptions, log useful context, and ensure one failed item does not hide the status of the remaining batch.
Choosing queries and repository boundaries
QueryBuilder can be convenient for content maintenance, but an unrestricted query across /content can become expensive. Constrain the path, node type, properties, and result limit. If the same query runs frequently, inspect the Oak indexes and confirm that the query plan avoids traversal. JCR-SQL2 or a purpose-built service may be preferable when the selection logic is stable and performance-sensitive.
A useful job divides discovery from mutation. First identify candidate paths and validate that each still meets the condition. Then update one item at a time, committing at sensible intervals. Keep the transaction small enough to recover cleanly, and record a checkpoint if processing may span thousands of pages or assets.
Automated validation belongs before and after scheduled changes. AEM teams can use content validation tests to check node properties, required metadata, and expected repository state before allowing a maintenance release into production. For destructive actions, add a dry-run mode that reports candidates without changing them.
Accounting for AEM topology and Australian time
Decide where the task is allowed to run. A job intended to modify author content should normally be restricted to author run modes, while a cache or publication check may belong on publish. Use OSGi configuration and run-mode-aware deployment rather than assuming the same component should execute everywhere. In a clustered environment, nominate one execution owner or make the operation safely repeatable across nodes.
Time zones deserve explicit treatment. Sydney and Melbourne observe daylight saving, while Brisbane and Perth do not, so a “2 am” schedule can shift relative to other offices during the year. A national organisation should generally schedule in UTC or configure a documented business timezone, then test the daylight-saving transition. Also account for public holidays and after-hours publishing windows when a job could compete with editorial work.
Mobile-heavy browsing habits mean expired pages can remain visible in caches or search results even after the repository changes. If a job unpublishes content, coordinate replication, Dispatcher invalidation, CDN purging, and redirects. A tenanted site serving customers in Sydney, Adelaide, and Perth may need region-specific content rules rather than one blanket deletion time.
Testing failure paths before deployment
Unit tests should verify cron-independent behaviour: candidate selection, permission failures, malformed content, repeated execution, and partial batches. Inject the repository service and clock where possible, rather than waiting for a real scheduler event. A fixed clock makes expiry rules deterministic and exposes mistakes around midnight or daylight-saving boundaries.
Integration tests should run against an AEM test environment with realistic Oak indexes and service-user mappings. Confirm that the job can read and write only the intended paths, that commits are visible to the expected consumers, and that an interrupted run can restart safely. Test a repository containing no matches, one match, and enough matches to require several batches.
Operational tests matter too. Temporarily lower the schedule interval in a non-production environment, inspect logs and metrics, and simulate a locked repository or unavailable dependency. The event FAQ is a useful reference when reviewing conference-era AEM terminology, but current project documentation should remain the authority for APIs and cloud deployment constraints.
Monitoring, rollout, and long-term operations
Expose useful measurements such as execution duration, candidate count, successful updates, skipped items, and failures. A scheduler that finishes in two seconds today may consume twenty minutes after a major content migration. Alert on repeated failures and unusual item counts, rather than sending an email for every expected empty run.
Roll out maintenance code in stages. Begin with a dry run, review sampled paths with content authors, then enable a small batch limit. Keep a clear rollback procedure for property changes and use versioned code for structural changes. For deletion, prefer quarantine or archival states before permanent removal unless a documented retention policy requires immediate erasure.
Traditional on-premises and managed AEM installations can support scheduled OSGi tasks directly. AEM as a Cloud Service has a more constrained operational model, so validate whether a Sling Scheduler component is suitable for the target workload. Event-driven processing, Sling Jobs, Adobe-hosted maintenance mechanisms, or an external scheduler may be safer for long-running or cross-environment workflows.
| Concern | Practical approach | Main risk |
|---|---|---|
| Schedule | Quartz-style expression with documented timezone | Daylight-saving drift |
| Repository access | Service user and least-privilege mapping | Excessive permissions |
| Processing | Bounded, repeatable batches | Timeouts and heap pressure |
| Cluster execution | Leader control or idempotent logic | Duplicate mutations |
| Query performance | Restricted paths and validated indexes | Oak traversal |
| Content delivery | Coordinate replication and cache purge | Stale public pages |
| Compliance | Minimal logs and defined retention | Privacy breaches |
| Cloud deployment | Confirm platform-supported pattern | Unsupported runtime behaviour |
Treat the scheduler as a small production service rather than a timer attached to a script. Define ownership, review its logs, document its timezone, and give content teams a visible record of what was changed. With those controls in place, AEM cron jobs can keep repositories healthier while preserving editorial control and Australian compliance expectations. Begin with a dry-run maintenance component, test it against representative content, and promote it only after its permissions, timing, and failure recovery are demonstrably safe.