Nov
20

Thus far I've written about caching an entire Web page, caching part of a Web page, and viewing page cache metadata. Today I want to focus on flushing pages and page fragments from the template cache. This task is easily accomplished using the <cfcache> tag with the action attribute set to "flush."

There are two basic ways to flush pages from template cache. You can flush the entire template cache using the following code. This should be done in moderation as flushing dozens or hundreds of pages or page fragments all at once might be an expensive operation.

<cfcache action="flush">

Secondly, you can flush a specific page from cache by adding the expireurl attribute and handing ColdFusion a URL reference. This can be in the form of a specific ColdFusion template or you can use wildcards to flush pages that match a specific pattern. Yesterday I alluded to the importance of ColdFusion using the URL as part of the cache ID for a cached page. Why is this significant? ColdFusion has the ability to cache every page based on the URL, though this isn't the default behavior of the <cfcache> tag. In order for this to occur you must add useQueryString="true" to the tag. For instance, a page with the URL http://www.mydomain.com/index.cfm?productID=20 would be cached separately from a page with URL http://www.mydomain.com/index.cfm?productID=25 even though the same ColdFusion template is being accessed. If you leave off the useQueryString attribute ColdFusion will cache the page once regardless of URL parameters.

Here's an example that shows caching based on URL.

<!--- If the URL parameter 'flush' is defined, flush the cache for just this page. --->
<cfif isDefined("URL.flush")>
    <cfcache action="flush" expireurl="*wt-4.cfm*">
</cfif>

<!--- Cache just a part of this page. --->
<cfcache action="cache" timespan="#CreateTimeSpan(0,0,0,45)#" useQueryString="true">
    <cfoutput>This date/time IS cached: #Now()#<br /></cfoutput>
</cfcache>

<cfoutput>This date/time is not cached: #Now()#</cfoutput>

<!--- Get the little bit of template cache metadata you can. --->
<cfdump var="#GetAllTemplateCacheIDs()#">
<br />
<a href="wt-4.cfm">Refresh this page without URL parameters</a>
<br />
<a href="wt-4.cfm?pid=1">A second URL with pid=1</a>
<br />
<a href="wt-4.cfm?pid=2">A third URL with pid=2</a>
<br /><br />
<a href="wt-4.cfm?flush=1">Flush Cache</a>

This ColdFusion template, wt-4.cfm, caches part of the page that displays a date/time string while also displaying a date/time string that isn't cached. Following the two date/times is a <cfdump> that uses the undocumented GetAllTemplateCacheIDs() function to show the metadata of all items currently in the template cache. At the top of the code is a simple conditional that checks for a URL parameter called flush. If the parameter exists, meaning someone clicked the hyperlink at the bottom of the code, we ask ColdFusion to flush the cache with URL reference "*wt-4.cfm*."

This is supposed to direct ColdFusion to remove any cached page that has wt-4.cfm as part of it's cache ID. Unfortunately, this doesn't work in the 9.0 release of ColdFusion. No matter what you put as the value of expireurl the behavior is the same. Let's walk through an example.

Suppose you run the page for the first time in your browser. The two displayed date/times will match and one page will exist in the cache.


URL: wt-4.cfm

If you then press the link that says "A second URL with pid=1" the results will look like this. Because the URL is different, a new page is added to the cache and the two date/times match.


URL: wt-4.cfm?pid=1

Next, press the link that says "A third URL with pid=2." A third page is added to the cache. We now have one page in cache that matches the URL wt-4.cfm, one page that matches the URL wt-4.cfm?pid=1, and one page that matches the URL wt-4.cfm?pid=2. All three cached pages have unique cache IDs associated with their respective URLs.


URL: wt-4.cfm?pid=2

Now, press the link that says "Refresh this page without URL parameters." This will run wt-4.cfm without any URL parameters. Since this template + URL combination was already cached earlier, no new caches are added and the first and second date/time values are different. The first date/time is pulled from cache and the second should be the current server date/time.


URL: wt-4.cfm

Now press the link that says "Flush Cache." The wt-4.cfm template is called with the URL parameter flush=1. The conditional statement at the top of the page executes and the <cfcache> tag attempts to flush cache with the expireurl attribute set to "*wt-4.cfm*." According to the ColdFusion 9 documentation this statement, with the included wildcard, should cause all cached pages that have a cache ID similar to wt-4.cfm to be removed from cache. Oddly, the first page we ran, wt-4.cfm without any URL parameters, is removed from cache and a new cached page with wt-4.cfm?flush=1 is added to cache. Here's the output in a browser.


URL: wt-4.cfm?flush=1

Finally, press the "Flush Cache" link again. When the cache flush occurs this time, the page with the URL pid=1 is removed from cache. The page we just ran a moment ago with flush=1 in the URL was already cached, so ColdFusion pulls the first date/time from cache and the second date/time from the current server time. Here's the resulting browser output.


URL: wt-4.cfm?flush=1

This behavior seemed quite odd so I sent some examples to Rob Brooks-Bilson to see what he thought. After trading e-mails back and forth we both believe this is a bug in the way expireurl works when flushing caches. Basically, it doesn't work. You can't rely on what you put for the value of expireurl and it doesn't appear it matters what you set it to.

The takeaways from this post are:

  • page and page fragment cache are stored in template cache
  • by default, a URL will be cached once unless the useQueryString attribute is set in the <cfcache> tag
  • if you use the useQueryString attribute each unique URL will be cached separately
  • you can flush the entire template cache using the <cfcache> tag
  • when caching pages with useQueryString set, you cannot yet rely on expireurl to remove certain pages from cache

Click here to download the code mentioned in this post.

Update 11.21.2009:
Thanks to Rob Brooks-Bilson for pointing out a small but critical detail I failed to mention in this post. When I discussed how different URLs can be treated as separate cached items I did not mention this is not default behavior of the <cfcache> tag. In order for this to occur you must add useQueryString="true" to the tag. After talking with Rob I began to redo my examples and noticed really really quirky behavior when using expireurl. This post was almost entirely rewritten as a result.

Aaron West's Gravatar
About this post:

This entry was posted by Aaron West on November 20, 2009 at 8:00 AM. It was filed in the following categories: ColdFusion. It has been viewed 13292 times and has 11 comments.

13 related blog entries

11 Responses to 14 Days of ColdFusion 9 Caching: Day 4 - Flushing a Template From Cache

  1. Your posts are so bite-size and easy to understand. Thanks.

  2. Heh, I suppose that's a compliment. Super duper detailed /can/ be a good thing. Sometimes. My Apache, SVN, ColdFusion series is ridiculously detailed but then again those posts originated from a 60+ page PDF. Thanks for the comment Ben.

  3. Sorry, it was completely meant as a compliment; perhaps I should have created more of a context - since you are planning 14 days of this, having all 14 days at one go would have been completely overwhelming :) That's really what I mean. I am excited to learn more about this.

  4. Thanks for the compliment Ben. Coming from you, it's more than appreciated.

  5. FYI - I logged a bug about the weird behavior with the cfcache tag's useQueryString and expireurl attributes. The bug, number 80894 was confirmed by Adobe and has already been fixed. I suppose the first hotfix, 9.0.1 maybe, will include this fix.

  6. Has this been addressed? I looked at the CF 9.0.1 hotfix but did not see it in the list.

  7. @Rob - the bug (80894) was verified by Adobe in ColdFusion 9.0 and is now marked as closed. I'm going to ping the ColdFusion team to see if the fix for this bug is included in the forthcoming 9.0.1 release.

  8. Hemant's Gravatar Hemant

    This bug is fixed in our upcoming release.

  9. Hemant - from the Adobe ColdFusion engineering team - confirmed the expireURL bug as fixed in 9.0.1. I wanted to update everyone to say I have also confirmed bug 80894 as fixed in 9.0.1.

    Now, only those cached pages with a cache ID (URL) that matches the pattern in expireurl are removed from the template cache. Remember, this requires the use of the useQueryString attribute in the cfcache tag.

  10. FellowCFer's Gravatar FellowCFer

    Aaron West your a life saver... the part about "Remember, this requires the use of the useQueryString attribute in the cfcache tag" was what I needed to know as I couldn't FLUSH caches that weren't made without that property set to TRUE. NOWHERE is that documented that you can't flush a template without that turned on!

  11. PJ's Gravatar PJ

    Thank you for this excellent series! It's a total lifesaver from me, coming into caching on CF9 and literally knowing zip about it aside from the cfquery cache features we've had a long time.

    Trivia: You wrote, "Yesterday I eluded to the importance ..." I believe you mean 'alluded' (implied a reference to) not 'eluded' (escaped). :-)

Leave a Reply

Leave this field empty

If you subscribe, any new posts to this thread will be sent to your email address.

RSS