Dependent Caching is a new feature in ColdFusion 9 that I immediately thought would be really useful. But when it came time to create an actual example for my BFusion talk back in October I was at a loss. I talked with my team at Dealerskins hoping they'd have some good ideas and while we all came up with a few none were fantastic. As MAX 2009 approached I continued to struggle with concepts I thought were doable but just weren't "real world" enough. I wound up creating an example based on a fictional order processing system. This still isn't good enough in my mind, but it works and should be fine for an example in a blog post. With that said, Rob has come up with a better example so I encourage folks to read through his post on this topic as well. But don't leave just yet! Read through this post first.
Exactly what is dependent caching in ColdFusion 9? It's a way to store cached pages or page fragments based on the value of a variable or list of variables. Consider the following pseudo code:
<!--- Set the dashboard level based on some lookup --->
dashboardLevel = "superuser"
dashboardLevel = "administrator"
<cfcache action="cache" id="dashboard-cache" dependsOn="dashboardLevel" timespan="#CreateTimeSpan(0,0,30,0)#">
This example shows pseudo code that could be used to display and cache a dashboard interface for different levels of users. Perhaps the dashboard includes modules that run complicated queries against a database and then displays an intricate HTML/CSS interface to represent the data. There are several different types of dashboards depending on the access level of the authenticated user. Superusers for example might see a dashboard that gives them insight into the health of the application. Administrators might see reporting data on how the organization is functioning with respect to key performance indicators (KPIs). Instead of having the code on the page run every time the user visits the dashboard, you simply cache the page for each user that has the specific access level. In this case there would be four cached pages each with a timespan of thirty minutes. The first user to access the dashboard in each access level would cause the page fragment to be cached. Subsequent users in each access level would see the page quickly since it would be pulled from cache.
Let's take a look at another example, this one using real code. Again, I don't think this is an awesome example, but it does demonstrate dependent caching.
Imagine an order processing system that performs heavy processing each time a new order is submitted into the system and queued via a Web interface. Order fulfillment specialists access the order processing system which retrieves new orders from a database. When no new orders exist, information about previous orders are displayed. When new orders exist, they are processed with some magical, super heavy code that takes a while to run. This code needs to be cached to help the page load faster on later visits. Here's the watered-down code that powers the system.
<cfquery name="getOrders" datasource="cfartgallery">
ORDER BY ORDERDATE DESC
<!--- Cache a heavy process that depends on the number of records in the Orders table. --->
<cfcache action="cache" id="wt-9-cache" dependsOn="getOrders.RecordCount" timespan="#CreateTimeSpan(0,0,30,0)#">
<cfoutput>Some big heavy process that does something with new orders...
Number of orders #getOrders.RecordCount# on #Now()#
The first thing the processing system does is retrieve orders from the database. The code here is using the built in Apache Derby cfartgallery database. After retrieving the orders a <cfcache> block is started with the dependsOn attribute added. This particular code is dependent on the number of records in the ORDERS table. If the number of records has changed (new orders) the page performs tasks that process the order. Next, to simulate the load of a heavy page we ask ColdFusion to sleep for one second. Finally, we output the number of orders and the current server date/time of the order.
To see this code in action, run it on your ColdFusion 9 server. You don't need to create a database or even a datasource since we're using the cfartgallery database.
Run this page in a browser to cache the page fragment based on the number of current records. If your database is still in its default state you should have 23 records in the ORDERS table. Here's the output from my browser.
After little more than a second, the page renders and you see the number of orders along with the current date/time of the server. If you refresh the page it should appear to run a little quicker since the page fragment is pulled from cache and the sleep() code isn't executed. At this point we have a cached fragment that is dependent on the number of orders equaling 23.
For step 2, create a new ColdFusion template named whatever you want (the downloaded code uses the name wt-9-update.cfm). Ensure the following code is in the template.
INSERT INTO ORDERS (TAX, TOTAL, ORDERDATE, ORDERSTATUSID, CUSTOMERFIRSTNAME, CUSTOMERLASTNAME, ADDRESS, CITY, STATE, POSTALCODE, PHONE)
VALUES (10, 100, #CreateODBCDateTime(Now())#, 1, 'Aaron', 'West', '2009 ColdFusion Ave', 'Nashville', 'TN', '37203', '415-555-9836')
<!---<cfquery name="deleteOrder" datasource="cfartgallery">
where ORDERID = 24
Run this new template in your browser. The insert query will run and create a new record in the art gallery ORDERS table.
Now that we've added a new record to the ORDERS table, rerun the original template. You should see results similar to the following.
Since a new order has been placed in the system and the record count of the getOrders query has changed, ColdFusion will process the order and cache the results of the page independently from the previous version of the page. This is a pretty significant event given the URL of the page didn't change. Why? Well, to have different versions of a page cache independently from one another the obvious thing to do is to pass in URL parameters and instruct ColdFusion to cache different versions using useQueryString="true" in the <cfcache> tag. But dependent caching with the dependsOn attribute is another way to accomplish the same task. I actually think dependsOn is a little more flexible and powerful than useQueryString, but both have their place.
To see the effect of the cached orders, comment out the insert query you created in step 2 and uncomment the deleteOrders query. Rerun your second template. Now go back to the first template and run it again. You should be back to the original number of orders (23). In fact, the date/time displayed on the page should be the same as the date/time you observed in step 1. Here's the output from my browser.
This time the page executed the order processing didn't occur. Instead, the basic order information was retrieved from template cache and the page loaded faster. Obviously this example is a bit of a stretch. How many order processing systems would process an order based on a record count value from a database. None, probably. But, the first example as well as this orders example show what's possible with dependent caching in ColdFusion 9.
What sort of use cases can you come up with for dependent caching? If you have any clever ideas submit a comment below; I'd love to read your thoughts.
Click here to download the code mentioned in this post.
About this post:
This entry was posted by Aaron West on November 25, 2009 at 10:03 PM. It was filed in the following categories: ColdFusion. It has been viewed 13121 times and has 3 comments.
13 related blog entries
- 14 Days of ColdFusion 9 Caching: Day 14 - Setting the Server Cache Properties (November 30, 2009)
- 14 Days of ColdFusion 9 Caching: Day 13 - Retrieving the Server Cache Properties (November 29, 2009)
- 14 Days of ColdFusion 9 Caching: Day 12 - Removing All Items in Cache (November 28, 2009)
- 14 Days of ColdFusion 9 Caching: Day 11 - Reporting On All Items in Cache (November 27, 2009)
- 14 Days of ColdFusion 9 Caching: Day 10 - Session-Specific Caching (November 26, 2009)
- 14 Days of ColdFusion 9 Caching: Day 8 - Cache Hits and Cache Misses (November 24, 2009)
- 14 Days of ColdFusion 9 Caching: Day 7 - Using cacheRemove to Flush Items from Cache (November 23, 2009)
- 14 Days of ColdFusion 9 Caching: Day 6 - Using cachePut, cacheGet, and cacheGetMetadata (November 22, 2009)
- 14 Days of ColdFusion 9 Caching: Day 5 - The Difference Between Timespan and Idletime (November 21, 2009)
- 14 Days of ColdFusion 9 Caching: Day 4 - Flushing a Template From Cache (November 20, 2009)
- 14 Days of ColdFusion 9 Caching: Day 3 - Viewing Page Cache Metadata (November 19, 2009)
- 14 Days of ColdFusion 9 Caching: Day 2 - Caching a Page Fragment (November 18, 2009)
- 14 Days of ColdFusion 9 Caching: Day 1 - Caching a Full Page (November 17, 2009)