2

Most of what I have read about retry operations is that they are vaguely complicated and indepth. I have written the code below which seems to accomplish this without too much confusion - I'm wondering if there are any pitfalls I am not seeing here.

The class uses a top-level schedulable class, which calls a queueable class to make the callout, and if the callout is unsuccessful, it just schedules the top level class again five minutes later. After testing it appears this works indefinitely.

A simple string token, assigned at the first invocation, is also passed between the classes, and I have tested and found that the token does persist, even when runs are scheduled for a later time.

Thanks for helpful thoughts!

public class SelfServe implements Schedulable {

    public String Token = null;

    public void execute(SchedulableContext ctx) {        

        RetrieveMachineDetails Job = new RetrieveMachineDetails();
            Job.Token = Token;    
        System.enqueueJob(Job);

    }     

    public class RetrieveMachineDetails implements Queueable, Database.AllowsCallouts {

        public String Token = null;

        public void execute(QueueableContext context){                              

            Http http = new Http();
            HttpRequest request = new HttpRequest();        
                    request.setEndpoint('https://app.endpoint.com/api');
                    request.setMethod('POST');
                    request.setHeader('Content-Type', 'application/json;charset=UTF-8');                 
                    request.setBody('{"query":  "$message_=\'METRIC\' && $tier=\'customer\' "}');                                                                                                                                                                       
            HttpResponse response = http.send(request);              

            if (response.getStatusCode() == 200) {
                //do stuff     
            }

            else { //retry

                DateTime Dt = system.now().addMinutes(5);            
                   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;

                SelfServe Job = new SelfServe();
                    Job.Token = Token;
                System.schedule('SelfServe Job'+Dt, ScheduledTime, Job);

            }
        }   
    } 
}
1
  • 1
    First thing that jumps out is that your endpoint may be vulnerable to injection. – Adrian Larson May 11 '20 at 4:22
3

The only downside is that this may not work for callouts that you need to make from a trigger, because of the 100 scheduled job limit (you can't have more than 100 pending jobs scheduled). A more elegant solution would store pending requests in a queue of some sort, and call itself every few minutes or so. The reason why many designs are "vaguely complicated and indepth" is because they need to accommodate a number of use cases, such as being called from a flow, trigger, on a regular basis, etc. Your design is perfectly fine if it's for some low-traffic job like a daily synchronization job or something, but would not scale well to higher frequency use cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.