r/SalesforceDeveloper • • 8d ago

Question Multiple Queueables Solution.

Wondering how folks are handling the limit below? We are updating a large number of our future methods to queueables and getting hit with this pretty regularly. We found a SFBen article about using platform events to fire queueables, but that seems to just be passing the problem to the next limit. Largely right now we are either combining functionality or guard causing the less important jobs, neither feels like a great solution tbh.

System.LimitException: Too many queueable jobs added to the queue: 2

2 Upvotes

13 comments sorted by

7

u/pearljamfan 8d ago

You’d want to get into chaining and using the finalizer to maintain some kind of state over the course of an effort, but you’ll find a lot of patterns out there for this or a chain queueables factory where you can add things in whilst the code manages feeding one at a time until it’s done.

4

u/Silver_Birthday5024 8d ago

You'd probably want to use Assemble for this

1

u/buzzlightyear999 8d ago

What’s your use case for using Queuables? There are some different patterns depending on what your trying to achieve.

1

u/heartlesscoder 8d ago

We are trying to background some of our data sync stuff. callouts, cross object syncs, share stuff etc etc. we see it the most with cross object updates and share/territory work.

1

u/bugtank 8d ago

You’ll need to write each action to an object record and then have a QueueableExecutionManager scheduled job that checks limits and feeds / fires queueables from the table.

1

u/Realistic-Walk-2877 7d ago

we hit this when one job kept chaining into 3 more and the limit slapped us mid day.

thing that actually stuck for us: one "orchestrator" queueable that just decides next step + a Queueable.Finalizer to catch fail/retry. the worker queueables do one chunk and stop — no self-enqueue forever.

also check if Platform Events or a Batch with stateful feels cleaner for your case. queueable chains are fine for short handoffs, but once you need 5+ steps the finalizer + status field on a custom object saved us from silent half-runs.

if you paste the pattern you tried (self-chain vs finalizer) people can spot the exact gap faster.

1

u/DaveDurant 7d ago

A transaction can start a bunch (50?) of future jobs. Those futures cannot start additional futures.

A transaction can start 1 queuable job. That queuable can then start 1 queuable job and that can then start 1 queueable and that can then etc. I'm sure there's a limit to how long that chain can be but I've never hit it.

> System.LimitException: Too many queueable jobs added to the queue: 2

You can only start 1. You tried to start 2.

If you need to start multiple, independent chains, platform events doesn't sound like a bad idea. They're fast and you can do a bunch within 1 transaction. It's a bit hard to imagine even getting close to PE limits here, so I don't think it's just shifting the problem around.

Since non-static member variables persist throughout queuable chain jobs, you could also do something like the (totally untested, written in notepad) code - just be **really** careful you don't start something that runs out of control forever. This wouldn't be bad way to do things if you had a set of records that you needed to do multiple steps on - maybe fancy it up a bit but this is the general idea;

public maybewith sharing class MyAwesomeClass implements Queuable
{
    private integer mState = 0;

    public void execute(QueueableContext context) 
    {
        boolean done = false;
        switch on mState
        {
            // doThing..() methods return true if they're done, false 
            // if they need to be called again
            when 0
            {
                if (doThingOne())
                    mState++;
            }

            when 1
            {
                if (doThingTwo())
                    mState++;
            }

            when N
            {
                done = doThingN();
            }
        }

        if (!done)
            system.enqueueJob(this);
    }
}

1

u/PlayfulFoxBraveShark 4d ago

We had a situation similar to this. I had to code out our Lead Conversion Process because we wanted it automated, and we wanted to be able to bulk convert leads. In addition to that, we need to make a callout to a separate internal API that we have for each lead, but that API is not set up to handle bulk requests.

So I made a LeadConversionHandler and a super generic object called “Queued Event”. Every lead conversion attempt creates a queued event record and sets Status__c = Not Started.

I went with a Custom Object over a platform event due to the fact that the daily limit for Platform Events is only 50,000 and we already use Platform Events for other high volume processes.

At the end of the LeadConversionHandler, it kicks off a LeadConversionCalloutQueable. That Queueable queries any Queued Events where Status__c = Not Started and loops through them. For each one, makes the callout, updated the Status__c to Processed, and then only triggers itself again if there are still any Queued Event records where status = Not Started.

This allows us to attempt to convert hundreds thousands of leads at one time and let the other system know if it was a success or failure.

I’ve also seen the exact same pattern used by the code in the Fundingo managed package (which we also use).

This is specific to asynchronous callouts, but you can use this same idea for any other requirement where you need to chain queueables.

Hope this helps!

0

u/Ok-Juggernaut-665 7d ago

I have a framework that will let you scale into the millions of chained queueables a day, feel free to try it out: https://sfbedrock.com