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
nelrib88nelrib88 

Trigger firing @future callout unexpectedly

I have built a trigger that is called when a contact/lead is updated. This trigger calls a @future method with a callout when a specific field (Email_Issue__c) starts off populated and is then saved to null.

One of our clients has a night batch upload that does an upsert on all its contacts and even though the Email_issue__c is not one of the fields being updated in the batch somehow the callout is going through. When looking through the bulk data load jobs we see the error CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY:itracmedia.InvalidEmailContactTrigger: System.LimitException: itracmedia:Too many future calls: 11:-- for about 100 of 5000 records it processes.

Can someone please explain why this might be happening and what i can do to fix this issue.

 

Trigger

trigger InvalidEmailContactTrigger on Contact (before update)
{
    private String emailissue {get; set;}
    if(Trigger.isBefore)
    {
        emailissue = null;
        for(Contact contact : trigger.old)
        { 
            emailissue = contact.itracmedia__Email_Issue__c;
        }
        
        for(Contact contact : trigger.new)
        {            
            if(contact.itracmedia__Email_Issue__c == null && emailissue != null)
            {  
                if(contact.lastName == 'ApexRunTestIssue'){
                    EmailIssueRemover.test();
                } else {      
                    EmailIssueRemover.removeEmailIssue(contact.id, emailissue, contact.itracmedia__session_id__c, contact.itracmedia__server_url__c);
                }
            } 
        }
    }
}

 

Apex Class:

public class EmailIssueRemover {

  // Static variable that assumes a test is not running
  public static boolean isApexTest = false;
    
  //Future annotation to mark the method as async.
  @Future(callout=true)
  public static void removeEmailIssue(String id, String issue, String sessionid, String serverurl) {

     String server = EncodingUtil.urlEncode(serverurl,'UTF-8');
     String session = EncodingUtil.urlEncode(sessionid,'UTF-8');
   
     Http h = new Http();
     HttpRequest req = buildWebServiceRequest(id, EncodingUtil.urlEncode(issue,'UTF-8'), session, server);
     if(!isApexTest){
       HttpResponse res = invokeWebService(h, req);   
     } 
  }
    
  public static HttpRequest buildWebServiceRequest(String id, String issue, String sessionid, String serverurl){

    //Build HTTP Request object
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://www.**.com/removeEmailIssue?sessionid=' + sessionid + '&serverurl='+ serverurl + '&type='+issue+'&id='+id);
    req.setMethod('GET');
    return req;
  }
  
  public static HttpResponse invokeWebService(Http h, HttpRequest req){
     HttpResponse res = h.send(req);
     return res;
  }
  
  // Wrapper method for "main" that we will call in the Test Class
  public static void test(){
    isApexTest = true;
    removeEmailIssue('test','test','test','test');
  }
}

 


Dirk GronertDirk Gronert

Hi,

 

pls have a look at the gov limits: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm

 

Total number of methods with thefutureannotation allowed per Apex invocation5 10

 

The problem is that you call the future for every single updated contact ..

 

EmailIssueRemover.removeEmailIssue(contact.id, emailissue, contact.itracmedia__session_id__c, contact.itracmedia__server_url__c);

 

To overcome the problem make the future method bulkifield --> means pass a list of contacts or contact wrappers with additional information ...

 

 

 


nelrib88nelrib88

Thanks i have modified my code a bit to make it bulkyfied can you please let me know if this way works better.

 

trigger EmailContactTrigger on Contact (before update)
{
    private String emailissue {get; set;}
    private String session {get; set;}
    private String server {get; set;}
    private Boolean changed = false;
    Map<Id,String> contactsToUpdate = new Map<Id, String>();
    
    if(Trigger.isBefore)
    {
        emailissue = null;
        for(Contact contact : trigger.old)
        { 
            emailissue = contact.Email_Issue__c;
        }
        
        for(Contact contact : trigger.new)
        {            
            if(contact.Email_Issue__c == null && emailissue != null)
            {  
                contactsToUpdate.put(contact.Id, emailissue);
                session = contact.session_id__c;
                server = contact.server_url__c;
                changed = true;
            } 
        }
        /*if(contact.lastName == 'ApexRunTestIssue'){
            EmailRemover.test();
        } else {  */    
        if(changed){
            EmailRemover.removeEmailIssue(contactsToUpdate, session, server);
        }
       // }
    }
}

 

public class EmailRemover {

  // Static variable that assumes a test is not running
  public static boolean isApexTest = false;
    
  //Future annotation to mark the method as async.
  @Future(callout=true)
  public static void removeEmailIssue(Map<Id, String> contacts, String sessionid, String serverurl) {

     String server = EncodingUtil.urlEncode(serverurl,'UTF-8');
     String session = EncodingUtil.urlEncode(sessionid,'UTF-8');
    
     for(Id id : contacts.keySet()) {         
         Http h = new Http();
         HttpRequest req = buildWebServiceRequest(id, EncodingUtil.urlEncode(contacts.get(id),'UTF-8'), session, server);
         if(!isApexTest){
           HttpResponse res = invokeWebService(h, req);   
         } 
     }
  }
    
  public static HttpRequest buildWebServiceRequest(String id, String issue, String sessionid, String serverurl){

    //Build HTTP Request object
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://www.**.com/removeEmailIssue?sessionid=' + sessionid + '&serverurl='+ serverurl + '&type='+issue+'&id='+id);
    req.setMethod('GET');
    return req;
  }
  
  public static HttpResponse invokeWebService(Http h, HttpRequest req){
     HttpResponse res = h.send(req);
     return res;
  }
  
  // Wrapper method for "main" that we will call in the Test Class
  public static void test(){
    isApexTest = true;
    Map<Id, String> test = new Map<Id, String>{'test' => 'test'};
    removeEmailIssue(test,'test','test');
  }
}

 

nelrib88nelrib88

Bumping it. Can someone please let me know if i bulkified my trigger correctly.

Dirk GronertDirk Gronert

looks good for me!