0

I would like to confirm the behaviour of asynchronous apex when an error occurs on its original/parent transaction.

Imagine we have a synchronous apex transaction (Transaction1-Apex) that launches a apex batch process (Transaction2-Batch).

Can I assume that if there is a uncatched exception in Transaction1-Apex after the executeBatch method has been called, the platform will also rollback or even not execute Transaction2-Batch?

Here is a more "graphical" representation of what I mean:

Transaction1-Apex
-
-
-
Database.executeBatch(...)          Transaction2-Batch
-                                           -
-                                           -
-                                           -
Uncatched exception                         -
-- Automatic rollback                       ... is this transaction also rolled back?

I assumed that was the case, asynchronous apex was always rolled back. However, I could not find confirmation in the official docs, then I found the following article indicating that there are some cases where this might not be true: https://smgoodyear.com/2015/12/04/asynchronous-apex-and-transaction-boundaries/

Has anyone investigated this in depth? If so, could you confirm or deny my hypothesis?

Thanks a lot everyone!

3

My understanding is that for most asynchronous invocations - including future, Queueable, Batchable, Schedulable - the invocation enqueues the operation but it does not execute until the end of the current synchronous Apex transaction. In case of an unhandled exception, these jobs are rolled back from the queue and don't execute.

However not all features work this way. Notably if you fire a Platform Event from a transaction that subsequently rolls back or has an unhandled exception, the Event (and any triggers on it, executed asynchronously) will continue unaffected.

6
  • They're supposed to be rolled back, but there have been known edge cases before. Trigger contexts can cause weird things to happen if an exception escapes the trigger's call stack.
    – sfdcfox
    Oct 16 '18 at 14:00
  • Interesting. I wonder if these edge cases mainly involve allOrNone = false? I know that weird stuff can happen with the rollback-rerun mechanism and triggers.
    – Charles T
    Oct 16 '18 at 14:03
  • I never did pin down the exact cause, but I did end up rationalizing that simply not throwing exceptions is the best policy. There's been three or four different behaviors in the past two years regarding how trigger exceptions are handled, and they're almost always not what we expect.
    – sfdcfox
    Oct 16 '18 at 14:06
  • 1
    @PranayJaiswal I couldn't come up with a repro, actually. I'd love to see it, but it may already be fixed in Winter '19 anyways.
    – sfdcfox
    Oct 16 '18 at 14:12
  • 1
    Thanks everyone for the answers, really appreciate them!! I actually also did my own testing and as @CharlesT said, everything is rolled back properly. Just be safe, I asked SF support to confirm the behaviour but they told me that I need to reproduce the case first, so no luck getting that info from them. For now I will operate under the assumption that the async transaction is rolled back (except platform events).
    – Pere Marti
    Oct 25 '18 at 9:17
2

Looks like things have changed since the time of writing that blog and now. I quickly tried doing it on API 44 Winter 19 org, after exception, the future/queueable don't get triggered.

public class MainClass {
    public static void mainMethod(){

        MainClass.futureMethod();
        MainClass.futureMethod();

        if(true){
            throw new DMLException();
        }
        System.debug('FInished');
    }

    @future
    public static void futureMethod(){
        System.debug('Future Called');
    }
}

In execute anon : MainClass.MainMethod();

When that blog was written, It was old Apex compiler which had few bugs. Starting Spring 18 A new Apex compiler is introduced and that might have potentially fixed this loophole.

That being said, I have been using future/queuable too often for my current project and I never faced the issue of they being called even if the current transaction wasnt committed to the database.

The behaviour you mentioned is actually a feature for platform events.

1

That blog post shows some lack of understanding of what's going on under the hood. One should not be allowing exceptions to escape a trigger context. Things can get really weird if you allow this happen. At one point the system had a bug that completely cancelled a transaction if an uncaught exception was raised in a trigger.

As long as you always use the appropriate error-handling techniques (e.g. always using addError to report errors), then future/queueable/batchable calls will roll back as expected. Do not use Platform events in a trigger if you have any reason to suspect your trigger may roll back, because those cannot be rolled back. Do not allow exceptions to escape a trigger, ever, because bad things can happen.

3
  • On the flipside, as Andrew Fawcett has documented, Platform Events can be a great method for logging errors precisely because they do not roll back.
    – Charles T
    Oct 16 '18 at 14:00
  • @CharlesT are you talking about developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… Oct 16 '18 at 14:08
  • 1
    @PranayJaiswal no that's a very specific feature that helps throw a defined Platform Event from batches. In general though if you publish a PE from any code that could get rolled back, the PE still proceeds. Which is great for logging any sorts of events or errors.
    – Charles T
    Oct 16 '18 at 17:32

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.