LinkedIn

Flows - Exception Logging using Fault Connectors & Platform Events - Implications

Since count of flows are getting increased day by day, it is also becoming really important to handle and log exceptions from flows, so that we can track what went wrong during your current execution. Let us see how to handle exceptions in a flow using fault connector, and what will be the transaction behavior after adding a fault connector to the flow.

Scenario:

Update Account Country from Contact to Country field in Account - Flow on Contact

Example :

Account - Account ABC
Contact 1 -> Country ->India
Contact 2-> Country->United States

On Contact 2 save Country Value on Account should be India, United states.

Scenario 1 - Contact Save Success 

Below is the flow which will be updating Account with child contact country values:



For the Above, flow execution will be as follows:

1. User create a new Contact with Account as Account ABC and Country as India.


2. Flow is getting executed and Flow updates Account country as India in Account as sown below.


Scenario 2 - Update Failed because of Flow exception

To see how the transaction is behaving on a flow failure, let us add a validation rule under Account which makes Account Number mandatory on Account update:


Now let us create another contact and check behavior. Contact creation is failing with below error message:




Now as a best practice, we need to handle this exception.

Scenario 3 - Handle Exception

As a best practice I would like to log all exceptions happening in my Org to an Exception custom Object.

For this let us create a simple Exception object as shown below:


How to handle Exception in a flow?

To handle Exception, we need to add a fault connector to the record update operation as shown below. 



Fault connector identifies which element to execute when the previous element results in an error. Fault connector is the second connector from a node which executed a DML or query statement.

A fault connector can have any target element but only the following source elements:
 In the below demo, you can see how I have added fault connector and what will be the  transaction behavior once you add fault connector.



Transaction behavior

When you add a fault connector to a flow and if the flow is getting failed, the record save will be still success,  since the exception is handled. But the flow action will be failed. This is same as an Apex class behavior when you add try - catch block.

Scenario 4 - Log Exception and fail the complete transaction

We might have situations where you want to log exception and wants to fail the complete transaction. But we have seen that if you have a fault connector - transaction will be a success.

In Apex classes you have an option to throw exception after catching and logging error details. So let us see if we can add that behavior to a flow.

I couldn't find any standard approach in a flow to throw exception. So I have created an invocable Apex method, which can throw our flow exception.

Apex Class which throw Exception:





In the below demo, let us see what is the transaction behavior after throwing Exception.



Transaction Behavior

When we added throw exception statement - entire transaction got rolled back and as a result even exception logging didn't happen. So how can we solve this problem?

Scenario 5 - Log Exception using Platform Events

This issue can be solved by logging exception using Platform events. 

Create Platform Event


Create a new Platform Event as shown below. Fields are same as what we have created in Exception object.


Make sure that Publish Behavior is Publish Immediately.

We have got 2 publish behavior in platform events:

Publish After Commit to have the event message published only after a transaction commits successfully. With this option, a subscriber receives the event message after the data is committed. If the transaction fails, the event message isn't published.
Publish Immediately to have the event message published when the publish call executes, regardless of whether the transaction succeeds. With this option, a subscriber might receive the event message before the data is committed.

Let us see what will be the transaction behavior after publishing Exception event instead of logging details to Exception object.



Transaction Behavior

Current Transaction got failed but still you can see exception record got created. How this is happening?

Since the platform event behavior is Publish immediately - it will not wait for complete transaction commit. So even if the transaction failed, platform event will be still success.

And I have created a trigger to process this platform event and log details to Exception Object using a trigger on Platform event.


You can also use a Process builder to process platform event and log details to Exception Object. But you have more control when you are using a trigger and performance will be better.

If Platform events can store the same details why we need a trigger on platform event to log the same details to Exception object? This is because of the below reasons:

1. You cannot create reports based on platform events record
2. You cannot query and retrieve details form platform event
3. You cannot create formula fields on Platform event if you want to do some additional processing.

Publishing platform events actually consumes 1 DML. So if we want to save this, we can move event publishing to an invocable method and make it queueable. 

To conclude -  Usage of Platform Events is the best approach for logging exceptions considering all different transaction scenarios.

P.S. - Please let me know if you have tried out a different approach for flow exception handling and logging. One problem I found here is that, I am not able to display a custom message when auto launched flow exception happens, even though I can see it in debug log.

Invocable Apex Class for throwing Exception below for reference:

public class ExceptionUtil {
public class MyException extends Exception {}
@InvocableMethod(label='Invoke ExceptionUtil')
    public static void throwcustomException(List<String> excmessage){
       
            throw new MyException('An internal exception happened during current operation.'+ 
                                  'Please contact system administrator with this exception details:'+excmessage[0]);
        
    }
    
}

Test Class

/************************
 * Test class for ExceptionUtil
 * **********************/
@isTest
public class ExceptionUtilTest {
    @isTest static void testTrhowException(){
        Test.startTest();   
        try{
            ExceptionUtil.throwcustomException(new List<String>{'Throwing custom Exception'});
        Test.stopTest();
        }catch(Exception ex){
            System.assert(ex.getMessage().contains('Throwing custom Exception'));
        }
        
       
    }
}

Comments

  1. Thank you for this post - very clear and easy to understand!

    ReplyDelete
  2. Best demo explaining how did you reach the best solution with different options.

    ReplyDelete
  3. Hi Meera, I followed your flow examples and code to the letter, however my exception log records are not populating the Object and Operation fields. In my flow were we create the exception log, the object and operaton fields are mapped to text variables. How are you populating those text variables with values? Is there another piece of code or somewhere in your process builder setting those field values?

    ReplyDelete
    Replies
    1. When I created those variables, I set the default value as the required value. For example, in the given scenario, the variable Objectname is populated with default value as "Account". Similarly populated other variables also.

      Delete
  4. Hi Meera,very informative blog.

    ReplyDelete
  5. Meera Hi,
    This is a great article, thank you very much for sharing!!!

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Meera Hi,
    As you pointed out the error message you've created was not displayed. So, if I understand correctly, we will add the Apex Action if we want the flow to throw an exception but the error message that will be displayed is the the standard one, right?

    ReplyDelete
    Replies
    1. Yes, you are right. But I was able to see the custom error message in the debug log.

      Delete
  8. Excellent article Meera. I am a newbie in Flows and looking for all the usecases to implement.
    Can you please share your flow logic along with variables and elements that you are using in this article.Appreciate it much.

    ReplyDelete
  9. Hello Meera, I am not able to generate exception logs. Even my trigger on Exception_Log__e is not calling during whole transaction. I followed same steps suggested by you.

    ReplyDelete
  10. For some reason the images in this post are not being displayed :(

    ReplyDelete

Post a Comment

Popular posts from this blog

Subscribing to Salesforce Platform Events using External Java Client - CometD

Send Data from Salesforce to Data Cloud using Ingestion API and Flow

How to develop reusable Invocable Apex methods for Flows