Thursday, April 30, 2015

A Web Service CallOut Per Minute In Between Business Hours

There was a very specific requirement from customer, as per the requirement he wanted to call a external websrvice in every minute during the business hours. I tried several ways to do it but that was really not simple. Even I was not sure it can hit any governor limit. I did google a lot for this but there was no help in case of per minute. Finally started to get if there is any solution in salesforce for this, without having confidence is this really possible in salesforce. But finally I got the solution & the best thing is it works without hitting any kind of governor limits. Here is the solution which can help if you stuck this kind of requirement.

#1-Create a new object called “Scheduled_Job__c”. This object will have below fields –
Request_DateTime__c – Type DateTime
Response__c – Type Long Text Area(32768)

This object will be used in two ways latter-
#A-track the request time &
#B-What is the response from the external web service.
#2-I created a batch class which allows callouts.
global class ScheduleLeads implements Schedulable,Database.AllowsCallouts {
 global void execute(SchedulableContext ctx) { 
      init(); 
 }
}

#3-Created a method in this class called ScheduleJob which will basically can be called from execute anonymous to schedule this job.
public static void ScheduleJob(){
 boolean isNeedToSchedule = true;
 String strSchedule = '';
/*here notice that we are adding a minute in current time, means it will be scheduled for next minute, you can change it even if you want to call every n minutes*/
 DateTime dt = Datetime.now().addMinutes(1);
/*Let’s say business hours is from 10 AM to 8 PM*/
 if(dt.hour() >=19 && dt.minute() >= 59){ 
         isNeedToSchedule = false;
 }else{
     strSchedule = '0 ' + dt.minute() + ' ' + dt.hour() + ' ' + dt.day() + ' ' + dt.month() + ' ?' + ' ' + dt.year(); 
     isNeedToSchedule = true;
 }
 if(isNeedToSchedule){
   String cronid = System.schedule('CalloutService_' + Datetime.now().getTime(), strSchedule, new ScheduleVWLeads());
  
   List listOfScheduledJob = [Select Id,Response__c from Scheduled_Job__c Order by CreatedDate DESC LIMIT 1];
   if(listOfScheduledJob != NULL && !listOfScheduledJob.isEmpty()){
    /*try{ 
     delete listOfScheduledJob;
    }catch(Exception ex){
     system.debug('exqqq::--->>>>' + ex);
    }*/
   }
   Scheduled_Job__c objScheduledJob = new Scheduled_Job__c();
   objScheduledJob.Name = cronid;
   objScheduledJob.Request_DateTime__c = datetime.now();
   insert objScheduledJob;
 }      
}

#4-Create another method called init
@future(callout=true)
  public static void init(){
     HttpRequest req = new HttpRequest();
  Http http = new Http(); 
  req.setMethod('GET');
  String requrl = 'YOUR_WEBSERVICE_URL'+ '?type=' + XYZ;
  req.setEndPoint(requrl);
  HTTPResponse res;
  if(!Test.isRunningTest()){
   Blob headerValue = Blob.valueOf('YOUR_WEBSERVICE_USERID' +':' +'YOUR_WEBSERVICE_PASSWORD');
   String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
   req.setHeader('Authorization', authorizationHeader);
   req.setTimeout(120000);
   res = http.send(req);
  }else{
   res = new HttpResponse();
   res.setHeader('Content-Type', 'application/json');
   res.setBody('DUMMY_RESPONSE_IN_CASE_OF_TEST_EXECUTES');
   res.setStatusCode(200);
   res.setStatus('Ok');
  } 
  String resBody;
  if(res != NULL){
   resBody = res.getBody();
   JSONParser parser = JSON.createParser(resBody);
   while (parser.nextToken() != null) {
    /*PROCESS YOUR RESPONSE HEREE */
   }
   ScheduleJob();
  }
  
 }

Here one important point is we are calling the schedulejob method in init again so this is scheduled for next minute.
Now if you start this job at some particular time daily let’s say when business start 10 AM in morning, go to schedule job & schedule a job by using this class. That’s it. The job will start on regular time daily & in code we are having a condition when it will stop. So in this way the job will execute from 10 AM to 8 PM daily.
You can either keep ScheduleJob records for tracking or can delete if not needed. In the above code there is a piece of code which is commented & that is deleting the ScheduleJob object records.

Happy ending! :)

2 comments: