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.
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 eluded 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.
<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.













