How to run a job on leader instance in AEM as a Cloud Service
Learn how to run a job on the leader instance in the AEM Author service as part of AEM as a Cloud Service, and understand how to configure it to run only once.
Sling Jobs are asynchronous tasks that operate in the background, designed to handle system or user-triggered events. By default, these jobs are distributed equally across all instances (pods) in the cluster.
For more information, see Apache Sling Eventing and Job Handling.
Create and process jobs
For demo purposes, let’s create a simple job that instructs the job processor to log a message.
Create a job
Use the below code to create an Apache Sling job:
package com.adobe.aem.guides.wknd.core.sling.jobs.impl;
import java.util.HashMap;
import java.util.Map;
import org.apache.sling.event.jobs.JobManager;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(immediate = true)
public class SimpleJobCreaterImpl {
private static final Logger log = LoggerFactory.getLogger(SimpleJobCreaterImpl.class);
// Define the topic on which the job will be created
protected static final String TOPIC = "wknd/simple/job/topic";
// Inject a JobManager
@Reference
private JobManager jobManager;
@Activate
protected final void activate() throws Exception {
log.info("SimpleJobCreater activated successfully");
createJob();
log.info("SimpleJobCreater created a job");
}
private void createJob() {
// Create a job and add it on the above defined topic
Map<String, Object> jobProperties = new HashMap<>();
jobProperties.put("action", "log");
jobProperties.put("message", "Job metadata is: Created in activate method");
jobManager.addJob(TOPIC, jobProperties);
}
}
The key points to note in the above code are:
- The job payload has two properties:
action
andmessage
. - Using the JobManager’s
addJob(...)
method, the job is added to the topicwknd/simple/job/topic
.
Process a job
Use the below code to process the above Apache Sling job:
package com.adobe.aem.guides.wknd.core.sling.jobs.impl;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = JobConsumer.class, property = {
JobConsumer.PROPERTY_TOPICS + "=" + SimpleJobCreaterImpl.TOPIC
}, immediate = true)
public class SimpleJobConsumerImpl implements JobConsumer {
private static final Logger log = LoggerFactory.getLogger(SimpleJobConsumerImpl.class);
@Override
public JobResult process(Job job) {
// Get the action and message properties
String action = job.getProperty("action", String.class);
String message = job.getProperty("message", String.class);
// Log the message
if ("log".equals(action)) {
log.info("Processing WKND Job, and {}", message);
}
// Return a successful result
return JobResult.OK;
}
}
The key points to note in the above code are:
- The
SimpleJobConsumerImpl
class implements theJobConsumer
interface. - It is a service registered to consume jobs from the topic
wknd/simple/job/topic
. - The
process(...)
method processes the job by logging the job payload’smessage
property.
Default job processing
When you deploy the above code to an AEM as a Cloud Service environment and run it on the AEM Author service, which operates as a cluster with multiple AEM Author JVMs, the job will run once on each AEM Author instance (pod), meaning the number of jobs created will match the number of pods. The number of pods will always be more than one (for non-RDE environments), but will fluctuate based on AEM as a Cloud Service’ internal resource management.
The job is run on each AEM Author instance (pod) because the wknd/simple/job/topic
is associated with AEM’s main queue, which distributes jobs across all available instances.
This is often problematic if the job is responsible for changing state, such as creating or updating resources or external services.
If you want the job to run only once on the AEM Author service, add the job queue configuration described below.
You can verify it by reviewing the logs of the AEM Author service in Cloud Manager.
You should see:
<DD.MM.YYYY HH:mm:ss.SSS> [cm-pxxxx-exxxx-aem-author-68775db964-nxxcx] *INFO* [sling-oak-observation-15] org.apache.sling.event.impl.jobs.queues.JobQueueImpl.<main queue> Starting job queue <main queue>
<DD.MM.YYYY HH:mm:ss.SSS> INFO [com.adobe.aem.guides.wknd.core.sling.jobs.impl.SimpleJobConsumerImpl] Processing WKND Job, and Job metadata is: Created in activate method
<DD.MM.YYYY HH:mm:ss.SSS> [cm-pxxxx-exxxx-aem-author-68775db964-r4zk7] *INFO* [sling-oak-observation-11] org.apache.sling.event.impl.jobs.queues.JobQueueImpl.<main queue> Starting job queue <main queue>
<DD.MM.YYYY HH:mm:ss.SSS> INFO [com.adobe.aem.guides.wknd.core.sling.jobs.impl.SimpleJobConsumerImpl] Processing WKND Job, and Job metadata is: Created in activate method
There are two log entries, one for each AEM Author instance (68775db964-nxxcx
and 68775db964-r4zk7
), indicating that each instance (pod) processed the job.
How to run a job on the leader instance
To run a job only once on the AEM Author service, create a new Sling job queue of the type Ordered, and associate your job topic (wknd/simple/job/topic
) with this queue. With this configuration will only allow the leader AEM Author instance (pod) to process the job.
In your AEM project’s ui.config
module, create an OSGi configuration file (org.apache.sling.event.jobs.QueueConfiguration~wknd.cfg.json
) and store it at ui.config/src/main/content/jcr_root/apps/wknd/osgiconfig/config.author
folder.
{
"queue.name":"WKND Queue - ORDERED",
"queue.topics":[
"wknd/simple/job/topic"
],
"queue.type":"ORDERED",
"queue.retries":1,
"queue.maxparallel":1.0
}
The key points to note in the above configuration are:
- The queue topic is set to
wknd/simple/job/topic
. - The queue type is set to
ORDERED
. - The maximum number of parallel jobs is set to
1
.
Once you deploy the above configuration, the job will be processed exclusively by the leader instance, ensuring it runs only once across the entire AEM Author service.
<DD.MM.YYYY HH:mm:ss.SSS> [cm-pxxxx-exxxx-aem-author-7475cf85df-qdbq5] *INFO* [FelixLogListener] Events.Service.org.apache.sling.event Service [QueueMBean for queue WKND Queue - ORDERED,7755, [org.apache.sling.event.jobs.jmx.StatisticsMBean]] ServiceEvent REGISTERED
<DD.MM.YYYY HH:mm:ss.SSS> INFO [com.adobe.aem.guides.wknd.core.sling.jobs.impl.SimpleJobConsumerImpl] Processing WKND Job, and Job metadata is: Created in activate method
<DD.MM.YYYY HH:mm:ss.SSS> [com.adobe.aem.guides.wknd.core.sling.jobs.impl.SimpleJobConsumerImpl] Processing WKND Job, and Job metadata is: Created in activate method