Retrying Failed Callouts in Salesforce Apex
In this blog, we’ll discuss best practices for retrying failed callouts in Salesforce Apex.
In Salesforce Apex, callouts are used to communicate with external systems and APIs. However, callouts can sometimes fail due to network issues or API errors, leading to errors in your Apex code. To improve reliability and error handling, it’s vital to implement retry logic for failed callouts.
Requirement Overview
- To have a callout 3 times based on defined response.
- Callout should not be done frequently based on responses (Considering the callout limit).
- At the time of specific responses, it should wait for a certain amount of time gap and then go for retry.
Solution Approach
- We can approach this requirement using two apex classes .
- To maintain the time interval between two callouts you can implement a Schedulable interface.
- You can schedule the failure callout to retry after 5 minutes as continuous hitting can put your server flooded. (recommended)
Below code will help for callout understanding:-
RetryCallout.cls
global with sharing class RetryCallout {
public static HttpResponse getResponseFromExternalCallout() {
HttpResponse response = new HttpResponse();
try {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('demoEndpoint');
request.setMethod('POST');
request.setHeader('Content-Type','application/json');
response = http.send(request);
return response;
}
catch(Exception e) {
//log exception
}
return null;
}
public static void performActionBasedOnResponse(HttpResponse response,Integer iRetryCount) {
if(response.getStatusCode() == 400 || response.getStatusCode() == 404 || response.getStatusCode() == 500) {
//go for retry
//capture log
scheduleJobOfFailureCallout(iRetryCount);// calling schedule function
} else if (response.getStatusCode() == 201) {
//capture log
} else if (response.getStatusCode() == 501) {
// capture log and don't do retry
} else {
//capture log
}
}
public static void scheduleJobOfFailureCallout(Integer iRetryCount) {
try {
if(iRetryCount < 3) {// here 3 is the count of retry ,you can configure according to your requirement
DateTime Dt = system.now().addMinutes(5);// adding 5 minutes to current time (you can configure your own)
String day = string.valueOf(Dt.day());
String month = string.valueOf(Dt.month());
String hour = string.valueOf(Dt.hour());
String minute = string.valueOf(Dt.minute());
String year = string.valueOf(Dt.year());
String ScheduledTime = '0 ' + minute + ' ' + hour + ' ' + day + ' ' + month + ' ?' + ' ' + year;
ScheduleCallout Job = new ScheduleCallout(iRetryCount);
System.schedule('Schedule Job '+Dt, ScheduledTime, Job);
} else {
// capture retry count here.
}
}
catch(Exception e) {
// capture failure in scheduling
}
}
}
ScheduleCallout.cls
public with sharing class ScheduleCallout implements Schedulable {
public Integer iRetryCount = 0;
public ScheduleCallout(Integer iRetryCount) {
this.iRetryCount = iRetryCount;
}
public void execute(SchedulableContext oSchCxt) {
ScheduleCalloutQueueable sCalloutQueueable = new ScheduleCalloutQueueable(iRetryCount);
System.enqueueJob(sCalloutQueueable);
}
public class ScheduleCalloutQueueable implements Queueable, Database.AllowsCallouts {
public Integer iRetryCount = 0;
public ScheduleCalloutQueueable(Integer iRetryCount) {
this.iRetryCount = iRetryCount;
}
public void execute(QueueableContext context) {
HttpResponse response = new HttpResponse();
try {
response = RetryCallout.getResponseFromExternalCallout();
}
catch(System.CalloutException e) {
response = null;
}
if(response != null){
iRetryCount++;// incrementing the retry count in this class
RetryCallout.performActionBasedOnResponse(response,iRetryCount);
}
}
}
}
3 comments
Good article. This is really helpful.
Thanks Dipak 🙂