Troubleshooting: Page Performance Issues (Error: “Time limit exceeded.”)
PROBLEM: A Skuid page takes a long time to load (between 60 and 120 seconds) and eventually fails to load with this error: “Time limit exceeded. Your request exceeded the time limit for processing.”
RESOLUTION: Optimize model queries by optimizing model conditions and deferring querying of data-heavy models until after page load.
At runtime, a specific page was taking a very long time to load and then erroring out with this error message: “Time limit exceeded. Your request exceeded the time limit for processing.”
The page worked fine in a partial Sandbox, but during UAT testing it was added to a full Sandbox and that’s when the page started timing out.
1. First, we looked for differences between the two sandboxes that might be causing the error. The full Sandbox had much more data than the partial sandbox. Some objects that were used on the page had thousands of records in the database. Even if all of the records aren’t brought into a Skuid page, the more records in an object the longer it takes to query that object because there’s more data to sort through. This is why the timeout error started occurring in the full Sandbox.
2. I put smaller Max # of records limits on all models (e.g. 50 rather than 1000). Issues with pages timing out, hitting Apex heap size errors, or taking a long time to load can almost always be traced to models that are bringing in large amounts of data. However, even with the new limits, the page still took a surprisingly long time to load (over a minute).
3. I dug deeper into the models and noticed that many of them contained conditions on related objects fields, some of which were unnecessarily redundant. To create a condition on a related object’s Id field, you can use the lookup relationship field, rather than using the RelatedObject.Id field (for custom objects RelatedObject__r.Id). You can configure conditions directly on the lookup field to a related object since this field contains the record Id. See the screenshot below for the preferred format (1) vs the redundant format.
Furthermore, some models had conditions on fields which weren’t included on the model. It’s best practice to always include condition fields in the model, especially when you’re using fields from a related object. When you encounter unexpected behavior, it’s always a good idea to ensure that the field is included in the model.
4. Next, I checked how each condition would behave if it couldn’t find a value. Abort this model’s query is typically the best way to go, especially with objects that contain large amounts of data. If you choose either of the other options, then the condition will not be applied and you could end up with a model that’s trying to query every record in the object.
5. At this point, the page loaded without the timeout error, but still took over 30 seconds to load. Since I had run out of ideas, I asked a teammate for help. They recommended I comment sections out of the page XML and see how it affected load time. We started commenting out big chunks (e.g. all JS and CSS resources, all models). By loading the page with different elements removed and seeing how long it took to load, we were able to narrow it down to which specific element on the page was causing the slowness.
When we commented out the custom code resources, the page still took a long time to load, but when we commented out the models (as shown below - the lines in green have been commented out), it loaded right away.
By commenting out some of the models and leaving others on the page, we were able to narrow it down further to one specific model that was having issues, and to one specific condition on that model.
The offending model was on one of the objects with the most records in the database, and it had a condition where the value was “in” one of multiple specified values. According to the Skuid documentation on Improving Query Performance you should avoid conditions like this with the “contains” (“in”) operator since in this case Salesforce can’t use the index and it makes the query slower.
Non-optimal condition configuration
We optimized the trouble model in 3 ways and were able to get the page to load in under 10 seconds.
- We deferred this model’s query to take place after page load. Since we knew this model took the longest to load (12 seconds even with the optimized conditions), we chose not to query it at page load but rather via an action sequence that ran at page load. This way it wasn’t loaded with the rest of the models and the initial page load was much faster.
- We included the condition field in the model to make sure the model could quickly find the data it needed.
- Rather than having one multiple specified values condition, we broke the condition into multiple = (single specified value) conditions and used grouping logic (1 OR 2 OR 3…) to ensure they were all applied. This way the model could perform indexed searches and return the data faster.
Optimal condition configuration
- Optimizing model queries is one of the most effective ways to improve page performance.
- Wherever possible, defer model query until after initial page load. For example, if a model is only used in a certain tab, have that model queried only when a user clicks on the tab for the first time.
- Commenting out sections of a Skuid page’s XML is a great way to quickly figure out which part of the page is causing an issue.
- If you’re experiencing unexpected behavior related to conditions or model data, always make sure the fields being used in model conditions and elsewhere on the page are included in the model.
- Not all model conditions are created equal. See Skuid’s Page Performance Guide for tips on which conditions will make your model queries faster, including:
- Wherever possible, put conditions on Indexed fields.
- Where possible avoid using wildcard operators in your model conditions. Operators to avoid include:
- does not contain
- does not start with
- does not end with
- Additional performance tips:
- For Salesforce data sources, enable the metadata caching feature so that Skuid can save the metadata for future use instead of downloading it on each page load.
- Use pagination on tables. All of the records allowed by the model will still be loaded, but the table will render faster because it only needs to display the first page of records rather than everything.
- Where it makes sense, use read mode or read with inline-edit mode for forms and tables. Components in edit mode can take longer to render since Skuid must verify that the user has permission to edit each field.
- Best Practices for Model Configuration
- Page Performance Guide
- Skuid and Salesforce Lightning Performance Tips
- Troubleshooting: Model Data Doesn’t Load Due To Heap Size Limits