This content has been marked as final. Show 48 replies
Vikas - Building on what Arie said, this clarification might help: When a page/region is rendered dynamically, it is eligible for caching right after rendering only if the basic criteria are met (see above), except for criteria 3 and 4, obviously. [I just edited that list to add #7, "cache-when condition is true".] So if the reason that your region rendered dynamically is that the cache-when condition was false, then that condition prevents the caching of the page as well. To recap the basic criteria:
1. no REQUEST value present in URL;
2. page is not a no-duplicate-page-submission-allowed page;
3. cached page/region exists in cache, for named user when applicable;
4. cached page/region is not stale;
5. certain session-state-protection conditions are met that we haven't installed yet;
6. the page is large enough to warrant caching;
7. cache-when condition is true;
In addition, pages run in debug mode do not cache.
Arie: Somehow, I don't think that we need to use the APEX_UTIL APIs to handle such basic caching behaviour. Those APIs seem to be designed to allow us to override the cache "age" which is a development-time declarative attribute.
as reading and writing condition is the same
Exactly. This is what I cannot grasp. I tried to spell this out a few posts up with Scott but still don't get it. How can the read-from-cache and write-to-cache use the same condition? If the condition evaluates to true, the region is read from cache. So it doesn't make sense to write it back to cache, it would be the same content. If the condition evaluates to false, the region is rendered dynamically. So it should be written back to the cache. But because the condition is false, it will NOT be! Seems like Catch-22!
So I haven't yet understood based on my little experiment is exactly when APEX updates the cached region. I just assumed that whenever the region is rendered dynamically, it would be written to the cache i..e the cache would be updated. But that doesn't seem to be happening.
Let's just wait for Scott to clarify the behaviour.
Looks like our posts crossed.
OK I see what you are saying. I added a After Submit process to my example conditional upon the New Search button being clicked that does
APEX_UTIL.PURGE_REGIONS_BY_PAGE(:APP_ID,:APP_PAGE_ID)and now the dynamically rendered region is getting written back to the cache, like I expect.
Given my example and what it is trying to achieve, do you think I still need the P61_USE_CACHE item and all those elaborate onload/after footer computations at all? If not, what should the cache-when condition be? Can it "Always"? That would let your conditions (3) and (4) control all the read/write cache behaviour and not the cache-when condition? Somehow that doesn't feel right.
pages run in debug mode do not cache
You mean "do not read from cache" or "do not write back to the cache" or "both"?
certain session-state-protection conditions are met that we haven't installed yet
Not sure what you mean by your point (5) above. Can you please clarify?
Thanks for your guidance.
Just thinking out loud. If your search field is in your report region (like in your APEX dictionary example), and cache condition will be set to always, the first result set will be cached, prior to any search. Then, you'll enter a string search and submit the page, but the APEX engine will render it out of the cache, regardless of your new search string.
Can it "Always"?
Another problem I can see with the "Always" condition is that you basically force the user to click a "New Search" button. If you are working with "submits page when Enter pressed", again like in your APEX dictionary example, the system will not catch the new search string, and will continue to display the cache result set.
you'll enter a string search and submit the page, but the APEX engine will render it out of the cache
Arie: Not necessarily. When you enter a search string and submit the page, an after-submit component would call that APEX_UTIL API to purge the cached region so that the show engine would not find the region in the cache and proceed to render it dynamically.
No, same principle applies here. i.e. you would trap all events that would result in the report contents changing and purge the cache during after submit processing.
The advantage of doing all this, of course, is that just navigating to that page will serve up the region from the cache. If you take any action that would need the cache to be refreshed, you need to manually purge the cache prior to that otherwise the user will be left scratching his/her head as to why the report is showing incorrect results!
As someone said earlier, all this caching stuff is "advanced use" of APEX, to be undertaken only if the performance benefits outweigh the added complexity.
But, having said all this, I find myself wondering what the use of the "cache-when" condition is. I guess it provides an additional degree of "fine-tuning" over when to serve the page from cache vs. dynamically, as part of the 7 steps Scott showed us.
Scott: Please correct us if we are wrong.
This is a useful discussion. I am learning as much as you are about this new feature. The feedback will help us document and explain the feature more effectively and possibly allow us to improve the usability too.
I agree with the assertion that you need to know when to purge a cache page/region and do it when your cache-when conditions don't cover it.
To address the pending questions:
If not, what should the cache-when condition be? Can it "Always"?
On a search page where results can also appear you might want a simple cache-when condition like :P1_SEARCH is null where the objective is to not cache the page when search criteria are entered. So thinking about the cache-when condition as the inverse of when not to cache might be easier to visualize. Put another way, ask what condition(s) must exist when this page is rendered to make the results look static = reusable = cacheable? That is the cache-when condition.
pages run in debug mode do not cache...You mean "do not read from cache" or "do not write back to the cache" or "both"?
Both, but the cause of not being able to read debug-mode pages from cache is that they are never cached.
certain session-state-protection conditions are met that we haven't installed yet
We have not yet (3.0) done all the necessary things to accommodate Session State Protection checksums. Those would appear in f?p URLs and, like session IDs, would not be reusable in most cases across sessions. So we'll be looking into that.
Thanks for your interest in this feature and your insightful comments.
.......Seems like Catch-22!
.......I just can't pass up the opportunity - we know you meant Cache-22.
>>Not necessarily. When you enter a search string and submit the page, an after-submit component would call that APEX_UTIL API to purge the cached region so that the show engine would not find the region in the cache and proceed to render it dynamically.
I thought the all point of using the "Always" condition is leaving the "when to cache" decision to the basic criteria Scott noted, and even leave rule #7 out of the game. What you are saying now is a bit different – using an after-submit component to clear out the cache. In a way you are shifting the point of decision from the pre-rendering "when to cache" point, to an after-submit point. In any case, you need some developer intervention.
>>But, having said all this, I find myself wondering what the use of the "cache-when" condition is. I guess it provides an additional degree of "fine-tuning" over when to serve the page from cache vs. dynamically, as part of the 7 steps Scott showed us.
In a way, I see it in reverse. The "cache-when" condition gives you the crude/general option to define when to cache – like "not null" search string, and then you should fine tune it with decisions on when to deviate from this rule, and clear the cache.
I have similar "search regions" as in Bill's application. I found out that when I'm using a "not null" cache condition for the search string, and an after submit clear-cache process, I'm getting the best results. When the user brunch from the search region into a details page (using a report link) he's redirected to the new page without the after-submit processes being fired, so the cache stay intact, and it being used when the user return to the search page. In all other cases, when a "new search" button is pressed, or the search string is changed, the page is submitted, the cache is cleared, and the search region is dynamically rendered, as expected. Moreover, as the initial "when to cache" condition is still valid – the search string is not null – the new search region is also being cached for further use.
Well, this has turned into a very lively, interesting, and enlightening conversation.
I'm learning more as the questions and answers fly by, and still confused by a few points, but I'm getting the functionality I want and expected by having the process that changes my search condition purge the cache so it is re-populated and re-cached.
In the end, that's all I really care about, though learning all of the why's and the other "ins and outs" will probably benefit me in the future.
A small correction though to a message above. Vikas mentions using the
APEX_UTIL.PURGE_REGIONS_BY_PAGE(application_id, page_id), but as Scott corrected me in an earlier post, it is better to use
APEX_UTIL.CACHE_PURGE_BY_PAGE(application_id, page_id, user_id)so that you can also specify the user of that page to purge the cache for.
I'm sure Arie and Vikas both realize the correct procedure to use, I'm only mentioning this here for others that may not be as familar (like a lot of the beginners), so they don't develop or deploy an app that would purge the cache for all users instead of just the one user that changed their search condition (or whatever condition).
I'm sure this will turn into a highly informative "How-To" eventually, hopefully with several different examples for different cases.
On a related but slightly different note, it would also be beneficial if the "Help" (both online and documentation) had a few more details on the various cache related procedures, like an example or two for the beginners, and an explanation of the purpose and outcome of it's execution would be. Like purging that page/region cache for everybody or just for a particular user, maybe with a "See Also" link (or text).
It would also be nice if the procedure/functions were grouped together both aplhabetically and also by functionality, since a quick scan of the alpabetical listing could allow one to easily miss the correct procedure, as the two procedures above demonstrate.
>>A small correction though to a message above. Vikas mentions using the
, but as Scott corrected me in an earlier post, it is better to use
APEX_UTIL.CACHE_PURGE_BY_PAGE(application_id, page_id, user_id)
so that you can also specify the user of that page to purge the cache for.
I believe "better" is not the right word to use in here. The use of the APEX_UTIL API functions should be correlated with the type of caching you are using. If you chose to use "Cached By User" – as you mentioned in your post - the proper function to use is indeed APEX_UTIL.CACHE_PURGE_BY_PAGE(application_id, page_id, user_id), as Scott pointed out. However, you can also choose the "Cached" option, which operate on the application level, and in this case, the proper function will be APEX_UTIL.PURGE_REGIONS_BY_PAGE(application_id, page_id , as Vikas used.
Point noted, though I can't envision that many possible uses where you'd want to clear the cache for all the users of your system.
When "Cache By User = No", e.g., say one of your pages is based on a datamart feed that is refreshed every Wednesday at midnight. An application process could check the age of your cached page after login and purge it if necessary to ensure synchronization. Refreshing for all users is the only thing that makes sense.
Thanks for the example, but I'm having problems following it.
At midnight the datamart feed is refreshed. As the morning wears on, people begin to log in to your app. After the first person logs on, a process checks the age of the cache and if the age condition to refresh is met, then the cache would be purged for all users. The next person logging on will re-execute the condition check, etc., with each user executing the same check.
If it's a heavily used system, wouldn't it make more sense to just have a process (or a job) that executes after the datamart refresh rather than each user executing the same piece of code over and over each day with the same results, "Use Cache"?
There are initially two "givens" in my example:
1. The page can be cached because it shows relatively expensive-to-retrieve data that has more than a momentary "shelf life".
2. The cache does not need to be "by user", it's the same data for everyone.
Even if my example wasn't the best, a common use case for page caching meets these two criteria.
So then the only question is how to purge this cached page. Using a job that runs "at the right time" each week is fine, if you can figure out how to do it. But that's not the situation I'm trying to illustrate, which is where you want your application to purge the cache based on realtime criteria available to it . Now that's a third "given", that we want the application to manage the cache.
So then the question is how efficient is it to do what I suggested. Extremely. Checking the age of the cached page requires one function call:
apex_util.cache_get_date_of_page_cache(p_application => v('APP_ID'), p_page => '100')
...which is very inexpensive and as I said, could be run just once per user session, after login.
I found out that when I'm using a "not null" cache condition for the search string, and an after submit clear-cache process, I'm getting the best results
Yes, I agree. That seems to work best.
Scott: Yes, I did mean Cache-22 :-)
Couple of other points to note
Perhaps the clear-cache (in hindsight, ambiguously named!) argument to the f?p= URL can be enhanced to accept some more keywords to purge this new type of cache
2. Setting the cache to be not "By User" i.e. system wide cache is a little risky for, say, dynamic report regions where the report query is customized for each user based on his authorization level, search filters, etc. If you inadvertently choose the "Cached" instead of "Cached By User" option from the Caching dropdown list on the Region definition page, and a super-privileged user happens to log in first thing and is shown all the top secret data and APEX caches that data. A regular user logs in next and boom the top-secret data is served out of the cache! Just something to be aware of, is all I am saying.