AEM Sling Scheduler: Reliable Jobs Across a Cluster

AEM Sling Scheduler makes it straightforward to run recurring Java tasks, such as content clean-up, report generation, cache preparation, or metadata synchronisation. The difficulty begins when an AEM author or publish tier contains several instances behind a load balancer. A task that appears to run once in development may execute on every node in production, creating duplicate emails, conflicting writes, or unnecessary load.

The right design depends on what the task actually represents. A local maintenance action can use a scheduler restricted to one instance, while business work that must be durable and retryable belongs in Sling Jobs. Australian teams also need to account for multiple data centres, Australian Eastern and Western time zones, and deployment windows that often run overnight to avoid peak traffic.

Understand The Scheduler’s Execution Model

The Sling Scheduler is an in-process scheduling service. Each AEM instance starts its own scheduler, reads its configuration, and evaluates the configured cron expression or interval. A load balancer does not coordinate these timers; it only distributes HTTP requests.

This distinction is easy to miss because a browser, dispatcher, or monitoring tool may show only one visible application endpoint. If three publish instances share the same code and configuration, all three can wake up at 2:00 am and perform the same action. The result may be three exports, three calls to an external API, or three attempts to update the same repository paths.

Scheduling is therefore a deployment concern as much as a coding concern. Before writing the task, define whether it is a singleton operation, a per-node operation, or a queue of independent work items. That decision determines the appropriate Sling API and cluster strategy.

Select A Cluster-Safe Strategy

For a task that should run on one AEM node, Sling Scheduler provides execution hints such as runOn, including leader-oriented options in supported versions. A leader election mechanism identifies one instance in the Sling topology, allowing a maintenance routine to execute once rather than once per node. The exact option names and behaviour should be checked against the AEM and Sling versions in use.

Leader-only execution is useful for jobs such as rebuilding a shared report, rotating a repository-based marker, or initiating a single import. It is not a complete transaction guarantee. A leader can stop halfway through a task, lose connectivity, or be replaced while external work is still running. The job must remain safe if it is interrupted and started again.

For reliable business processing, use the Sling JobManager and job queues instead of treating a scheduled Runnable as a durable queue. A scheduler can act as a lightweight trigger that creates a job, while the job framework manages distribution, retries, and processing topology. This separation is particularly valuable when a task must survive restarts or move between publish nodes.

Keep Scheduled Work Idempotent

Idempotency means that running the same operation twice produces the same acceptable state as running it once. For example, a synchronisation task can record a source identifier and version, then skip work that has already been applied. An export can write to a temporary location before replacing the final file, rather than appending duplicate records.

Repository changes should use service users with narrowly defined permissions. Resolve a service resource resolver inside the task, close it reliably, and avoid retaining sessions or resolvers between executions. A task should also set clear time limits for network calls, because a stalled endpoint can occupy a scheduler thread and delay other work.

Use a distributed lock only when the locking mechanism is genuinely shared by all relevant instances. A local Java lock protects one JVM, not a cluster. JCR-based markers can work for short coordination windows when implemented carefully, but they need ownership, expiry, and recovery rules. A lock without an expiry can block every future run after a process failure.

Design For AEM Operations

Configuration should be externalised through OSGi rather than embedded in Java constants. Store the cron expression, enabled state, batch size, endpoint settings, and queue name in environment-appropriate configuration. This allows a team to disable a job on author while keeping it active on publish, or to use different schedules for staging and production.

Australian organisations often operate across Sydney, Melbourne, Brisbane, Adelaide, and Perth, where daylight-saving rules do not align. A cron expression based on local time can run at an unexpected UTC moment, particularly when daylight saving begins in New South Wales or Victoria but not Queensland or Western Australia. Choose a documented time zone, preferably UTC for infrastructure-level schedules, and communicate the corresponding local window.

AEM deployments also need a clear ownership model. If a managed service team performs releases after business hours in Australian Eastern time, a scheduled migration should not compete with package installation, dispatcher flushes, or index maintenance. Add a feature flag or OSGi enablement switch so operations staff can pause a task without rebuilding the application.

Package Dependencies Carefully

Sling Scheduler APIs come from AEM and Apache Sling bundles, so dependency versions must match the target runtime. Avoid copying arbitrary JARs into an application bundle to solve an import error. An incompatible version can create class-space problems that appear only after deployment or restart.

Dependency locking and repeatable builds are especially important when several AEM applications share a release pipeline. This discussion of AEM dependency management is useful background for controlling repository sources, package versions, and build provenance. Artifactory or an equivalent repository can provide a consistent supply chain for local development and continuous integration.

Keep the scheduler component small. Put business logic in a service that can be called by a command, an integration test, or a job consumer. The scheduled method should mainly validate configuration, acquire the required service, create work, and record a useful outcome. This structure makes it easier to test without waiting for a real cron trigger.

Test The Failure Modes

A test environment should include at least two AEM instances, not just a single local author. Verify whether the task runs once or multiple times, then stop the active node during execution and observe what happens after another node becomes the leader. Test a slow external service, a repository permission failure, a malformed configuration, and an empty result set.

Front-end checks also matter when a scheduled process changes pages, assets, or published data. A scheduled content update can invalidate assumptions in browser tests, so teams may benefit from reviewing front-end testing strategies alongside backend scheduler tests. The objective is to confirm that automated changes leave the site usable, cacheable, and accessible.

Java developers moving between ecosystems may recognise similar concerns in other enterprise platforms. Discussions at C# developer events can provide useful comparisons around hosted services, retries, dependency injection, and background processing, although Sling’s cluster behaviour must still be verified in an AEM environment. Broader distributed-systems material, including distributed systems research, can also sharpen thinking about delivery guarantees and failure recovery.

Operate With Evidence

A scheduled job should expose enough information for an operator to answer four questions: when did it start, which instance ran it, what input did it process, and why did it finish or fail? Use structured logs with a correlation or execution ID. Report counts and durations rather than dumping every repository path into production logs.

Metrics should distinguish successful runs, failed runs, skipped runs, processing time, and queue depth. Alerts need sensible thresholds. A single transient failure may deserve a retry, while repeated failures or a growing job queue should create an incident. Include the schedule name, environment, and active instance in operational dashboards.

Practical Checks Before Release

  • Confirm whether the task is singleton, per-node, or queue-based
  • Use a service user and close every resource resolver
  • Document the cron time zone and daylight-saving behaviour
  • Test node loss, retries, duplicate delivery, and slow dependencies

Useful Production Records

  • Execution ID, start time, finish time, and processing duration
  • Active AEM instance and leader status
  • Input count, success count, skip count, and failure count
  • Last successful run and current queue depth

A job that cannot be observed is difficult to trust, even when its code is correct. Retain enough history to compare normal execution with unusual behaviour, while avoiding sensitive content in logs. For Australian operations, align alert routing with the support roster and record whether times are displayed in AEST, AEDT, AWST, or UTC.

Treat the scheduler as a trigger, not a guarantee that work has been completed. A successful trigger should mean that processing was created or handed to the correct queue; the consumer should report the final business outcome. This distinction produces clearer dashboards and prevents a green scheduler status from hiding failed downstream work.

Start by inventorying every recurring AEM task and classifying it as local, singleton, or durable work. Then review the cron configuration, service permissions, retry rules, and monitoring for each one. Implement the safest strategy in a non-production cluster, test node failure deliberately, and promote only after the run history demonstrates predictable behaviour.