2

I have a class that I want to schedule every 5 mins in apex. I have implemented the schedulable interface and I'm using the anonymous apex to create the scheduled jobs and start it locally.

I have a few questions regarding that -

  • I wanted to know whether this is the standard way to invoke a schedulable class?
  • This class would be part of a managed package and I want to invoke the scheduled jobs when the package gets installed without having to go and run anonymous apex. Is that possible?
  • Do I need to consider race conditions here. Ideally there would be only one job running at a time but Apex Schedular documentation mentions that "Actual execution may be delayed based on service availability." So can I have two instances running at the same time?
  • Anything else I need to be aware of while creating schedulable jobs in apex.

Thanks in advance

1
  • Standard way is via UI. - You could provide a post install or setup screen where the user could click a button to schedule. You could try a post install script as well. - Yes, you will need to consider it. Thats why I only schedule one batch and have the finish method start the next one 5 minutes later
    – Eric
    Jan 8, 2017 at 6:04

1 Answer 1

4

I wanted to know whether this is the standard way to invoke a schedulable class?

Many ISVs include a Configuration page, which is just a Visualforce page configured as a Home Page Custom Link and configured as the Managed Package's configuration link. From there, they usually have a button or link to call some Apex Code that performs the scheduling. It's more user friendly than asking admins to run code.

This class would be part of a managed package and I want to invoke the scheduled jobs when the package gets installed without having to go and run anonymous apex. Is that possible?

You can use an InstallHandler, which allows you to run code upon install. Normal asynchronous rules apply, so be aware of governor limits, and do consider trying it out in an ISV trial org before you give it to your customers.

The interface is a single function that accepts an InstallContext object:

global interface InstallHandler {
  void onInstall(InstallContext context)
};

You implement as you would any other interface:

global class OurPackageInstallHandler implements InstallHandler {
  global void onInstall(InstallContext context) {
    // Do stuff here
  }
}

The InstallContext has the following features:

global interface InstallContext {
  ID organizationId();
  ID installerId();
  Boolean isUpgrade();
  Boolean isPush();
  Version previousVersion();
}

As you can see, it gives you some basic information about any prior context and some basic organization information. In onInstall, you can go ahead and schedule your class.

Do I need to consider race conditions here. Ideally there would be only one job running at a time but Apex Schedular documentation mentions that "Actual execution may be delayed based on service availability." So can I have two instances running at the same time?

In theory, yes, you could. In practice, it's incredibly rare that the scheduler is so delayed that multiple instances would be running at once, especially since the scheduler prefers to load balance over all orgs' jobs, which means that you should rarely experience this problem. I'd say use "FOR UPDATE" on any records you need to query, which will row-lock relevant records to avoid duplicate processing in those rare circumstances. It should be okay in most cases.

Anything else I need to be aware of while creating schedulable jobs in apex.

You main problem is going to be that there's no convenient way to specify "every five minutes" as an option. You can only schedule hourly at minimum. This means you're going to have to deal with either "suicide scheduling", where your job aborts itself and schedules itself for five minutes later, or you're going to have to schedule 12 different jobs so they're staggered five minutes apart. Now, we do get 100 scheduled jobs, but most orgs are probably already pushing that limit, so you'll need to consider if that's the best idea.

Also, remember that jobs do not execute precisely at the scheduled second. I'm not sure what you're doing, but you're likely to miss records if you use time stamps/audit trail fields. You may have to resort to using some sort of queued job Custom Object to keep track of where you left off, or perhaps via Custom Settings. Not being able to depend on the exact start time means you should take extra care.

3
  • Thanks so much for the detailed response. Much appreciated. Glad you mentioned about the scheduled jobs limit in orgs, I was planning on implementing the 12 different jobs way which is not optimal. I changed the implementation to the suicide scheduling approach which sounds much cleaner. A quick question there, I read the following and salesforce.stackexchange.com/questions/119655/… and implemented the schedular to reschedule itself every 5 minutes before aborting the current job.
    – gerad26
    Jan 8, 2017 at 11:38
  • contd .. How do you make sure that it stops rescheduling itself after an hour and falls back on the hourly schedular? I'm using the following cron expression --> Datetime sysTime = System.now().addSeconds( 300 ); String chronExpression = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year(); . Do I need to have additional logic to check if the parent which started the child jobs is one hour old?
    – gerad26
    Jan 8, 2017 at 11:39
  • @SFuser11 Using your cron expression, there isn't an hourly replay. It'll run once, and if it crashes for any reason, it'll be stuck permanently until someone restarts your job. The hourly method that I mention in some previous answers is a defensive measure. Without it, once your job dies, someone has to fix it. By leaving the hour, day, month, and year as a wild card, it gives you an opportunity to resume automatically in an hour.
    – sfdcfox
    Jan 8, 2017 at 15:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .