Run a batch in every other 15mins in the clock (i.e. clock time 00:15, 00:30, 00:45 01:00....).

Method 1 - create a schedulable to run the batch every 15mins.

  • Pros: it allows me, in execute() method of schedulable, to check if the batch is already scheduled or running so it can abort if needed.

  • Cons: I need to create 4 separate schedulable instances.

Method 2 - use System.scheduleBatch() to run the batch every 15mins.

  • Pros: no need to create 4 instances
  • Cons: it seems no place/hook to allow me to check if already scheduled or running right before the batch starts.


No ideal solution, either way has opposite pros&cons.

  • 5
    Are you trying to run the batch every fifteen minutes, or fifteen minutes after the last time it has completed? What if the batch takes more than 15 minutes? What problem are you actually trying to solve? Right now, it sounds like an X-Y Problem.
    – sfdcfox
    Nov 13, 2019 at 17:34
  • NB: if you use the same name every time you try to use scheduleBatch then if it is already scheduled you will get an exception when you try to add it again. In terms of making sure only one batch instance runs at a time you can check this robustly in the batchable's start method by querying the Async Apex Jobs for this type of batch. This is robust since start will not be called concurrently on a given org.
    – Phil W
    Nov 13, 2019 at 17:52
  • Sorry, it is the former (every 15 mins), I updated the description. I aim to see what is a better way to fulfill this requirement.
    – Xi Xiao
    Nov 14, 2019 at 8:58
  • @PhilW if we check in the start method, I assume the batch has technically already been initiated thus I need to run system.abort to stop the current batch?
    – Xi Xiao
    Nov 14, 2019 at 9:00
  • Yes, it has technically started and will have consumed 1 async call, but this is quite robust. Clearly you can also query the async jobs table before scheduling the batch as well to help avoid hitting this scenario in the first place (where you already have the batch running and you are about to schedule a second run that might overlap). You can't use System.abortJob, since that requires permissions not normally granted to users (just admins). However, you can trivially change the return from start to be an entirely empty query (add LIMIT 0, for example) or you can throw an exception.
    – Phil W
    Nov 14, 2019 at 9:50

1 Answer 1

  1. When using System.scheduleBatch, if you always use the same name every time for scheduling this batch, an attempt to schedule the batch whilst it is already scheduled will result in an exception and the batch won't get double scheduled.
  2. You can use the Async Apex Jobs table to provide info about whether the specified batch is already executing and you might do this before scheduling the batch.
  3. By adding this "already executing" test also into the batch's start method (see this answer for more info) you can ensure that if a second instance does manage to start (due to race conditions, for example) you prevent this from actually doing anything by throwing an exception, returning a query locator with LIMIT 0 or by returning null - the middle option is cleaner and errors are not reported to admins in this case, but this will consume an additional async call when finish is invoked).
  4. The batch finish can look to re-schedule itself either with a fixed 15 minute delay or by aligning with the real time clock (on the hour, quarter past, half past or quarter to) as needed.

NB: If something causes the batch to exit abnormally before it re-schedules itself there's nothing here to get the batch going again of course...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.