How to Schedule Automation in Salesforce Using Apex Code

Find out why and how to schedule your automation using asynchronous Apex code. Learn the do's and don'ts of this asynchronous function.

In our current blog series on choosing the right type of Salesforce automation, we’ve explored the dos and don’ts of real-time automation in Salesforce, including workflow rules and process builder, flows, and Apex triggers. Then we talked about scheduling your automation declaritively using scheduled flows, process builders with Mass Action Scheduler, and DLRS.

This week, we tackle why and how to schedule your automation using asynchronous Apex code.

When Should I Schedule My Automation in Code?

As we’ve established in previous posts, you should always schedule your automation unless there is a business justification for running it in real time. (For example, lead assignment or time-sensitive email alerts). While it is possible to schedule some automation declaratively, it will still be subject to limitations around volume and batch size, which can lead to errors. Scheduling your automation using asynchronous Apex code can avoid some of the pitfalls of scheduling it declaratively.

What Do I Need to Know When Scheduling Automation in Code?

Don’t DIY code-hack. (Ever.)

For Apex triggers, we said to avoid copying and pasting code from the internet with no real understanding of how it works, even though you might get away with it in some simple use cases. But when it comes to coding scheduled functions, you should avoid DIY code in every case. Code-hacking can easily have catastrophic impacts on the greater coding environment and cause failures.

As a cautionary tale: We once had a client go DIY to implement a coded function in a future call. Unbeknownst to them, the function was initiated every single time any record was edited in their org. This created an overload to the Apex flex queue, which completely froze their Salesforce account until the queue was cleared. Obviously, this is a situation to avoid.

The truth is that declarative tools are getting so sophisticated that in most cases, you won’t even need code in the first place. But when you do need to use it, leave coding to the experts.

Select the right type of scheduled function.

There are 4 ways to run asynchronous Apex code, so you’ll need to pick the most suitable approach. Knowing which one to choose requires coding expertise: another reason we caution against going DIY.

1. Scheduled Apex

Use scheduled apex to ensure that your function only runs on the records you want it to, when you want it to. This is a good way to avoid volume issues, because it means your function is triggered by a specific schedule and not by user actions. Note: If you use the out-of-the-box Salesforce scheduler, you’ll be limited to 1 scheduled run per day. But in code, you can schedule jobs as frequently as once an hour. (If you need to run your job more frequently than once an hour, ask us about clever workarounds.)

2. Queueable Apex

This option is appropriate when you need to start a long-running operation and get an ID for it, pass complex types to a job, or chain jobs.

3. Batch Apex

Select this approach for long-running jobs with large data volumes that need to be performed in batches, or jobs that need larger query results than regular transactions allow.

4. Future Methods

Use Future Methods when you have a long-running method and need to prevent delaying an Apex transaction, are making callouts to external Web services, or to segregate DML operations and bypass the mixed save DML error.

For a complete description and more information on options for asynchronous Apex, visit this page.

Need a Salesforce

Understand that an asynchronous function cannot result in another asynchronous function.

You may run into one of these common errors: “Too many queueable jobs”, or “Future method cannot be called from a future.” These errors happen when one asynchronous function calls another asynchronous function.

If your asynchronous function triggers another asynchronous function, the code will detect that it’s being called by an asynchronous function and run itself immediately instead of triggering another batch.

For example, if a job that calculates an account score that runs nightly results in a future call to assign a lead, it will fail. This kind of failure is a safeguard against the possibility of triggering an endless loop within Salesforce (a function that would never stop running).

To make sure you’re protecting your org against this possibility, add the following to your code to check the state that the code is being called in:

if (System.isBatch || System.isFuture || System.isQueueable()) {

  // run regular code


else {

  Database.executeBatch(new MyBatch());