BatchApexErrorEvent is a standard platform event introduced by Salesforce as part of API version 44.0. This mainly helps us to get the details of unhandled exceptions that happened from Batch Apex.
To fire exception details to BatchApexErrorEvent, Batch Apex should implement Database.RaisePlatformEvents interface.
Let us cover below in detail:
1. BatchApexErrorEvent Details
BatchApexErrorEvent holds below details:
Let us implement a batch apex and see how BatchApexErrorEvent is helpful for tracking unhandled exceptions.
2. Sample Batch Apex Scenario
Both Account and Contact has a field called Active__c which contains 2 values - Yes, No. When a parent Account is getting deactivated,ie Active=No, we need to mark all child contact's Active also as No.
Batch Apex LogicBelow Class is implemented to solve this.
You can see that this class has implemented Database.RaisePlatformEvents interface.
public with sharing class Batch_ContactDeactivation implements Database.Batchable<sObject>,Database.RaisesPlatformEvents {
3. How to Subscribe to BatchApexErrorEvent
We can subscribe to this platform event in multiple ways like shown below:
4. Subscribe Using Flow
Let us subscribe to this event using a flow and log exception details to a custom object called Exception.
The exception object looks like below:
Create new Flow of type Platform-Event Triggered flow
And select auto-layout format.
Choose platform event as Batch Apex Error Platform Event
The flow will look like below at this stage:
Click on '+' symbol and add a 'Create Record' element.
Select Object as Exception:
And for field mapping select record -BatchApexErrorEvent
The final mapping looks like below:
Save and activate this flow.
5. Exception Scenarios and BatchApexErrorEvent Behavior
Scenario 1 - Unhandled DML Exception
To produce a DML exception during contact update, I added a validation rule in contact, making Email field a required one.
Also I removed the Exception handling around contact update operation:
Now for some Accounts which has associated contacts, make Active value as No, and also make sure, it has contacts with Active as Yes and Email as empty.
Account:
Contact:
Batch_ContactDeactivation reassign = new Batch_ContactDeactivation();
ID batchprocessid = Database.executeBatch(reassign,5);
Result:
Under Apex Jobs you can see that batch failed with DML exception due to validation error:
Now let us check the Exeption Object and we can see that a new Exception record got created with Exception details received from BatchApexErrorEvent.
Under Record ID - you can see that all contact Ids in the current scope got populated there.
This is utilizing the "JobScope" field of BatchApexErrorEvent.
Scenario 2 - Handled DML Exception
Now let us uncomment exception handling and execute once again.
Since we handled the exception, you can see under Apex jobs that it got completed withour throwing any error.
Since the exception got handled, no event got published under BatchApexErrorEvent also.
Same behavior will happen for a DML Exception, when we use Database.update instead of update.
Scenario 3 - Unhandled Query Exception
Let us see another exception scenario here.
In the query getting executed as part of batch, suppose the field name is added wrongly.
Example
String query = 'select id from Contact WHERE account.Active__c=:inactive AND Active__c=:active';
In the above query instead of Active__c in contact, we added Active only by mistake:
String query = 'select id from Contact WHERE account.Active__c=:inactive AND Active=:active';
Now execute the batch.
Under Apex Jobs, we can see that batch execution failed:
Also we can see a new Exception record got created from BatchApexErrorEvent.
Here, record ID is empty since the query itself got failied and we don't have any records in the current scope.
So the above scenario is a good use case of unhandled exception which can be tracked using BatchApexErrorEvent.
In addition to the above, BatchApexErrorEvent will hold any kind of unhandled exception from Batch which include:
- Batch Execution Limit related Exceptions
- Unexpected Exception
- System Exception
Another advantage of this approach is that, based on the Exception type if we would like to reexecute specific batches,
we can build a retry logic around these exception records.
References:
- https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/sforce_api_objects_batchapexerrorevent.htm
- https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_platformevents.htm
Hi Meera , can you also show an example how u can we can achieve
ReplyDeletethe below statement
Another advantage of this approach is that, based on the Exception type if we would like to reexecute specific batches,
we can build a retry logic around these exception records.
My idea was around exceptions caused by Batch Apex limits/concurrent Access Issues etc. which might be a success if we rerun for those records later. So we can build a batch process around exception Object for the specific exception types and execute those specific failed batch processes, but only for those failed record Ids mentioned in Exception Record. Yes, might not be simple but I think it is feasible.
DeleteHi Meera ,
ReplyDeleteThanks for the great explanation. I second Abhishek , i think many individuals will be benefitted by the re execute logic example.
Very informative article. Thank you
ReplyDelete