AEM Scheduler

AEM Scheduler is a service which is used to schedule jobs in AEM Application. We can write a scheduler service in AEM by two different ways.

1:- Using Scheduler API
2:- Using Whiteboard Pattern

We can create our scheduler class using SCR Annotaions or using New OSGi R6 Annotaions. From AEM 6.2 SCR Annotations are deprecated now.So we will only use OSGi Annotaions to create our scheduler.

Writing scheduler class using Whiteboard Pattern:-

In this case we will use the normal Java thread API to schedule a job.
In example below we are scheduling a job for every 2 seconds. We have given cron expression as */2 * * * * ?.
We can take help of http://www.cronmaker.com/ to create your cron expression easily.


package com.adobe.aem.saurabhaem.core.schedulers;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Designate(ocd = SimpleScheduledTask.SchedulerConfig.class)
@Component(
service=Runnable.class,
immediate = true
)
public class SimpleScheduledTask implements Runnable {

    @ObjectClassDefinition(name="Demo Scheduler Configuration",description = "Demo Scheduler Configuration")
    public static @interface SchedulerConfig {

        @AttributeDefinition(name = "cron-job-expression")
        String scheduler_expression() default "*/2 * * * * ?";

        @AttributeDefinition(name = "Run concurrently",description = "Check if job is scheduled to run concurrently")
        boolean scheduler_concurrent() default false;

        @AttributeDefinition(name = "Some Custom Property",description = "Custom property")
        String custom_parameter() default "";
    }

    private final Logger LOGGER = LoggerFactory.getLogger(getClass());

    private String customParameter;
    
    @Override
    public void run() {
    LOGGER.info("Running scheduler for...."+customParameter);
    }

    @Activate
    protected void activate(final SchedulerConfig config) {
    customParameter = config.custom_parameter();
    }

}

Check the scheduler service created above in http://localhost:4502/system/console/configMgr


You can check your logs to check if your scheduler is triggering according to given cron expression.




Writing scheduler class using Scheduler API:

In this case we will use the org.apache.sling.commons.scheduler.Scheduler service reference in our service class which is part of open source Quartz library.

@Reference
private Scheduler scheduler;

Below is the example of creating a scheduler class which used Scheduler APi & OSGI Annotaions.

package com.adobe.aem.saurabhaem.core.schedulers;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "Test Scheduler Configuration", description = "Test Scheduler Configuration")
public @interface TestSchedulerConfig {

@AttributeDefinition(name = "Scheduler name", description = "Scheduler name", type = AttributeType.STRING)
public String schedulerName() default "Test Scheduler";

@AttributeDefinition(name = "Run Concurrently?", description = "Schedule task concurrently", type = AttributeType.BOOLEAN)
boolean schedulerConcurrent() default true;

@AttributeDefinition(name = "Enabled", description = "Enable Scheduler", type = AttributeType.BOOLEAN)
boolean serviceEnabled() default true;

@AttributeDefinition(name = "Cron Expression", description = "Default: run every two minute.", type = AttributeType.STRING)
String schedulerExpression() default "0 0/2 * 1/1 * ? *";

}



package com.adobe.aem.saurabhaem.core.schedulers;

import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Saurabh
 *
 */
@Component(immediate = true, service = TestScheduler.class)
@Designate(ocd = TestSchedulerConfig.class)
public class TestScheduler implements Runnable {
@Reference
private Scheduler scheduler;
private int schedulerID;
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());

@Activate
protected void activate(TestSchedulerConfig config) {
schedulerID = config.schedulerName().hashCode();
}

@Modified
protected void modified(TestSchedulerConfig config) {
removeScheduler();
schedulerID = config.schedulerName().hashCode(); // update schedulerID
addScheduler(config);
}

@Deactivate
protected void deactivate(TestSchedulerConfig config) {
removeScheduler();
}

/**
* Remove a scheduler based on the scheduler ID
*/
private void removeScheduler() {
LOGGER.info("Removing Scheduler Job '{}'", schedulerID);
scheduler.unschedule(String.valueOf(schedulerID));
}

/**
* Add a scheduler based on the scheduler ID
*/
private void addScheduler(TestSchedulerConfig config) {
if (config.serviceEnabled()) {
ScheduleOptions scheduleOptions = scheduler.EXPR(config.schedulerExpression());
scheduleOptions.name(String.valueOf(schedulerID));
scheduleOptions.canRunConcurrently(config.schedulerConcurrent());
scheduler.schedule(this, scheduleOptions);
LOGGER.info("Test Scheduler added succesfully");
} else {
LOGGER.error("Test Scheduler is Disabled, no scheduler job created");
}
}

@Override
public void run() {
LOGGER.info("Inside Test Scheduler run Method");
}
}

Check the scheduler service created above in http://localhost:4502/system/console/configMgr



You can also check logs if scheduler added successfully & running according to scheduler expression.


Comments

  1. While writing schedulers i hope you have written environment specific configs for these schedulers did you ever face below issue-

    1. Configs doesn't get reflected until they are saved manually into Felix
    console.

    If you have faced such an issue what was your solution to that.?

    ReplyDelete

Post a Comment

Popular posts from this blog

AEM Sling Servlet

Event Handling in AEM