Salesforce Development: Apex Triggers

Salesforce Quick Tip – How to improve Apex Trigger performance by using Asynchronous Jobs

2 min read

Subscribe on YouTube

Why This Is Useful

Your trigger is slow. You’ve already bulkified it, you’ve pulled the SOQL out of the loops, and it’s still dragging. Users are sitting there watching a spinner every time they save a record.

The thing I see most often in slow triggers is an enormous amount of logic that doesn’t need to be there at all, because the user doesn’t need to see the result immediately.

And that’s the trick: if the user doesn’t need to see it right now, it doesn’t belong in your trigger. Hand it off to a Queueable job and let it happen a minute later. Nobody will notice, and the save gets its time back.


The Code

Create a class that implements Queueable:

Apex
public class AccountProcessorQueueable implements Queueable
{
    private List<Account> accounts;

    public AccountProcessorQueueable(List<Account> accountsToProcess)
    {
        this.accounts = accountsToProcess;
    }

    public void execute(QueueableContext context)
    {
        //All the slow stuff that nobody is waiting on
        for (Account acct : accounts)
        {
            acct.Description = 'Processed asynchronously';
        }
        update accounts;
    }
}

Two things: implement the interface, and take your data in through the constructor so execute() has something to work with.

Then enqueue it:

Code
System.enqueueJob(new AccountProcessorQueueable(Trigger.new));

That’s it. The save completes immediately, the heavy work happens in its own transaction shortly after.


Please Don’t Put That Line In The Trigger

I showed it that way because it’s the shortest possible demonstration. In real code that enqueueJob call belongs in a trigger handler or a domain class, not in the trigger file itself.

Your trigger should stay one line. Same rule as always.


The Bonus You Get For Free

Going async doesn’t just make the save feel faster, it also roughly doubles your governor limits. 200 SOQL queries instead of 100. 12MB of heap instead of 6MB. 60 seconds of CPU instead of 10.

So if your trigger is bumping into limits rather than just feeling sluggish, this can solve that too.

You can also make callouts from a Queueable, which you flat out cannot do after DML in a synchronous trigger. Add Database.AllowsCallouts to the class and you’re away.


What To Watch For

Errors go quiet. There’s no user watching, so a failure just… doesn’t happen visibly. Log your failures somewhere you’ll actually look.

You get 50 queued jobs per transaction. Don’t enqueue one per record, enqueue one job with all the records.

Tests need Test.startTest() and Test.stopTest(). The async work only runs at stopTest(). Forget the wrapper and your test passes without testing anything, which is a fun way to get a false sense of security.

More detail in my complete guide to asynchronous Apex.


Get Coding With The Force Merch!!

We now have a redbubble store setup so you can buy cool Coding With The Force merchandise! Please check it out! Every purchase goes to supporting the blog and YouTube channel.

Get Shirts Here!
Get Cups, Artwork, Coffee Cups, Bags, Masks and more here!


Check Out More Coding With The Force Stuff!

If you liked this post make sure to follow us on all our social media outlets to stay as up to date as possible with everything!

Youtube
Patreon
Github
Facebook
Twitter
Instagram


Salesforce Development Books I Recommend

Advanced Apex Programming
Salesforce Lightning Platform Enterprise Architecture
Mastering Salesforce DevOps

Good Non-SF Specific Development Books:

Clean Code
Clean Architecture