1

In the Connect to Salesforce with Server-Side Controllers module on trailhead, when advising of the requirement to do CRUD/FLS checks, the author cautions:

Also, describe calls are expensive. If your app is calling this method frequently, you should find a way to optimize or cache your access checks per user.

I can't find any documentation on how this ought to be done. What's the best way to cache the results of an access check? Do we need to invalidate the cache at any point, in case the users permissions have changed?

This is the code provided in the trail. How does it need to be modified to enable caching?

Map<String,Schema.SObjectField> fieldDescribeTokens = 
    Schema.SObjectType.Expense__c.fields.getMap();

for(String field : fieldsToCheck) {
    if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) {
        throw new System.NoAccessException();
        return null;
    }
}
1

This questions needs a lots of explanation,

Before coming to your question, let's understand why describe calls are expensive, Although there is no limit as such on the number of calls.
I came across to an interesting SFSE thread, where Adrian Larson provides some performance insight about the different types of describe calls, see that describe calls performance impact:

Schema.getGlobalDescribe()
CPU Time: ~7ms
Heap Space: ~0.3%

Schema.SObjectType.getDescribe()
CPU Time: ~0.002ms
Heap Space: ~0.001%

Schema.SObjectField.getDescribe()
CPU Time: ~0.38ms
Heap Space: ~0.001%

Schema.DescribeSObjectResult.getRecordTypeInfosByName()
CPU Time: ~0.2ms
Heap Space: ~0.0001%

That above insight gives you an idea about each and every describe call impact on CPU performance.
You can analyze your number of calls in a transaction and based on that you can decide do you really need to cache or not,

Like if your single transcation contains 100 calls of Global Describe (CPU Time: ~7ms | Heap space: ~0.3%) then its really worth to cache that;

In the same way if it contains 100 calls of sObject Describe (CPU Time: ~0.002ms | Heap Space: ~0.001%) then it takes only ~0.2 ms of CPU time, so its not really make any big difference to cache it, until unless there are many calls and very frequent. Same thing with the SobjectField Describe also.

You can see full analysis on this thread here: What governor limits impact Apex Describe methods?

Now comes to your question, As you can see to accessibility check calls comes under less impacted describe calls, so its your wisdom to use cache over there or not. But there are few points which I would like to mention here,

  • Accessibility calls are based on Object access or Field level, if you want to cache the fields accessibility then are many fields and objects to cache and it can dynamic also.

  • Accessibility needs to check for every transaction and as you have doubt, accessibility can be change frequently if there is any possibility in your case.

In above case, it may not worth to cache, but if you think it is static with the user session and not changing frequently or you already known about the fields and object for accessibility then you can go ahead with accessibility cache.

Now comes to the cache, there are different types of cache, like Org Cache, Session Cache, read more about that here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_cache_namespace_overview.htm

For accessibility cache as it is based on user and its session, so best choice will be use of session cache here. Session cache is also available at VF side with global variable, I'll not go into further details you can read about that on above link or following trailhead exercise: https://trailhead.salesforce.com/modules/platform_cache/units/platform_cache_use

use below code snippet for session based cache:

Map<String,Schema.SObjectField> fieldDescribeTokens = 
    Schema.SObjectType.Expense__c.fields.getMap();


// cache the accessibility
// create a cache partition first and then start the partition use in code block

// Get partition
Cache.SessionPartition sessionPart = Cache.Session.getPartition('local.AccessibilityCache');

// Add cache value to the partition
//sessionPart.put(<fieldApiname>, <accessibility>);
for(String field : fieldsToCheck) {
    sessionPart.put(fieldDescribeTokens.get(field).getDescribe(), fieldDescribeTokens.get(field).getDescribe().isAccessible());        
}
// Retrieve cache value from the partition
boolean isAccessibleField = (boolean)sessionPart.get(<fieldName>);

I just provide you a sample code to use accessibility with cache, Please follow the above links for cache to get accurate code syntax and detailed information.

Let me know if you need further explanation.

  • So would it be accurate to say that there's no need to pre-emptively cache the result of describe calls, and instead developers should first profile their apps to see if there's a performance problem related to describe calls? – studds Feb 22 '17 at 3:10
  • Yes you are right, It should be measured by your transcation performance and code optimization. The describe calls which we are talking here in your case like sobject and Field describe, those are using less CPU time as comparison to other describe like global describe call. if your single transactions include lots of accessibility check with the same or predefined fields/sobject, then it may be good to cache it, rather then doing accessibility check frequently. I hope you get your clarification – user2809299 Feb 22 '17 at 3:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.