Home SalesforceApex Avoid Batch Apex and Use Queueable Class

Avoid Batch Apex and Use Queueable Class

by Dhanik Lal Sahni

Salesforce has four asynchronous apex ( Queueable Apex, Scheduled Apex, Batch Apex, Future Methods) to run code asynchronously to handle different need of business application. These apex is used for syncing data in two systems, handling longer jobs which will hit Salesforce Governor limits. These asynchronous apex can be used in different use case. This post is to explain where to avoid batch apex and use Queueable Class instead. Although there are lot of use cases where batch job is sufficient to handle processing.

This post will explain how to handle callout issue You have uncommitted work pending. Please commit or rollback before calling out

Use Case To Solve:

We have around 30K+ account records of health care providers, we need to validate address of all records using address API (any API like SmartyStreet, Google Places, ZipCode ). After API call we need to update record with outcome of API call like address validation is successful or failed in ValidationStatus field. ValidationStatus is custom field in account object. All health care data are stored in account object.

Solution:

To solve this use case we can use batch apex which will handle 200 records (100 in case of callout in batch) in a single batch and batch job will be created for all records. As it will run in batch, we have to put some condition in batch SOQL so that it will not process same record again and again. So we can use query like

Select id, ValidationStatus__c from Account where ValidationStatus__c=false

This will only process record which is pending but there is another problem with this approach. As validation is not successful due to some reason that record will be pending and same records will be fetched in each job for process. This issue we can handle using adding another filter last modified date in SOQL

Select id, ValidationStatus__c from Account where ValidationStatus__c=false and LastModifiedDate<>TODAY

Using this batch it will solve issue of not processing same record again and again. We will face another problem after that is , if we want to re-process pending record or error records after correction, it will not re-process those record on same day.

So what will be efficient solution for our use case. Can we use another asynchronous apex as we have lot of records to process? Yes, we have to use another asynchronous apex Queueable to handle this. We can query all pending records in one parent queueable class and then process records in another queueable class which will support callout. We will run chain of Queueable child class to process 100 records at once. Once 100 records are processed, start another queueable child job. This way we can call external system and make list of records to update before we start another job. This way we can avoid uncommitted work pending issue also.

Uncommitted work pending issue throws when we are calling external system and then updating response in object, when system start processing next record, previous records is still pending for commit so we get that error. This issue will be address by below approach

  1. We will call external callout for reach record one by one
  2. We will not update records immediately, instead we will add all records in collection
  3. Once 99 records are processed, we will start new queueable job for processing another set of 99 records
  4. Before we start new batch, we will update all records for status update.

Above approach will handle issue uncommitted work pending for commit issue.

Let us see code for this solution

Above queueable apex code is getting all records which need to process and passing all records to another child queueable class. As we are passing all records to child queueable class we don’t require to run this class multiple time. So if any error occurs for any records and we want to re-process those records, we can run this class once again after record correction.

Let us see code for child queueable class which will process each record and also handle uncommitted code pending issue.

AddressVerification class do external callout to Smarty Street address API. External callout code is available in another blog Generic Apex class for Calling External System. To store API detail, I have used named credential SmartyStreet which will store API url https://us-street.api.smartystreets.com/street-address , username and password.

AddressValidationQueueable is child queueable class which will call AddressVerification class for each record and add those accounts in list. Once set of 99 records are processed, we will update those records and start new child queueable class to process next set of 99 records. We are also removing that record from list so that it will not process again.

Why 99 records in one batch?

As we can call only 100 records in one batch in asynchronous apex. I have used 99 records instead of 100 but you can use 100 as well.

Reference:

  1. Generic Apex class for Calling External System
  2. Revisit Asynchronous Apex : Type and Usage
  3. Queueable Apex
  4. Smarty Street API

Related Posts

  1. Handle Heap Size for Apex Code Optimization
  2. Enhance Apex Performance with Platform Caching
  3. Apex Trigger Code Optimization
  4. Optimize Code by Disabling Debug Mode
  5. Optimizing Salesforce Apex Code
  6. Optimizing Loop in Apex Code

If you need more discussion on this topic, let us connect for discussing and implementing this pattern.

You may also like

10 comments

Optimizing Salesforce Apex Code | SalesforceCodex December 8, 2021 - 7:23 pm

[…]  Avoid Batch Apex and Use Queueable Class […]

Reply
Ronen May 3, 2022 - 10:26 pm

Hello thanks for a great solution,
I tried this yesterday and it all works fine with above 200 records, suddenly I started to get this error
Too many queueable jobs added to the queue: 2
Any Idea why this happened ?
TIA

Reply
Dhanik Lal Sahni May 6, 2022 - 6:44 am

Hello Ronen,

This error will come when you are creating many queueable parent jobs. We should create new queueable job from child queueable class like i have mentioned in AddressValidationQueueable.apxc lines #48-50. I am not creating new job from AddressValidationQueueableRunner, this is done in AddressValidationQueueable.

Let me know if this is not working.

Thank You,
Dhanik

Reply
Queueable Vs Batch Apex In Salesforce - Salesforce Codex - Stories June 28, 2022 - 11:09 am

[…] blog  Avoid Batch Apex and Use Queueable Class to understand where we shoudl use Queueable instead of Batch […]

Reply
C Wallace July 22, 2022 - 2:23 am

Question. Why call processTargets(accts) twice? Why not call if before the the If statement? Seems like an issue to concise coding. Unless I’m missing something?

Reply
Dhanik Lal Sahni July 23, 2022 - 7:13 pm

Thank You, Wallace. It should be called only once before queuing a new job. I have updated the code.

Regards
Dhanik

Reply
Viraj October 13, 2023 - 7:34 pm

What if I only need to process 10 records at a tine?

Reply
Dhanik Lal Sahni October 13, 2023 - 9:40 pm

Hello Viraj,
Please check updated code. processTargets(accts) should be out from if loop.

Thank You,
Dhanik

Reply
Boost Performance of Salesforce Service Cloud - Vagmine Cloud Solution December 19, 2023 - 8:44 pm

[…] Asynchronous Apex allows you to do long-running or resource-intensive operations in the background without interfering with the user interface’s performance. This is especially handy for things like mass emailing or processing massive amounts of data. […]

Reply
Queueable Vs Batch Apex In Salesforce February 7, 2024 - 1:04 pm

[…] out the blog Avoid Batch Apex and Use Queueable Class to understand where we should use Queueable instead of Batch […]

Reply

Leave a Comment