Retrying Failed Callouts in Salesforce Apex

INTEGRATION

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);
            }
        }
    }
}

How to do auto refresh

3 comments

Leave a Reply