brought to you by REVSYS

Don't Break Your Cache

Today we're going to tell you about a trick to make it easier to do whole page caching on pages where a small amount of the content differs by user.

Often your site has exactly the same content for 95+% of all pages, with one or two bits that are specific to the logged in user. Those bits usually are things like:

  • Login vs Logged in as frank
  • User specific sidebar
  • User specific tools, such as voting/rating buttons that aren't shown to anonymous users

Now obviously you actually have a "dynamic" site here, but thinking about it as such is like thinking of your average nursing home patient as "active". Technically true for some definition of the word, but it's a stretch.

You could simply cache pages for non-logged in users and dynamically generate the pages, with these small differences, for your logged in users. We know that 95+% of the content on these pages is going to be exactly the same, so we're purposefully giving our interested/engaged logged in users a slower experience. And for what? Just to show them they're logged in? Or to make the 'Add Comment' link show up? Here's an example from HackerNews.

Logged Out

HackerNews screenshot not logged in

VS Logged In

HackerNews screenshot with user logged in

This isn't to pick on HN. Sure they use <table>s for rendering non-tabluar data, but for such a high traffic site they're extremely fast. It's just the first site that came to mind that is popular enough that you have likely been there.

Enough with the setup, on to the tip!

Use Javascript to handle the differences

Yep, that's it. An earth shattering revelation. We wouldn't even mention it here in this performance series, but we see sites NOT doing this all of the time and we would like it to stop.

You're using Javascript on the page already. Likely even using it for more advanced purposes, so why not for this?

In Javascript, we've got access to the cookie(s) you're likely using to denote logged in users and track their session so there really is only a single downside: There is a possibility for user 'frank' to be logged out and the page still shows they are logged in.

This can happen because:

  • Their session cookie expires
  • Their session is closed or reaped on the server, perhaps to force users to login every week/month
  • They log out of the site from another device

"Unacceptable!!!", you say. But is it really? As a user the worst case is I see Logged in as Bob Smith at the top of the page, but when I go to actually use some of my logged in user powers I'm redirected to a login page. Or perhaps I see that, but my name is Frank and I'm confused for a second until I go to do something, login, and boom the problem fixes itself.

On a scale of zero to annoying, this is closer to the zero side.

Making it happen

Coding this for your site is even pretty easy, but will vary by your site, CMS, platform, etc. The general idea is:

  1. Store the user specific info in a cookie or even better in localstorage
  2. Load any larger or more frequently updated content, say a user specific sidebar, via ajax
  3. Dynamically inject that content into the page

Sorry to disappoint, but and that's all there is to it.

Assuming you have markup that looks like:

<div id="login">
    <a href="/login/">Login</a>
</div>

And a session cookie named 'session' and storing the username in a cookie named 'username', you'll need jQuery that looks like:

if( ($.cookie('username') !== null) && $.cookie('session') !== null) {
    var username = $.cookie('username');
    $('#login').html("<a href='/account/" + username + "/'>Logged in as " + username + "</a>");
}

Gotchas

There are a few issues around using this technique, but they're easy to work around. You need to:

  • NOT use the simple presence of these cookies to actually handle authentication
  • Remember to update the values in these cookies when the underlying data changes

Benefits

Doing this gives us several useful benefits. We can serve most logged in user pages without have to dynamically create them. This improves the perceived performance of the site AND reduces your need to expand server resources over time.

We can also take better advantage of CDNs pushing the, now effectively static, pages out closer to our end users.

Another small side benefit is that we now have a cookie with the username so even if the user is logged out we can entice them a bit with content like, "Welcome back Bob, haven't seen you in awhile...".

This technique however does quickly break down if more and more of your content becomes user specific, for those situations it's best to start using something like Varnish and Edge Side Includes instead.

Hope to see you using this technique in the wild soon. Happy Holidays!