0

I'm working on implementing a robust error logging framework for our org using Platform Events to ensure that we always capture errors in our code even if the transaction is rolled back.

If I use Database.insert(listRecords,false), I parse the Save/Upsert/etc Result List for errors and then log those errors. In scenarios where I am explicitly using allOrNothing = false, I expect partial DML and for the transaction to be at least partially committed to the database, so this works great in situations like this.

However, when it comes to try{}catch(DMLException){} exception handling, what I am looking for is the ability to still capture/handle the DML Exception, but have Salesforce perform a full transaction rollback the same way that it would if it had encountered an unhandled exception.

From my understanding of rollback, it only works if I first create a savePoint, but if I only create my savePoint before the DML that I am handling exceptions for, then everything that occurs in the transaction prior to that savePoint would still be committed to the database (for example, before insert/before update field changes made before the failing DML).

Question: Is it possible for us to both handle the exception for logging purposes AND rollback the entire transaction?

3
  • 2
    AFAIK no. And some exceptions (e.g. governor limit ones) can't be caught in any case. You could Google on using publish immediately Platform Events to handle the catchable ones.
    – Keith C
    Jun 8, 2021 at 18:01
  • Note that delivery of platform events is not guaranteed (though such failure should only happen in extreme cases).
    – Phil W
    Jun 8, 2021 at 19:21
  • You could, in the exception handler, create and publish an immediate publish behaviour platform event and then re-throw the caught exception to cause the transaction to fail. The important point: all exception handlers in the stack must re-throw. You might find you generate multiple events for the same reason at different levels in the call stack if you are not careful.
    – Phil W
    Jun 8, 2021 at 19:23

1 Answer 1

0

I ended up solving this as best as I could using a custom exception which I use to re-throw the exception after publishing the Platform Events related to the logging framework.

The rough implementation is something like this:

try{
  // Do some Things
}catch(Exception ex){
  logger.error('Message',ex);
  logger.saveLogs();
  GeneralException.rethrow(ex);
}

The contents of GeneralException are:

public class GeneralException extends Exception {
  public static GeneralException rethrow(Exception ex) {
    GeneralException ge = new GeneralException();
    ge.setMessage(ex.getMessage() + GENERAL_EXCEPTION);
    throw ge;
  }
}

This obviously won't account for things that are uncatchable, such as Governor Limits as mentioned by Keith C, but for situations that can be caught it seems to serve its purpose. By using Platform Events that publish immediately, I can publish the Event before throwing the exception, then throw it to roll back the whole transaction. The Platform Event is then picked up by an Apex trigger and logged into a Log object.

Seems like as close to a perfect solution as I'm going to get within the boundaries of Apex.

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.