Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Trigger scheduler once after deployment

Avatar

Level 4

Hi guys,

is it possible to trigger a scheduler once after every deployment? So the regular schedule time is 4 hours, but it will took 4 hours for the first run.

Any property to set?

Br,

Tim

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

Hi,

I see. The only chance to get it working the way you want is to trigger the scheduled job manually on activation of a SCR component/service.

Jörg

View solution in original post

16 Replies

Avatar

Level 3

Maybe you can schedule it again when activating the component?

@Activate or @Modified

Avatar

Level 3

Let me try to see if I understand correctly what you're trying to achieve here.

You have application code (an OSGi component) that schedules a specific task, every 4 hours. You want this task to be done after you've deployed your application code aswell. Let's take the following code as your OSGi component as an example:

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.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;

@Component(service = CustomSchedulerServiceImpl.class, configurationPolicy = ConfigurationPolicy.REQUIRE, immediate = true)

public class CustomSchedulerServiceImpl implements CustomSchedulerServiceImpl {

   /**
  * Cron formatted scheduling expression
  */
   private String schedulerExpression;

   @Reference
   private Scheduler scheduler;

   /**
  * Activate.
  *
  * @param config the polling service config
  */
   @Activate
   public void activate(final Map<String, Object> config) {

        this.schedulerExpression = <YOUR CRON EXPRESSION HERE PREFERABLY FROM CONFIG>

          scheduleNow();

        

         scheduleLater();

   }

   @Override
   public void scheduleLater() {

   final ScheduleOptions scheduleOptions = scheduler.EXPR(schedulerExpression);
    scheduler.schedule(tireDesignsFetchJobFactory.createJob(), scheduleOptions);
   }

  @Override
  public void scheduleINow() {

    final ScheduleOptions scheduleOptions = scheduler.NOW();
    scheduler.schedule(tireDesignsFetchJobFactory.createJob(), scheduleOptions);
  }

}

Avatar

Level 4

I have an actual scheduler but it runs not on startup only after the 4 hours of waiting and I want it the be run immediately.

What's that: tireDesignsFetchJobFactory.createJob()

Avatar

Level 10

WHen setting up a schedule - are you using the org.apache.sling.commons.scheduler.Scheduler API?

Avatar

Level 4

@Component(enabled = true, immediate = true, metatype = true, label = "cron job",
   description = "cron job ")

@Service(value = Runnable.class)

@Properties({

   @Property(name = "scheduler.expression", value = "0 0/15 * * * ?", description = "Cron-job expression Ex: '0 0/15 * * * ?' for 15 Mins"),
   @Property(name = "scheduler.concurrent", boolValue = false)

})

@Slf4j
public class TestScheduler implements Runnable {

...

}

Avatar

Community Advisor

I am not sure if I understood it correctly, but will an expression like below help ?

0 0 */4 ? * * - It will run every 4 hours starting next closest hour .. Unfortunately i could find one which start immediately

Avatar

Level 3

My bad

This was code that I've written for a project of mine and I wanted to remove anything that didn't have anything to do with your question. Seems like I missed something!

Anyway, that "tireDesignFactory" simply creates a new instance that implements Runnable, like your TestScheduler. (So it's custom code)

Your TestScheduler is not a scheduler, but a job itself. If you would use my example and create a factory that returns a new Runnable instance, then your scheduler service will schedule the job at a specific time, and you can also ask it to schedule a job right after you instantiate your bundle with the @Activate annotated method.

You would get something like this:

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.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;

@Component(service = CustomSchedulerService.class, configurationPolicy = ConfigurationPolicy.REQUIRE, immediate = true)

public class CustomSchedulerServiceImpl implements CustomSchedulerService {

   private String schedulerExpression;

   @Reference
   private Scheduler scheduler;

   @Reference
   private CustomJobFactory factory;


   @Activate
   public void activate(final Map<String, Object> config) {

        this.schedulerExpression = <YOUR CRON EXPRESSION HERE PREFERABLY FROM CONFIG>

          scheduleNow();

         scheduleLater();

   }

   @Override
   public void scheduleLater() {

   final ScheduleOptions scheduleOptions = scheduler.EXPR(schedulerExpression);
    scheduler.schedule(factory.createJob(), scheduleOptions);
   }

  @Override
  public void scheduleINow() {

    final ScheduleOptions scheduleOptions = scheduler.NOW();
    scheduler.schedule(factory.createJob(), scheduleOptions);
  }

}

------------------

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.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;

@Component(service = CustomJobFactory.class, immediate = true)

public class CustomJobFactoryImpl implements CustomJobFactory {

//you can use this class to get references from the OSGi container and pass those to your CustomJob instances

   @Override
   public void createJob() {

        return new CustomJob();
   }

}

--------------------

import org.apache.sling.commons.scheduler.Job;
import org.apache.sling.commons.scheduler.JobContext;

public class CustomJob implements Job {

   public CustomJob() {

 
   }

   @Override
   public void execute(final JobContext jobContext) {

   //do something
   }

}

Avatar

Employee Advisor

What do you want to achieve? Can we rephrase your requirement to something like this: "By default the scheduling interval should be 4 hours. In case it is taking more time, the process should not run in parallel, but serialized"?

In that case the section "preventing concurrent execution" of Apache Sling :: Scheduler Service (commons scheduler)  is covering that.

Jörg

Avatar

Level 4

If want to achieve that the scheduler runs directly on statup/after deployment but it seems it just starting after 4 hours for the first time and after that every 4 hours.

The problem is the scheduler pulls data into AEM and otherwise I have to wait 4 hours for the very first execution.

So the component shows nothing for the first 4 hours.

Avatar

Level 10

This is an interesting use case - when you setup a scheduler to fire every 4 hours - the first time it will count 4 hours.  See if you can modify the code to fire once 1 when its activated.

Avatar

Correct answer by
Employee Advisor

Hi,

I see. The only chance to get it working the way you want is to trigger the scheduled job manually on activation of a SCR component/service.

Jörg

Avatar

Level 4

Yes that what i thought, but then it will block all other components on startup because its maybe running for 30 minutes. So no chance to do it this way. I have to create a new Service and trigger it by a custom scheduler.

Thanks for all replies.

Avatar

Employee Advisor

I don't think that you need to do this. You can use the Scheduler API to immediately fire an event. But yes, you need to trigger that in an activate method.

Jörg

Avatar

Level 3

So would it come down to the example I provided? (More or less)

Avatar

Employee Advisor

I guess so. But please validate, that the case of some activations/deactivations of the component in a short time is handled properly :-) Depending on your deployment processes this might happen.

Jörg