Find your content:

Search form

You are here

How can I determine how many future calls have been executed in 24 hours?

 
Share

I just ran into a huge gotcha in Salesforce: the 24 hr limit on # of future calls - cf. http://www.sundoginteractive.com/index.php?/sunblog/posts/governor-limit-gotchas-part-1-the-future-call/.

I have the following questions about how to handle this:

  1. How can I determine how many future calls have been made in a 24 hour period? I need to have a trigger check first so that it doesn't cause the overall upsert operation to fail on SF records if I'm over the limit. I saw a post on Developerforce boards saying it was stored in AsyncApexJobs object, but I didn't see how to query it in the API docs.

  2. What's the best way to have a custom script that I do to update a bunch of records in SF ensure that it is not making any future calls? Is there a way I could set some kind of global variable in my script that i could then reference in all the triggers so they wouldn't make future calls if I'm doing a mass update (it's an update of over 2000 records).

Currently I am in a really awkward situation where none of the leads from my external systems are getting added b/c of the future call failing in a trigger set to run whenever a Lead is upserted.

Here is the script that does the sync to Salesforce: https://github.com/techmission/mdl_custom_reports/blob/master/sf_student_sync.php. It is using an upsert function that leverages the PHP Toolkit, and the function is in the same Github repo, in sf_libs.inc

The code of the trigger is here:

trigger CityvisionUpsertLead on Lead (after insert, after update) {
   // score & qualify all leads
   // methods execute in future, so as to be non-blocking for save, and so tests will pass
   // confirm we are not in a future context or a batch context (i.e., when doing a bulk update)
   if(!System.isFuture() && !System.isBatch()) { 
     Set leadIds = new Set(); // leads to score and qualify - currently filtered in the methods, not here
     // iterate over all the leads
     for (Lead l : Trigger.new) {
        // add all to the pool for scoring and qualification
        leadIds.add(l.Id);
     }
     // invoke the methods for scoring and qualifying leads
     // if this is not being called from a future method context 
     if(!leadIds.isEmpty()) {
       CityvisionUtils.scoreLeads(leadIds);
       CityvisionUtils.qualifyLeads(leadIds);
    }
  }
}

Attribution to: Evan Donovan

Possible Suggestion/Solution #1

* [EDIT: Just read through the Developer Boards post, and then confirmed this is only within the context of the future call stack, and not the 24 hour limit, I thought for sure there was a method that exposed the 24 hour limit...let me dig around a bit more.]

For #1, take a look at the Limits methods, specifically Limits.getFutureCalls() and Limits.getLimitFutureCalls(). Depending on how your code is structured, you could branch off and only perform some logic if you've got X number of Future Calls available.*

Salesforce Limit Methods

For #2, depending on how your org is structured, one thing we do is have all of our bulk loads done by a specific API Only Profile (perhaps a SysAdmin in a smaller org). We typically have logic in place in Workflow Rules/Triggers/other that won't cause logic to fire if this Profile is performing the bulk update.

One other thing you could look at would be having Custom Setting(s) to store a variable on whether or not to execute the logic, that your code could check. This could easily be turned on and off prior to doing any bulk loads, but depending on how it's setup, could also remain off if a user is performing an update via the UI during this same load window. That's why I would recommend scoping the logic to a user/profile.

Salesforce Custom Settings


Attribution to: Mikey

Possible Suggestion/Solution #2

(1) To determine the number of Future calls run in the past 24 hours, you can use this utility method:

public static Integer GetNumFutureCallsInLast24Hours() {
    return [select count() from AsyncApexJob 
            where CreatedDate >= :Datetime.now().addHours(-24) 
            and JobType = 'Future'];

(2) To dynamically run methods in a future context ONLY if you have future calls available, you could leverage a "dispatcher" method framework that would run your code in a future context only if you have not surpassed the 24-hour-calls Limit and Call Stack Limit yet:

// Can we run future calls right now?
public static boolean CanUseFutureContext() {
    boolean callStackLimitExceeded = Limits.getFutureCalls() >= Limits.getLimitFutureCalls());

    if (!callStackLimitExceeded) {
        // Check 24-hour rolling window limit
        // of 200 * # of Salesforce, Salesforce Platform, or Force.com One App Licenses
        // *NOTE 1*: These queries may be cacheable depending on your situation
        // *NOTE 2*: If you have not used up all of your allocated licenses,
        // you will have more available licenses than this, so you may need to adjust.
        // However, you can't use SOQL to determine 
        //how many AVAILABLE licenses you have, 
        // only how many have actually been assigned to users
        return GetNumFutureCallsInLast24Hours() < getMaxFutureCallsAllowed();
    } else return false;
}

public static Integer getMaxFutureCallsAllowed() {
    Integer usersCount = [
        SELECT
            COUNT()
        FROM
            User 
        WHERE
            Profile.UserLicense.LicenseDefinitionKey IN ('SFDC','AUL','PID_FDC_FREE')];
    return Math.max(250000, usersCount*200);
}

// Main entry point to your method: call this from a trigger, other class, etc.
public static void RunMyLogic(params) {
    if (CanUseFutureContext()) futureRunMyLogic(params);
    else RunMyLogicMain(params);
}

private static void RunMyLogicMain(params) {
   /* Your logic here */
}

@future
private static void futureRunMyLogic(params) {
   RunMyLogicMain(params);
}

Attribution to: zachelrath
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/3380

My Block Status

My Block Content