ObjectBroker; arbitrary cache namespaces

ObjectBroker is FarCry’s internal cache management system.

It is used to cache content objects (ie the data of each content item) and webskins (aka views). In FarCry 7.0, friendly URL and dmNavigation/dmCategory alias lookups were added. With this most recent change, all FarCry core caching including arbitrary cache namespaces is handled by the ObjectBroker.

The ObjectBroker service is managed by the ./packages/lib/objectbroker.cfc component, and it’s behaviour can be extended or overridden by plugins. So far we have had a lot of success storing FarCry caches in EhCache servers, Memcache and Amazon ElastiCache clusters.

Configuration

You can set up any number of cache namespaces on application initialisation from your ./config/_serverSpecificVarsAfterInit.cfm config:

<cfset maxObjects = 10000 />
<cfset cacheTimeout = 3600 />
<cfset application.fc.lib.objectbroker.configureType("myCacheNamespace", maxObjects, cacheTimeout) />
<cfset application.fc.lib.objectbroker.configureType("myCacheUnicorn", maxObjects, cacheTimeout) />
<cfset application.fc.lib.objectbroker.configureType("myCacheRainbow", maxObjects, cacheTimeout) />

Using ObjectBroker

Setting cache content

Example for caching the result of a search using url.q as the filter:

<cfset key = "query-" & rereplace(url.q, '[^\w]+', '-', 'ALL') />
<cfset data = { q=qSomeResult } />
<cfset application.fc.lib.objectBroker.AddToObjectBroker(data, "myCacheNamespace", key) />

Notes:

  • The data must always be a struct, even if it only has a single item
  • The data must be serializable to / deserializable from JSON - no components or Java objects
  • The cache key must only contain alphanumeric characters and hyphens

Getting Cache Content

Example for getting the cached search results:

<cfset key = "query-" & rereplace(url.q, '[^\w]+', '-', 'ALL') />
<cfset stResult = application.fc.lib.objectbroker.GetFromObjectBroker(key, "myCacheNamespace") />
<cfif structIsEmpty(stResult)>
    <!--- Data is not in the cache --->
<cfelse>
    <!--- Use cache result here --->
</cfif>

Notes:

  • If an item is not in the cache ObjectBroker will return an empty struct.

Removing Items From ObjectBroker

Example of removing data from the cache.

<cfset key = "query-" & rereplace(url.q, '[^\w]+', '-', 'ALL') />
<cfset application.fc.lib.objectbroker.RemoveFromObjectBroker(key, "myCacheNamespace") />

Best Practices

Cache Usage Should be Transparent

The process of checking the cache for data, and adding a cached value if there is none, should be encapsulated in a function. Developers using your functionality should not need to know about ObjectBroker. A lib, e.g. packages/lib/mysearch.cfc, or a content type component is a good place to put that function.

Allow the Developer to Skip the Cache

This gets us all - we waste time troubleshooting an issue and not seeing results, only to realise that the page had been in the cache the whole time. FarCry has a setting to disable caching in the tray; you can use that setting too.

When the caching is disabled FarCry sets request.mode.flushcache to true.

Complete Example

In this example, I have encapsulated the search examples we’ve been using so far.

<cffunction name="getResults" returntype="query" access="public" output="false">
   <cfargument name="filter" type="string" required="true">
   <cfargument name="bFlushCache" type="boolean" required="false" default="#request.mode.flushcache#">
        
   <cfset var key = "query-" & rereplace(arguments.filter, '[^\w]+', '-', 'ALL')>
   <cfset var data = application.fc.lib.objectbroker.GetFromObjectBroker(key, "mysearch") />

   <cfif arguments.bFlushCache or structIsEmpty(data)>
       <cfset data.result = application.fapi.getContentObjects(typename="dmHTML", title_like="%#arguments.filter#%") />
       <cfset application.fc.lib.objectBroker.AddToObjectBroker(data, "mysearch", key) />
   </cfif>
        
   <cfreturn data.result />
</cffunction>

<cfset qResult = application.fc.lib.mysearch.getResults("home") />
1 Like