Hi All,
I have scheduler configured in AEM to perform some activity everyday night at 2pm. My scheduler every 3 to 4 days it is unable to trigger job and do not log any information in the logs. I'm using AEM 6.5 and with latest service pack.
Please help or provide troubleshooting steps.
Solved! Go to Solution.
Views
Replies
Total Likes
First I would like to ask few questions here -
1. Are you facing this issue since long time ?
2. Have you written this scheduler with OSGi R6 annotation?
3. Have you made any changes in scheduler recently and deploys the same without modifying the cronjob expression?
I had similar experience with scheduler and able to fix the issue.
Sharing my demo scheduler and Implementation class as reference , please review code comments and I believe it will help you to debug the issue -
Scheduler -
/**
*
*/
package com.aem.demo.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;
import com.aem.demo.core.configurations.TaskNotificationSchedulerConfiguration;
import com.aem.demo.core.services.TaskNotificationService;
import com.google.common.base.Strings;
/**
* @author debal
*
* A cron-job like tasks that get executed regularly.
*/
@component(service = Runnable.class, immediate = true)
@Designate(ocd = TaskNotificationSchedulerConfiguration.class)
public class TaskNotificationScheduler implements Runnable {
private final Logger logger = LoggerFactory.getLogger(TaskNotificationScheduler.class);
@reference
TaskNotificationService taskNotificationService;
@reference
Scheduler scheduler;
private String contentDampath;
private String schedulerName;
@activate
private void activate(TaskNotificationSchedulerConfiguration configguration) {
this.contentDampath = configguration.assetPath();
this.schedulerName = configguration.schdulerName();
logger.info("**** Task Notification Scheduler ****");
//This scheduler will continue to run automatically even after the server reboot, otherwise the scheduled tasks will stop running after the server reboot.
addScheduler(configguration);
}
@MODIFIED
protected void modified(TaskNotificationSchedulerConfiguration configguration) {
// Remove the scheduler registered with old configuration
removeScheduler(configguration);
contentDampath = configguration.assetPath();
// Add the scheduler registered with new configuration
addScheduler(configguration);
}
private void addScheduler(TaskNotificationSchedulerConfiguration configguration) {
boolean enabled = configguration.enabled();
if (enabled) {
ScheduleOptions scheduleOptions = scheduler.EXPR(configguration.cronExpression());
if (!Strings.isNullOrEmpty(schedulerName)) {
scheduleOptions.name(schedulerName);
scheduleOptions.canRunConcurrently(false);
scheduler.schedule(this, scheduleOptions);
logger.info("****** Task Notification Scheduler has been added successfully ******");
}
} else {
logger.info("****** Task Notification Scheduler is in disable state ******");
}
}
@deactivate
protected void deactivated(TaskNotificationSchedulerConfiguration configguration) {
logger.info("**** Removing Task Notification Scheduler Successfully on deactivation ****");
removeScheduler(configguration);
}
private void removeScheduler(TaskNotificationSchedulerConfiguration configguration) {
logger.info("**** Removing Task Notification Scheduler Successfully **** {}", schedulerName);
scheduler.unschedule(schedulerName);
}
@Override
public void run() {
taskNotificationService.setTaskNotification(contentDampath);
logger.info("******Inside Task Notification Scheduler ******");
}
}
Impl -
/**
*
*/
package com.aem.demo.core.services.impl;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.granite.taskmanagement.Task;
import com.adobe.granite.taskmanagement.TaskManager;
import com.adobe.granite.taskmanagement.TaskManagerException;
import com.adobe.granite.taskmanagement.TaskManagerFactory;
import com.adobe.granite.workflow.exec.InboxItem;
import com.aem.demo.core.services.TaskNotificationService;
import com.drew.lang.annotations.Nullable;
import com.google.common.base.Strings;
/**
* @author debal
*
* This Implementation class is responsible to responsible to set/send
* notification in AEM inbox in case we set expiration datetime of an
* asset after current date time. Task Management in AEM is the set of
* APIs that manage Tasks, which can show up in AEM user's inbox. This
* can be done using Task and TaskManager API
*/
@component(service = TaskNotificationService.class, immediate = true)
public class TaskNotificationServiceImpl implements TaskNotificationService {
private final Logger logger = LoggerFactory.getLogger(TaskNotificationServiceImpl.class);
public static final String NOTIFICATION_TASK_TYPE = "Notification";
@reference
ResourceResolverFactory resourceResolverFactory;
@Override
public void setTaskNotification(String assetPath) {
ResourceResolver serviceResourceResolver = getResourceResolver();
try {
TaskManager taskManager = serviceResourceResolver.adaptTo(TaskManager.class);
TaskManagerFactory taskManagerFactory = taskManager.getTaskManagerFactory();
if (!Strings.isNullOrEmpty(assetPath)) {
Resource resource = serviceResourceResolver.getResource(assetPath);
if (Objects.nonNull(resource) && resource.isResourceType("dam:Asset")) {
Resource metadataresource = resource.getChild("jcr:content/metadata");
ModifiableValueMap modifiableValueMap = metadataresource.adaptTo(ModifiableValueMap.class);
@nullable
String creatorName = modifiableValueMap.get("dc:creator", String.class);
@nullable
Date expirydate = modifiableValueMap.get("prism:expirationDate", Date.class);
logger.info("*** Expiration Date ***{}", expirydate);
Date currentDate = new Date();
if (Objects.nonNull(expirydate) && !Strings.isNullOrEmpty(creatorName)) {
if (expirydate.after(currentDate)) {
Task newTask = taskManagerFactory.newTask(NOTIFICATION_TASK_TYPE);
newTask.setName("Content Expiry Notification");
newTask.setContentPath(assetPath);
// Optionally set priority (High, Medium, Low)
newTask.setPriority(InboxItem.Priority.HIGH);
newTask.setDescription("Content Expiry Notification");
newTask.setInstructions("Content Expiry Notification");
newTask.setCurrentAssignee(creatorName);
taskManager.createTask(newTask);
}
}
}
}
} catch (TaskManagerException te) {
logger.error("Could not create task {} ", te.getMessage());
} finally {
if (Objects.nonNull(serviceResourceResolver)) {
serviceResourceResolver.close();
}
}
}
private ResourceResolver getResourceResolver() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(resourceResolverFactory.SUBSERVICE, "readWriteService");
ResourceResolver serviceResourceResolver = null;
try {
serviceResourceResolver = resourceResolverFactory.getServiceResourceResolver(map);
} catch (LoginException e) {
logger.error("Could not get service user [ {} ]", "demoSystemUser", e.getMessage());
}
return serviceResourceResolver;
}
}
Interface -
/**
*
*/
package com.aem.demo.core.services;
/**
* @author debal
*
* This service is responsible to set/send notification in AEM inbox
*/
public interface TaskNotificationService {
public void setTaskNotification(String assetPath);
}
Please review the comments at code level.
Yes,
String schedulerExpression() default "0 0 2 1/1 * ? *";
which user permissions do I need to check?
First I would like to ask few questions here -
1. Are you facing this issue since long time ?
2. Have you written this scheduler with OSGi R6 annotation?
3. Have you made any changes in scheduler recently and deploys the same without modifying the cronjob expression?
I had similar experience with scheduler and able to fix the issue.
Sharing my demo scheduler and Implementation class as reference , please review code comments and I believe it will help you to debug the issue -
Scheduler -
/**
*
*/
package com.aem.demo.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;
import com.aem.demo.core.configurations.TaskNotificationSchedulerConfiguration;
import com.aem.demo.core.services.TaskNotificationService;
import com.google.common.base.Strings;
/**
* @author debal
*
* A cron-job like tasks that get executed regularly.
*/
@component(service = Runnable.class, immediate = true)
@Designate(ocd = TaskNotificationSchedulerConfiguration.class)
public class TaskNotificationScheduler implements Runnable {
private final Logger logger = LoggerFactory.getLogger(TaskNotificationScheduler.class);
@reference
TaskNotificationService taskNotificationService;
@reference
Scheduler scheduler;
private String contentDampath;
private String schedulerName;
@activate
private void activate(TaskNotificationSchedulerConfiguration configguration) {
this.contentDampath = configguration.assetPath();
this.schedulerName = configguration.schdulerName();
logger.info("**** Task Notification Scheduler ****");
//This scheduler will continue to run automatically even after the server reboot, otherwise the scheduled tasks will stop running after the server reboot.
addScheduler(configguration);
}
@MODIFIED
protected void modified(TaskNotificationSchedulerConfiguration configguration) {
// Remove the scheduler registered with old configuration
removeScheduler(configguration);
contentDampath = configguration.assetPath();
// Add the scheduler registered with new configuration
addScheduler(configguration);
}
private void addScheduler(TaskNotificationSchedulerConfiguration configguration) {
boolean enabled = configguration.enabled();
if (enabled) {
ScheduleOptions scheduleOptions = scheduler.EXPR(configguration.cronExpression());
if (!Strings.isNullOrEmpty(schedulerName)) {
scheduleOptions.name(schedulerName);
scheduleOptions.canRunConcurrently(false);
scheduler.schedule(this, scheduleOptions);
logger.info("****** Task Notification Scheduler has been added successfully ******");
}
} else {
logger.info("****** Task Notification Scheduler is in disable state ******");
}
}
@deactivate
protected void deactivated(TaskNotificationSchedulerConfiguration configguration) {
logger.info("**** Removing Task Notification Scheduler Successfully on deactivation ****");
removeScheduler(configguration);
}
private void removeScheduler(TaskNotificationSchedulerConfiguration configguration) {
logger.info("**** Removing Task Notification Scheduler Successfully **** {}", schedulerName);
scheduler.unschedule(schedulerName);
}
@Override
public void run() {
taskNotificationService.setTaskNotification(contentDampath);
logger.info("******Inside Task Notification Scheduler ******");
}
}
Impl -
/**
*
*/
package com.aem.demo.core.services.impl;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.granite.taskmanagement.Task;
import com.adobe.granite.taskmanagement.TaskManager;
import com.adobe.granite.taskmanagement.TaskManagerException;
import com.adobe.granite.taskmanagement.TaskManagerFactory;
import com.adobe.granite.workflow.exec.InboxItem;
import com.aem.demo.core.services.TaskNotificationService;
import com.drew.lang.annotations.Nullable;
import com.google.common.base.Strings;
/**
* @author debal
*
* This Implementation class is responsible to responsible to set/send
* notification in AEM inbox in case we set expiration datetime of an
* asset after current date time. Task Management in AEM is the set of
* APIs that manage Tasks, which can show up in AEM user's inbox. This
* can be done using Task and TaskManager API
*/
@component(service = TaskNotificationService.class, immediate = true)
public class TaskNotificationServiceImpl implements TaskNotificationService {
private final Logger logger = LoggerFactory.getLogger(TaskNotificationServiceImpl.class);
public static final String NOTIFICATION_TASK_TYPE = "Notification";
@reference
ResourceResolverFactory resourceResolverFactory;
@Override
public void setTaskNotification(String assetPath) {
ResourceResolver serviceResourceResolver = getResourceResolver();
try {
TaskManager taskManager = serviceResourceResolver.adaptTo(TaskManager.class);
TaskManagerFactory taskManagerFactory = taskManager.getTaskManagerFactory();
if (!Strings.isNullOrEmpty(assetPath)) {
Resource resource = serviceResourceResolver.getResource(assetPath);
if (Objects.nonNull(resource) && resource.isResourceType("dam:Asset")) {
Resource metadataresource = resource.getChild("jcr:content/metadata");
ModifiableValueMap modifiableValueMap = metadataresource.adaptTo(ModifiableValueMap.class);
@nullable
String creatorName = modifiableValueMap.get("dc:creator", String.class);
@nullable
Date expirydate = modifiableValueMap.get("prism:expirationDate", Date.class);
logger.info("*** Expiration Date ***{}", expirydate);
Date currentDate = new Date();
if (Objects.nonNull(expirydate) && !Strings.isNullOrEmpty(creatorName)) {
if (expirydate.after(currentDate)) {
Task newTask = taskManagerFactory.newTask(NOTIFICATION_TASK_TYPE);
newTask.setName("Content Expiry Notification");
newTask.setContentPath(assetPath);
// Optionally set priority (High, Medium, Low)
newTask.setPriority(InboxItem.Priority.HIGH);
newTask.setDescription("Content Expiry Notification");
newTask.setInstructions("Content Expiry Notification");
newTask.setCurrentAssignee(creatorName);
taskManager.createTask(newTask);
}
}
}
}
} catch (TaskManagerException te) {
logger.error("Could not create task {} ", te.getMessage());
} finally {
if (Objects.nonNull(serviceResourceResolver)) {
serviceResourceResolver.close();
}
}
}
private ResourceResolver getResourceResolver() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(resourceResolverFactory.SUBSERVICE, "readWriteService");
ResourceResolver serviceResourceResolver = null;
try {
serviceResourceResolver = resourceResolverFactory.getServiceResourceResolver(map);
} catch (LoginException e) {
logger.error("Could not get service user [ {} ]", "demoSystemUser", e.getMessage());
}
return serviceResourceResolver;
}
}
Interface -
/**
*
*/
package com.aem.demo.core.services;
/**
* @author debal
*
* This service is responsible to set/send notification in AEM inbox
*/
public interface TaskNotificationService {
public void setTaskNotification(String assetPath);
}
Please review the comments at code level.
test
There won't be any problem if you create all required configurations in the scheduler it self.
I have tested your code -
Approach 1: Deployed your scheduler on my local AEM instance and then change the cronjob expression, scheduler got triggered.
Approach 2: Set the cronjob expression first and then deployed scheduler (bundle, which contains the scheduler), scheduler got triggered perfectly.
I did these multiple times and scheduler got triggered every time.
As @Jörg_Hoh suggested , could you please check the threadpool also.
Are you still facing the same problem?
Thanks it works perfectly fine. Could you please remove the sample code.
This code is overly complex, because you register the scheduler manually. Sling can do that for you as well, you just need to define the scheduler expression as a property (see https://sling.apache.org/documentation/bundles/scheduler-service-commons-scheduler.html#scheduling-w...).
Already Aruna has defined scheduler expression as a property in her code.
Even I have defined scheduler expression as a property in my demo code also. Forgot to add that piece of the my code and plz accept my apology -
here is my demo code -
package com.aem.demo.core.configurations;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
/**
*
* @author debal This is the configuration class that takes properties for a
* scheduler to run
*/
@ObjectClassDefinition(name = "TaskNotificationSchedulerConfiguration", description = "Task Notification scheduler configuration")
public @interface TaskNotificationSchedulerConfiguration {
/**
* This method will return the name of the Scheduler
*
* @Return {@link String}
*/
@AttributeDefinition(name = "Scheduler name", description = "Name of the scheduler", type = AttributeType.STRING)
public String schdulerName() default "Task Notification scheduler configuration";
/**
* This method will set flag to enable the scheduler
*
* @Return {@link Boolean}
*/
@AttributeDefinition(name = "Enabled", description = "True, if scheduler service is enabled", type = AttributeType.BOOLEAN)
public boolean enabled() default false;
/**
* This method returns the Cron expression which will decide how the scheduler
* will run
*
* @Return {@link String}
*/
@AttributeDefinition(name = "Cron Expression", description = "Cron expression used by the scheduler", type = AttributeType.STRING)
public String cronExpression() default "0 * * * * ?";
/**
* This method returns the Asset Path
*
*
* @Return {@link String}
*/
@AttributeDefinition(name = "Asset Path", description = "Asset Path", type = AttributeType.STRING)
public String assetPath() default "/content/dam";
}
Just to test her scheduler, manually I have modified the default cronjob expression.
Another possible problem is that the threadpool you are using (most likely the default thread pool) does not have a free thread to run your job.
Are you referring Apache Sling Job Thread Pool OSGi configuration here? Please correct me.
yes