Sling scheduled job not executing | Community
Skip to main content
Level 2
June 3, 2025
Solved

Sling scheduled job not executing

  • June 3, 2025
  • 2 replies
  • 578 views

Hi everyone,

I’ve implemented a simple Sling scheduled job in Cloud Service. It works perfectly in my local SDK, but once deployed to the dev environment, the job never seems to run - and there are no related logs or errors.

Below the core code:

@8220494(
service = Runnable.class,
immediate = true,
configurationPolicy = ConfigurationPolicy.REQUIRE
)
@Designate(ocd = MyScheduledTask.Config)
public class MyScheduledTask implements Runnable {

@ObjectClassDefinition(name = "My Scheduled Task Configuration")
public @interface Config {
@AttributeDefinition(name = "CRON Expression")
String scheduler_expression() default "0 */1 * * * ?"; // Every 1 minute

@AttributeDefinition(name = "Concurrent execution")
boolean scheduler_concurrent() default false;
}

private static final Logger LOG = LoggerFactory.getLogger(MyScheduledTask.class);

@580286
@9182423
protected void activate(Config config) {
LOG.info("Scheduled Task configured with expression: {}", config.scheduler_expression());
}

@9944223
public void run() {
LOG.info("MyScheduledTask is running...");
}
}

 

And in ui.config/config.dev, I have configured:

{
"scheduler.expression": "0 */1 * * * ?",
"scheduler.concurrent": false
}

In the dev environment, the job never executes and I don’t see any logs or errors in the Cloud Manager logs, making it hard to debug.

Is there a specific configuration or restriction that prevents scheduled jobs from running?

Thanks in advance!

Best answer by SantoshSai

Hi @sanaqu,

Based on what you described and some common pitfalls we have seen, here are a few key things to double-check in your setup:

1. Scheduled jobs must be enabled via OSGi configurations

Make sure the scheduler.expression and other values are configured correctly for the environment (like dev) via ui.config under the correct runmode folder.

For example, in:

ui.config/src/dev/com/example/core/MyScheduledTask.cfg.json

Make sure it's named exactly using the fully qualified class path, such as:

{
  "scheduler.expression": "0 */1 * * * ?",
  "scheduler.concurrent": false
}

Also ensure this configuration is part of your Cloud Manager deployment.

2. Use @Component(immediate = true) with caution

In AEM as a Cloud Service, immediate = true can sometimes prevent the service from being registered properly if dependencies are not satisfied at activation. Consider using immediate = false and control job behaviour via lifecycle management.

3. Logs might not show unless the job actually triggers

Logging level in AEM as a Cloud Service may suppress non-error logs unless explicitly configured. Use:

LOG.error("Task is running..."); // temporarily for visibility

Or configure custom loggers in ui.config to increase visibility.

4. Cloud readiness - avoid State-Based jobs

AEM as a Cloud Service is stateless and distributed, so Adobe recommends using Sling Jobs (org.apache.sling.event.jobs) or Adobe Scheduler Service via Cloud Manager for time-based automation, especially if reliability and scaling are concerns.

Sling Scheduler vs Sling Jobs – Adobe Best Practices

5. Deployment timing and bundle activation

Sometimes, if your bundle is active before the OSGi configuration is deployed, the @Activate method won't get the right values. To fix:

  • Ensure the .cfg.json file is deployed as part of the same package as your bundle

  • Or deploy configs before the bundle if separated

Quick debug tip

Add this to verify if your job is at least active:

curl -u admin:admin http://localhost:4502/system/console/status-slingscheduler

In Cloud Service, you won’t have this access, so rely on log statements or Adobe’s Developer Console for deeper telemetry.

Try this:
MyScheduledTask.java:

@Component(service = Runnable.class, configurationPolicy = ConfigurationPolicy.REQUIRE, property = { "scheduler.concurrent=false" }) public class MyScheduledTask implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(MyScheduledTask.class); @Override public void run() { LOG.error("Scheduled Task is running..."); // Use ERROR level for Cloud visibility } }

 MyScheduledTask.cfg.json:

{ "scheduler.expression": "0 */1 * * * ?", "scheduler.concurrent": false }

Place this under:

ui.config/src/dev/com/example/core/MyScheduledTask.cfg.json

I would not recommend using immediate=true, if dependencies are not met immediately, this can prevent activation. Best practice is to remove immediate=true and instead rely on lifecycle management or OSGi configuration.

 

2 replies

SantoshSai
Community Advisor
SantoshSaiCommunity AdvisorAccepted solution
Community Advisor
June 3, 2025

Hi @sanaqu,

Based on what you described and some common pitfalls we have seen, here are a few key things to double-check in your setup:

1. Scheduled jobs must be enabled via OSGi configurations

Make sure the scheduler.expression and other values are configured correctly for the environment (like dev) via ui.config under the correct runmode folder.

For example, in:

ui.config/src/dev/com/example/core/MyScheduledTask.cfg.json

Make sure it's named exactly using the fully qualified class path, such as:

{
  "scheduler.expression": "0 */1 * * * ?",
  "scheduler.concurrent": false
}

Also ensure this configuration is part of your Cloud Manager deployment.

2. Use @Component(immediate = true) with caution

In AEM as a Cloud Service, immediate = true can sometimes prevent the service from being registered properly if dependencies are not satisfied at activation. Consider using immediate = false and control job behaviour via lifecycle management.

3. Logs might not show unless the job actually triggers

Logging level in AEM as a Cloud Service may suppress non-error logs unless explicitly configured. Use:

LOG.error("Task is running..."); // temporarily for visibility

Or configure custom loggers in ui.config to increase visibility.

4. Cloud readiness - avoid State-Based jobs

AEM as a Cloud Service is stateless and distributed, so Adobe recommends using Sling Jobs (org.apache.sling.event.jobs) or Adobe Scheduler Service via Cloud Manager for time-based automation, especially if reliability and scaling are concerns.

Sling Scheduler vs Sling Jobs – Adobe Best Practices

5. Deployment timing and bundle activation

Sometimes, if your bundle is active before the OSGi configuration is deployed, the @Activate method won't get the right values. To fix:

  • Ensure the .cfg.json file is deployed as part of the same package as your bundle

  • Or deploy configs before the bundle if separated

Quick debug tip

Add this to verify if your job is at least active:

curl -u admin:admin http://localhost:4502/system/console/status-slingscheduler

In Cloud Service, you won’t have this access, so rely on log statements or Adobe’s Developer Console for deeper telemetry.

Try this:
MyScheduledTask.java:

@Component(service = Runnable.class, configurationPolicy = ConfigurationPolicy.REQUIRE, property = { "scheduler.concurrent=false" }) public class MyScheduledTask implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(MyScheduledTask.class); @Override public void run() { LOG.error("Scheduled Task is running..."); // Use ERROR level for Cloud visibility } }

 MyScheduledTask.cfg.json:

{ "scheduler.expression": "0 */1 * * * ?", "scheduler.concurrent": false }

Place this under:

ui.config/src/dev/com/example/core/MyScheduledTask.cfg.json

I would not recommend using immediate=true, if dependencies are not met immediately, this can prevent activation. Best practice is to remove immediate=true and instead rely on lifecycle management or OSGi configuration.

 

Santosh Sai
AmitVishwakarma
Community Advisor
Community Advisor
June 3, 2025

Hi @sanaqu ,

 

Root Causes of Job Not Running in Cloud:

  - immediate = true is risky in AEMaaCS — it may prevent service activation silently if dependencies are not ready.

  - No scheduler.expression in @Component properties — Cloud needs static properties present at component level for proper binding.

  - Logs at INFO level are filtered in AEM Cloud unless explicitly enabled — use ERROR or configure a custom logger.

  - Config file naming/path issue — must match the fully qualified class name exactly.


Updated Java Code – AEMaaCS-Compatible

package com.example.core.schedulers; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Activate; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.framework.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component( service = Runnable.class, configurationPolicy = ConfigurationPolicy.REQUIRE, property = { Constants.SERVICE_DESCRIPTION + "=My Scheduled Task", "scheduler.concurrent=false" // Do NOT hardcode CRON here; we’ll use cfg.json } ) @Designate(ocd = MyScheduledTask.Config) public class MyScheduledTask implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(MyScheduledTask.class); @ObjectClassDefinition(name = "My Scheduled Task Configuration") public @interface Config { @AttributeDefinition(name = "CRON Expression") String scheduler_expression() default "0 */1 * * * ?"; @AttributeDefinition(name = "Concurrent Execution") boolean scheduler_concurrent() default false; } @Activate protected void activate(Config config) { LOG.error("MyScheduledTask activated with CRON: {}", config.scheduler_expression()); } @Override public void run() { LOG.error("MyScheduledTask is running in AEM Cloud!"); } }

Configuration File

Path:

ui.config/src/main/content/jcr_root/apps/YOUR_PROJECT/osgiconfig/config.dev/com.example.core.schedulers.MyScheduledTask.cfg.json

Content:

{ "scheduler.expression": "0 */1 * * * ?", "scheduler.concurrent": false }


Regards,
Amit