I'm doing a code review for a client (which I've been doing a lot lately and boy is it fun to find bugs in someone else's code for once ;) and noticed his home page was using CFFEED to put CNN's latest articles. However, he wasn't doing any caching at all. I whipped up a quick mod for him to show a simple example of caching. It doesn't have any fancy way to force a refresh, but quickly sped up his home page. So here is a quick code snippet showing simple caching of CFFEED:
<cfset feedurl = "http://www.mugglenet.com/feeds/news.xml">
<cfset cacheMinutes = 60>
<!--- check if cached, and not too old --->
<cfif not structKeyExists(application,"rsscache") or dateDiff("n", application.rsscache.created, now()) gt cacheMinutes>
<cffeed source="#feedurl#" query="entries">
<cfset application.rsscache = structNew()>
<cfset application.rsscache.data = entries>
<cfset application.rsscache.created = now()>
</cfif>
<cfdump var="#application.rsscache#">
All I do is check for an application variable. If it doesn't exist, or the 'created' value for the cache is more than cacheMinutes old, I reload from cffeed. While not as fancy as a conditional get, it is certainly a lot simpler.
Archived Comments
Oh for CF8 & CFFEED :)
In CF7 I built an aggregator based on rss.cfc which uses a scheduled task (checks the feeds once an hour) to write the entries to a static page.
Works though :)
Ooooh! New look! Love what you've done with the place.
If cacheMinutes were application.cacheMinutes, then it could be set to 0 by an admin program.
This would force a refresh the next time anyone visited the page.
It would then need to be reset back to 60.
Ray,
Thanks for the great example. I am doing something similar, but I write the feed to a local xml file. Then I read that locally for the next hour.
Do you think there is any speed difference between reading from a local file, or an application struct?
@PS: My problem with that though is that it would need two steps to clear the cache. First it needs to get set to 0, then you need to rerun the CFM above to reload. I'd rather have a process by which I remove items from the cache using a simple structDelete. No need to change the timeout then. TO me - that is a static example.
@Jared - I would imagine the file system is slower than RAM access. Not significant probably, but I'd defer to using memory storage here instead of file storage. Of course, if your server restarts you loose the cache.
Oh, I see.
If your admin program does a
<cfset structDelete(application,"rsscache")>
Then that clears the cache and away you go.
Very good.
@PS - If you want to get _truly_ sophisticated, you could use a application.cache struct to hold all your caches, and build a 'service' to make it easier to clear crap:
cfset app.cache.clear("rss1")
for example. But I'm going to stop there. This post is on SIMPLE stuff. ;)
Nice. I do something similar but write the feed content to a file. This way no user is impacted in waiting for the feed to process.
I'm a bit of a perpetual noob, not to mention a tad late on this post, but if you could show me an example on how to loop through the application.rsscache to cfoutput the Content field found in the dump, that would make my day.
It's just a query, so cfoutput query="" would work fine on it.
Thanks for your response. So a cfoutput of the query "entries" (below) is what is cached?
<cfoutput QUERY="entries">
#Content#
</cfoutput>
No, remember the query was stored as application.rsscache.entries. It's a complex name, but it's just a query.
I too am looking for a feed-caching solution, and this one looks pretty simple. However, I'm trying to display the feeds as unordered lists, and I'm having a bit of a problem parsing your script for that. Any tips?
The result of cffeed is a query. You would output it as a UL just like you would any other query.
Thanks Ray. I actually got it working a few hours after I posted this, but was too embarrassed by how simple it was to get working.
This leads me to the next question of why it works locally on my CF10/Linux machine at home, but not on my shared hosting account. I'm guessing something is either disallowed or not set on the server.
You would need to share _how_ it isn't working in production.
Indeed, and I wish I could. The page just stops rendering at the spot where the code is, and wrapping it with a try/catch block results in no error message of any kind.
The account just got set up (I recoded my old PHP site in CF) so once I get everything else uploaded, I'll probably email the host's tech support to see if I'm using any disallowed tags. In the meantime, I'll fiddle with it some more and see if I get lucky.
Figgered it out! On my local machine, I was using a cfloop with startrow, endrow, and query, and a cfoutput inside that to build my list. I changed it to just a cfloop with query and maxrows, and bingo, it works on both.
Sometimes you just have to talk to a Jedi to work through these problems!
Glad you got it!