ColdBox Event,Views,Object & Data Caching Guide
For caching, I really wanted to take my time and prepare something useful and smart. It has various tuning parameters such as default object timeout, default last access timeout, maximum objects to have in cache, a JVM memory threshold and a reaping frequency in which to garbage collect. This is an in-memory cache that lives in Application Scope designed for handlers, plugins, events, views and any other objects or data you so desire. You can choose to place timeouts on them or use the global default timeout the framework provides. This cache is also thread safe per application.
The cool thing about the last access timeout is that you can tell the cache to purge objects that have not been used for X amount of minutes. So the cache cleans itself out periodically using the reaping frequency. So every X minutes, when a request comes in that needs something from cache, it will run the reaping routing to clean old objects out.
And since I really wanted for users to know what was going on in order for them to tune their cache, I added a caching snapshot report to the debugging panel that can even be opened by itself so you can watch your cache performance on AJAX applications. It tells you the efficiency of the cache in hits vs miss ratio, it shows you how many objects exist in the cache, the free and total JVM memory and it even charts for you the hits vs misses and the actual types of objects in that are currently in the cache in a pie chart and event the contents of the objects in the cache. WOW!!!
Cache Monitor Screenshot
Does the cache take advantage of ColdFusion 8?
Yes, the new ColdBox Cache in version 2.5.0 and later, have cf8 support, in which it takes advantage of using the cfthread tag to create new threads for reaping and maintenance. This increases the performance of the cache.
How do I use It?
Well, the main methods for using the cache can be found in the ColdBox API. However, the main method that you need to memorize to use the cache is getColdBoxOCM(). This method is used to retrieve the coldbox cache manager so you can interact with the cache.
Below are some of the most used caching methods:
| clear | DO NOT CALL FROM A CACHED OBJECT SUCH AS A HANDLER,PLUGIN OR INTERCEPTOR. If you do, then you will receive a coldfusion 500 null error.VERY VERY bad. If you want to clear all the objects in the cache, you can either, reinitialize the application or use the expireAll() method. |
| clearKey | Clears a key from the cache. |
| expireAll | Expires all the objects in the cache. This is safe to call from cached objects. |
| get | Get an object from cache. If it doesn't exist it returns a blank structure. |
| getSize | Get the cache's size in items |
| lookup | Check if an object is in cache. |
| set | sets an object in cache. |
New Methods since version 2.5.0
| clearEvent | This method is used to purge events using names, partial event names or name + arguments. This is done asynchronously by default |
| clearAllEvents | This method will clear all event caching, asynchronously by default |
| clearAllViews | This method will clear all view caching, asynchronously by default |
How to open the caching panel?
In order to open the cache debug panel you must first be in debug mode. Please look at the URL Actions Guide. Once the panel is open, you can see a cache overview report and a cache content report. You can now even click on the name of the cached element in order to see its content.
The debugpanel url action can ONLY BE used when in debug mode. If you are not in debug mode, then the panel will not be rendered. You can open the monitor by clicking on the Open Monitor button inside of the cache panel of the debugger or you can open it by going to the following URL:
index.cfm?debugpanel=cache
Techniques
There are various ways that you can use the coldbox cache and it all depends on the data you want to store and how to retrieve it. One method that I have used for storing queries in the cache is to use the on application start method to place the queries on the cache indefinitely.
//On the application start <cfscript> var qStates = getPlugin("ioc").getBean("lookupsService").getStates(); var qCountries = getPlugin("ioc").getBean("lookupsService").getCountries(); //Place in cache indefinetly until application reinitializes. getColdBoxOCM().set('qStates',qStates,0); getColdBoxOCM().set('qCountries',qCountries,0); </cfscript> //Then on my handlers or views/layouts I can do the following <cfset qStates = getColdboxOCM().get('qStates')>
This is a simple example of placing data on the cache that will persist the entire application. Another example is you can place a query to persist for 10 minutes:
<cfset getColdboxOCM().set('myQuery', myQuery, 10)>
However, when you do a get the method can fail because the query might have expired. That is why you have the lookup() method which tells you if the key you sent in exists in the cache. This is useful to create facade methods where you can do the following:
<cffunction name="getMetadata" access="private" returntype="any" output="false"> <cfargument name="lookup" type="string"> <cfscript> var oMD = structnew(); if ( getColdboxOCM().lookup(arguments.lookup) ){ oMD = getColdboxOCM().get(arguments.lookup); } else{ //Create md from Transfer oMD = getTransfer().getTransferMetaData(arguments.lookup); //set back in cache getColdboxOCM().set(arguments.lookup, oMD, 10); } return oMD; </cfscript> </cffunction>
This is a great example of using the coldbox cache for checking and verifying data. As you can see, there are several ways to tap into the power of the coldbox cache. The following example is to create your own url action to expire objects that is part of a request start handler.
<cffunction name="onRequestStart" access="private" returntype="void" output="false"> <cfargument name="event" type="any" required="true"> <cfscript> //Request start handler. //check if you pass in a url var called: clearcache if ( event.valueExists("clearcache") ){ getColdBoxOCM().expireAll(); setNextEvent(); } </cfscript> </cffunction>
How To Cache a View:
In order for you to cache a view, you will have to use the event.setView() method. With this method, you are saying that the view you just set for rendering, needs to be cached. So the next time the view get's rendered by ANY event, it will render from cache rather than from execution. Below are the arguments to the setView() method.
Arguments
- view : the view to render or cache
- nolayout [default=false] : Whether to render the view in a layout or not
- cache [default=false] : Cache or not the view.
- cacheTimeout [default=""] : The timeout of the view in cache
- cacheLastAccessTimeout [default=""] : The last access timeout before the view expires.
So in order to tell the framework to cache the view called vwHome for 10 minutes, you would do the following:
event.setView(view="vwHome",cache="true",cacheTimeout="10");
That easy!! The framework reads the caching metadata, constructs a cache entry and then saves it for pickup by the renderer plugin. How can you tell if the view was rendered from cache or not? Well, if you are in debug mode, you can check out the debugging panel and you will see that if you are normally rendering a view it says: Rendering View [vwHome.cfm]. However, if rendering from cache, it will say: Rendering Cached View [vwHome.cfm]
Purging Views
Use the getPlugin("renderer").purgeView( view ) method or there is also a purgeView(view) facade method on the super type. That means that all handlers,plugins and interceptors get this facade method. To purge all views, just reinit the app using the fwreinit URL action or call the clearAllViews() method in the ColdBox Cache.
Ways to purge views:
- getPlugin("renderer").purgeView('view name')
- purgeView('view name')
- getColdboxOCM().clearAllViews( [async=true] )
For example, to purge the vwHome view just do the following:
getPlugin("renderer").purgeView("vwHome");
//or
purgeView("vwHome");
//or purge all Views
getColdBoxOCM().clearAllViews();
How do I cache an event? What is this?
Event caching is extremely useful and easy to use. All you need to do is add several metadata arguments to the cffunction tag of your event and the framework will cache the output of the event. In other words, the event executes and produces output that the framework then caches. So the subsequent calls do not do any processing, but just output the content. Almost all of the entire lifecycle is skipped, the content is just delivered.
Cached Event Lifecycle
- Event is trapped
- URL action fwCache is verified, if it exists, incoming event is purged from cache.
- preProcess Interception is executed
- RequestStartHandler is executed
- Cached content is retrieved and outputed.
Please be aware that an event can have several unique permutations depending on the incoming url/form parameters. Also, caching is application wide, not user wide. So be careful of not caching secure events or session based events.
As from the warning above, when event caching is enabled for an event, the framework will hash the incoming request collection plus the incoming event to determine a cacheable key. So an event can have thousands of different combinations that will create multiple cache entries. So make sure that you have the Cache Max Objects setting turned on.
Enabling Event Caching
To enable event caching, you will need to set a new setting in your configuration file called EventCaching which is a boolean variable.
<Setting name="EventCaching" value="true" />
If you do not enable this setting, the framework will not cache your events.
Setting up an event for caching
The way to set up an event for caching is on its cffunction declaration with the following extra arguments:
| ATTRIBUTE | TYPE | DESCRIPTION |
| cache | boolean | A true or false will let the framework know whether to cache this event or not. The default is FALSE. |
| cachetimeout | numeric | The timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default object timeout in the cache settings. You can place a 0 in order to tell the framework to cache the event's output for the entire application timeout controlled by coldfusion, NOT GOOD. Always set a decent timeout for content. |
| cacheLastAccesstimeout | numeric | The last access timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default last access object timeout in the cache settings. This tells the framework that if the object has not been accessed in X amount of minutes, then purge it. |
Please be aware that you should not cache output with no timeouts. Always use a timeout.
Here is an example of setting up an event for caching:
<cffunction name="dspBlog" access="public" returntype="void" output="false" cache="true" cacheTimeout="30">
That's it, whenever the framework detects the dspBlog event, it will cache it.
Purging Events
If you need to override the event so you can see the real deal, you can use a new URL action called: fwCache This URL action tells the framework to not cache the incoming request. If the event is cached, it will first purge it and re-execute and re-cache it. If you want to purge all events, well, just reinit the application using the fwReinit URL action or call the clearAllEvents() method on the ColdBox cache. This will clear all the events in the cache. However, there is a final method that can clear a family of cached events, or family of handler events and more, the clearEvent() method.
Ways to purge events:
- URL Action fwCache
- getColdboxOCM().clearAllEvents([async=true])
- getColdboxOCM().clearEvent(eventSnippet,[queryString=""],[async=true])
Examples:
//Trigger to purge all Events
getColdBoxOCM().clearAllEvents();
//Trigger to purge all events sync
getColdboxOCM().clearAllEvents(false);
//Purge all events from the blog handler
getColdbocxOCM().clearEvent('blog');
//Purge all permutations of the blog.dspBlog event
getColdbocxOCM().clearEvent('blog.dspBlog');
//Purge the blog.dspBlog event with entry of 12345
getColdbocxOCM().clearEvent('blog.dspBlog','id=12345');
As you can see from the clearEvent() samples, you can send in snippets of event names and the cache will try to find keys that match and reap them. You can also do this asynchronously if cfthread is available in your engine.

