Integrated Social Media Feed With Caching

Yesterday I released a social media integration plugin for my site. On each page load, It would connect to twitter and facebook to get the latest set of data. This turned out to be horribly horribly slow. So I have now implemented an auto updating caching which checks for new data every 15mins or so.

this was not a overly difficult task, but one which took a little bit of thinking, so I am going to explain my thought process on this one.

Idea One: have the system run a scheduled task to update the application cache.

This has a couple issues. first off, my live site is on a virtual hosting where I so do not have access to the ColdFusion control panel, so I would need to set and manage this task programatically. In researching how to do that, I quickly find my second problem.

ColdFusion does not invoke Application.cfc methods, when invoking a task's event handler methods.

(https://wikidocs.adobe.com/wiki/.../cfschedule)

Because I am caching on the application, I need access to the Application and the variables contained within. This does not explicitly say I do have access to the application scope, but its enough to make me want to think about other options.

Idea Two: Skip the Cache, Persists the Data

This could be a good option as well, but highly complicates the process. It would require me to fetch the data somehow, store said data in the persisted structure somewhere/somehow, then change my plugins to access that persisted data.

In addition, it would need to do so without use of an scheduled task less I build an interface to maintain that task.

It'll work, but not without a lot of setup. I will keep this as a backup plan.

Idea Three: A Self Maintaining Application Cache

Change my current plugin to make use of its own caching abilities. because I am setting my CFC as an application variable, I can persist the data inside that CFC.

public array function getTwitterUserFeed(string screenName = "liaodrake") {  
    if (this.isConnectedToTwitter()) {

        if (!structKeyExists(VARIABLES,"twitter")) { VARIABLES.twitter = {}; }
        if (!structKeyExists(VARIABLES.twitter,ARGUMENTS.screenName)) { VARIABLES.twitter[ARGUMENTS.screenName] = {}; }

        if (!structKeyExists(VARIABLES.twitter[ARGUMENTS.screenName],"feed")) {
            VARIABLES.twitter[ARGUMENTS.screenName].feed = this.getTwitter().getUserTimeline(screen_name=ARGUMENTS.screenName);
        }
        return VARIABLES.twitter[ARGUMENTS.screenName].feed;
    }
} // close getTwitterUserFeed

This works great... until I make a new twitter post. This is where we make the cache self managed. I want to make sure that my data is never more then X old. Lets say 15 minutes. To do this, we add another key to our feed structure for the time that data was retrieved. I can then do a dateDiff on that time to see if the data is older then 15 minutes.

public array function getTwitterUserFeed(string screenName = "liaodrake") {  
    if (this.isConnectedToTwitter()) {

        if (!structKeyExists(VARIABLES,"twitter")) { VARIABLES.twitter = {}; }
        if (!structKeyExists(VARIABLES.twitter,ARGUMENTS.screenName)) { VARIABLES.twitter[ARGUMENTS.screenName] = {}; }

        if (
            (!structKeyExists(VARIABLES.twitter[ARGUMENTS.screenName],"feed")) ||
            (!structKeyExists(VARIABLES.twitter[ARGUMENTS.screenName],"cacheTime")) ||
            (DateDiff("n",VARIABLES.twitter[ARGUMENTS.screenName]Time,now()) > 15)
        ) {
            VARIABLES.twitter[ARGUMENTS.screenName]Time = now();
            VARIABLES.twitter[ARGUMENTS.screenName].feed = this.getTwitter().getUserTimeline(screen_name=ARGUMENTS.screenName);
        }
        return VARIABLES.twitter[ARGUMENTS.screenName].feed;
    }
} // close getTwitterUserFeed

This now prevents the slowdowns for once every 15mins at most for my sites regular traffic load. On a large traffic load site, we would want to perform a lock on that caching operation to ensure that its not being fired continuously. In addition to that, I can set my cache intervals at different values to help disperse those calls over multiple page requests.

Thats the basic operation of my social media cache.