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
ChrisMagellanChrisMagellan 

Future Call limit when adding field to SOQL query (Eclipse)

Close to my wits' end on this one. I have a trigger that calls a Future class. When I run through my tests I get up to 7 future calls. I then add another conditional to my SOQL query in the trigger, and the whole thing breaks, highlighting a random line in my class and saying  I'm suddenly using 11 future calls.

 

Trigger:

 

if (trigger.isInsert) {
			for (Contact workingContact : trigger.new) {
				// Check for existing Contacts
				List<Contact> orgContacts = [Select Id, Name, Email from Contact where ( Name = :workingContact.Name and Email = :workingContact.Email and Email != null and Id != :workingContact.Id)];
				if (orgContacts.size() != 0) {
					NotificationEmail.AvianisError(orgContacts[0].Id, orgContacts[0].Name, 'Duplicate Contact found on Contact insert');
					continue;
				}
				// Insert Contact into Avianis
				if (workingContact.AvianisID__c == null && workingContact.AccountId != null) {
					Avianis.aviContactFuture('insert', workingContact.Id);
				}
			}
		}

 Future method called:

// Contact method
    @future (callout=true)
    public static void aviContactFuture(String operation, String conId) {
    	
    	// Get contact info
        List<Contact> sfContacts = new List<Contact>();
        
        sfContacts = [SELECT Contact.Id, ...
                      FROM Contact WHERE Contact.Id = :conID ALL ROWS];
                      
        if (sfContacts.size() == 0) {
        	return;
        }   

    	aviContact(operation, sfContacts[0]);
    }

 The aviContact method builds a SOAP envelope and sends it, then updates the Contact with a return value. Eclipse is highlighting a random line in the aviContact method (where it's setting a variable with "") as System.LimitException: Too many future calls: 11

 

In case it matters, here's the NotificationEmail.AvianisError method:

public static void AvianisError(Id EId, String EName, String ErrType) {
		// Send notification email if Avianis trigger encounters an error.
		
		Messaging.SingleEmailMessage mail = new Messaging.Singleemailmessage();
		mail.setSaveAsActivity(false);
		String mailSubject = 'Avianis Trigger Error: ' + EName;
		String mailBody = 'Error for: ' + EName + ' https://na14.salesforce.com/' + EId + '\n\n' + 'Error Code: ' + ErrType;
		mail.setToAddresses(new String[] {'**@**.com'});
		mail.setSubject(mailSubject);
		mail.setPlainTextBody(mailBody);
		
		Messaging.sendEMail(new Messaging.SingleEmailMessage[] {mail});
		
	}

 

I'm going nuts here, any ideas?

empucempuc

Hi Chris,

 

You haven't mentioned whether the trigger is before or after insert. If both then it might happened that it will be processed at least two times. Whats more, if You are having some workflows which are updating the contact record then it may happened that it will be runned not once, not twice.... but even more :)

 

Anyway, there is a common solution for such cases. You should store along the whole transaction ids which You have processed - send for future method. 

 

By the way I do not know your Avianis system and the API which it shares, but it will be more effficient if it could allow to send many contacts in one request and therefore process many contacts in single aviContactFuture invocation.

 

But lets go to the business. To preserve from processing the same record more than once you need to:

 

1. if You didn't do it yet, make sure that the trigger which You pasted is working on after insert (otherwise it will not make any sense, cause the contact id will be null at this stage). 

 

2. declare in some class static map or set - it depends on Your need. Both are ok. In my example below I will use set. And for Your own comfort build 2 pasted methods:

 

private static Set<String> sKey;

 

public static boolean checkExecution(string s){
if(sKey == null || !sKey.contains(s)){
return false;
} else {
return true;
}
}

 

public static void markExecution(string s){
if(sKey == null){
sKey = new Set<String>();
}
sKey.add(s);
}

 

 

 

Then on Your trigger add code as below. It should work and block multpile future calls for the same records. 

 

 

if (workingContact.AvianisID__c == null && 
workingContact.AccountId != null &&
!checkExecution(workingContact.Id)) { Avianis.aviContactFuture('insert', workingContact.Id);
markExecution(workingContact.Id);
} }
ChrisMagellanChrisMagellan

Hmm, thanks for the ideas! I implemented the change you suggested and it's still an issue but I'm working on a few different ways to try to fix it. I think the problem is stemming from my future calls updating a record, and since the future call is outside the scope of the actual operation it's totally separate from the original insert/update/etc. If I do manage to **bleep** this one I'll try to come back here and update for future Googlers.

 

In regards to the specifics in your post:

 

  • It's an after-insert trigger (so I have an Id to pass!)
  • I'll have to look into my workflows a little more, that may have something to do with it now that you mention it...
  • Unfortunately there's no bulk method in Avianis so I'm kind of stuck with what I have.