I’ve been using CacheBox within Coldbox for awhile, but I’ve never really understood the details of how the set() method works. Specifically, I’m unclear on the difference between timeout and lastAccessTimeout, in a real world example.
What’s interesting is that running a search in the CacheBox docs for LastAccessTimeout yields no results and I don’t see a dedicated page describing how to set() and get() aside from the examples section of the common cachefactory methods page
I would be happy to contribute to the ColdBox or CacheBox docs on how to cache data within a ColdBox app if I had a better understanding of how this works.
Here’s how I currently use data caching in my ColdBox models, for anyone else that stumbles upon this post. I believe I learned this pattern in one of the Ortus ColdBox in-person training courses:
// Example model object in /models/ folder
component
singleton
{
// Inject an instance of the Coldbox cache factory
property name="cache" inject="cachebox:default";
/**
* get
* Returns a struct of data
*/
struct function get( required id ) {
// build a unique, yet reproduceable cache key based on a namespace and the unique id of the data we want
var cacheKey = "mydata-#arguments.id#";
// if our data already exists in the cache, return it.
if ( cache.lookup( cacheKey ) ) {
return cache.get( cacheKey );
}
// assert: The data wasn't found in the cache. Get it (API call, database query, etc)
var result = getTheData( arguments.id );
// Put the data in the cache for later retrieal.
cache.set( cacheKey, result.data, 30, 15 ); // timeout 30 minutes, lastAccessTimeout 15 minutes
return result.data;
}
}
I have no idea if the above is a best-practice or not, so if anyone has suggestions on improving the pattern (perhaps with some type of scope locking) please feel free to share.
Time to update the docs then. Here is the reason behind both times.
Timeout
This is how long an object can potentially live.
Last Access Timeout
This is an OPTIONAL, timeout, that if attached to the entry, make it more prominent to remove it from cache if that specific entry is NOT retrieved by anybody in that period of time. This number has to be less than the timeout to make any sense at all.
This makes the cache policies of LFU (least frequently used) to take advantage of those entries that have been less frequently accessed and kick them out.
Thank you for the explanation. Let me break it down with a real-world example to make sure I understand.
Let’s say I cache a list of the top 100 greatest reggaetón songs of all time with the following: var songs = cache.set( 'songs-for-itb', getSongs(), 60, 15 )
The above code would cache the list of songs for 60 minutes UNLESS a get() isn’t called within 15 minutes. If 15 minutes goes by without calling get(), the cache will clear the list of songs.
If I alter the code to this and omit last access timeout: var songs = cache.set( 'songs-for-itb', getSongs(), 60)
The songs will be cached for 60 minutes, no matter what.
Ah yes, I didn’t consider the CacheBox default configuration.
Here’s a question: Assuming that you only have one item cached, with a timeout of 60 and a last access timeout of 30, and the cached item is retrieved every 5 minutes for a full day, will it ever get refreshed? Or will it perpetually remain cached as long as it is called?
Or does the 60 minute timeout take precedence and the item will be refreshed every 60 minutes regardless?
resetTimeoutOnAccess : If true, then when cached objects are retrieved their timeout will be reset to its original value and thus elongating the survival strategy of the items. Much how session storages work.
If you have this enabled, then the last access timeout will be reset as it is accessed. This is actually how session scope works. Meaning that a usage retrieval kicks the can down the road and your timeout is reset.