function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Varun ChopraVarun Chopra 

Callout from scheduled Apex not supported.

Hi,

I am stuck with an problem with my schedular. I am tyring to read files from S3 bucket using amazon S3 api calls. When I am trying to call this method using schedular it gives me error :
  System.CalloutException: Callout from scheduled Apex not supported.

Here is my schedula class :

global class ScheduleXMLDownload implements Schedulable{
  
   global void execute(SchedulableContext SC) {
        downloadFiles();
    }
  
      public static void downloadFiles(){
       try{
          ReadXml.requestIvans();
         }
   catch (DmlException ex)  { 
          system.debug('error insert DefaultProducer '); 
  
         
        }
    }
   
}


Here is my method I am calling in shedular.


-------------------------------------------------------------------------------

@future(callout=true)
     public static void requestIvans(){
        Http h = new Http();
        AmazonAccess amz = new AmazonAccess();
        
        CanaryAMS__Defaults__c property = CanaryAMS__Defaults__c.getValues('MailBoxId');
        String mailBoxId = property.CanaryAMS__value__c;
       
        Map< String,String> xmlFileList = new map<String,String>();
        
        String aWSAccessKeyId = amz.key;
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        SaveObjects.ListEntry[] bucketList  = amz.listBucket('canary.ams.xml',mailBoxId);
       
        List<String> xmlResponseList = new List<String>();
        List<String> bucketKeys = new List<String>();
        String filesToDelete = ''; 
        boolean runSchedular = true;
        Integer countRun = 0 ;
        do {
  
       if(bucketList!=null && !bucketList.isEmpty()){
        runSchedular = false;
        Integer maxFiles  = bucketList.size();
        if(maxFiles>3){
        maxFiles = 3;
        }
           for(integer i=1; i<maxFiles; i++){
               Datetime now = DateTime.now();
               Datetime expireson = now.AddSeconds(30+i);
               Long Lexpires = expireson.getTime()/1000;
               Lexpires = Lexpires + i;
               bucketToList = 'canary.ams.xml';
               String stringtosign = 'GET\n\n\n'+Lexpires+'\n/'+bucketToList+'/'+bucketList[i].Key;
          
               String signed = amz.make_sig(stringtosign);
              
               String url = 'http://'+bucketToList+'.s3.amazonaws.com/'+bucketList[i].Key+'?AWSAccessKeyId='+aWSAccessKeyId+'&Expires='+Lexpires+'&Signature='+signed;
        //     system.debug('shalini ======= > '+url);
          //     String url =  'https://s3-us-west-2.amazonaws.com/canary.ams.xml/'+bucketList[i].Key;
               bucketKeys.add(bucketList[i].Key);
               system.debug(url);
               //String url = EncodingUtil.URLENCODE(url1,'UTF-8');
               req.setEndPoint(url);
               req.setMethod('GET');
               res = h.send(req);
             
               String response = res.getBody();
               ReadXml readXml = new ReadXml();
               if(readXml.checkXMlFormat(response)){
                //filesToDelete = filesToDelete+bucketList[i].Key+',';
                xmlResponseList.add(response);
                xmlFileList.put(bucketList[i].Key,response);
               }
            
          }
          ReadXml readXml = new ReadXml();
          readXml.processXMl(xmlFileList);
          
         /* String url =  'http://ec2-54-186-194-3.us-west-2.compute.amazonaws.com/Script/UploadToS3Bucket/moveToArchiveFolder.php?key=';
          url = url+filesToDelete;
          req.setEndPoint(url);
          req.setMethod('GET');
          res = h.send(req);
         
         
          String response = res.getBody();
          for(String resp : xmlResponseList){
              if(checkXMlFormat(resp)){
                parse(resp);
              }
          } */
         
         
      }else{
      system.debug(' ==================== schedular Error ====================');
           if(countRun < 3 )  
           {   
    countRun ++ ;
    runSchedular = true;
    system.debug('S3 bucket is not accessible '+Apexpages.Severity.ERROR ) ;
           }
           else
           {
     runSchedular = false;
           }
      }
      } while (runSchedular);
       
       
    }


   
   I have searched on google and most of solutions are to add @future annotaion over my method. I have tried this, but it is still not working.
   Please let me know whats wrong with my code?

Thanks
Ramesh KallooriRamesh Kalloori
we can't call htpp callouts from Scheduler class.

instead of .

create the batch apex class from that call the http callout class.

from schedular class call the batch apex class.

below is the example.
public class HttpCallout
{

//http request logic..

}
global class schedule implements Schedulable
{
//call batch class with size as 1
batch ob=new batch();
DataBase.executeBatch(ob,1);
}
global class batch implements Database.Batchable<sObject>,Database.AllowsCallouts{

//in excecute method call HttpCallout class
}


thanks,
Ramesh
ishchopraishchopra
Hello there,

I am facing similar problem, i am new to apex so doesnt understand how to split the classes. if i remove for loop and run the job on one reports it works fine. BTW this code is for sending reports in csv format via emails but i am getting below error:

please help

First error: You have uncommitted work pending. Please commit or rollback before calling out
 
global class EmailReports implements Schedulable 

{
        global void execute(SchedulableContext sc)
        {
               CallSchedule.EmailReports();
              
       }

   }
public class CallSchedule {
            
        @future(callout=true)
        public static void EmailReports()
        {

        String ReportID;
        String EvntName;
        
        List<string> reportids = new List<string>{'00OM0000000GzioMAC'};  // reports to send
        List<string> EventName = new List<string>{'EAGC+2016','LNGCAN+2017','CEE+2017','GASASIA+2016','Gastech+2017','GIS+2017'};  // Event Value to be passed runtime 
          
       
       
        if (EventName.size() >0)
        {
        
        for (integer i=0 ; i < 5 ; i++)
        {
        
        ReportID = reportids[0];
        EvntName = EventName[i]; 
          
                           
        ApexPages.PageReference report = new ApexPages.PageReference('/'+ ReportID + '?pv0=' + EvntName +'&csv=1');
              
        Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment();
        attachment.setFileName('report.csv');
        attachment.setBody(Blob.valueof(report.getContent().toString()));
        //attachment.setBody(Blob.valueof(report1.getContent().toString()));
        attachment.setContentType('text/csv');
        Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
        message.setFileAttachments(new Messaging.EmailFileAttachment[] { attachment } );
        message.setSubject('Report For' + EventName );
        message.setPlainTextBody('The report is attached.');
        message.setToAddresses( new String[] { 'skh@gmail.com' } );
        Messaging.sendEmail( new Messaging.SingleEmailMessage[] { message } );
       
        }
        }   
     }