DEV Notes: Don’t Forget To Clear Cache!

This post is for anyone who wants to contribute to the DEV codebase, and needs some notes on how caching might affect the features/bugs they’re working on.
We don’t have much info about caching in our docs (yet), except that fastly is listed as a key service we rely on for edge caching. That little note theoretically gives enough info for an experienced rails dev to know what to consider and how to navigate caching on DEV, but likely leaves juniors totally lost.
If you’re a bootcamp grad like me, caching might not have popped up in your curriculum at all — that’s because caching isn’t really something you need to think about until your app is serving a lot of traffic. So if you’re not familiar with the general concept of caching, please read this awesome article by Kevin Kononenko first:

Web Caching Explained by Buying Milk at the Supermarket
Kevin Kononenko


On DEV, we rely heavily on caching through our content delivery network, Fastly. This means your requests will hit the closest proxy server to your location (a server provided by the CDN that stores the files for our most common requests) instead of traveling all the way to the origin. If your request does need to hit the origin, we also rely on out-of-the-box caching features provided by Rails that also stores static, ready-to-go info. This means the browser, CDN, and Rails are all working together to fulfill a request before it goes directly to the underlying code for fresh assets.
Browser Cache > CDN > Rails Cache > Underlying Code
This is all pretty conventional so the Fastly and Rails documentation are great resources for learning more.
If you’re working on DEV, it’s worthwhile to ask: “should this be cached? and if so, at what level?" Or the reverse, "should the cache be cleared?" We’re going to focus on the latter for this article.
Recently, I was building the functionality to merge two users — sometimes people login via twitter and github separately (instead of linking them), which creates two accounts. A pretty straightforward process:

Move all activity from Account B to Account A.
Delete Account B.

After doing the above, one can reasonably assume that when I visit Account A’s profile, I would see all of the user’s consolidated activity. Nope! I had a momentary panic thinking all of Account B’s data was deleted. Turns out I didn’t signal, in my code, to clear the Fastly cache so the request didn’t receive fresh data. Yes, user profiles (/username) are all cached which means we need to clear the cache every time something on that page changes.
We have a cache busting object that makes it easy to purge our Fastly cache, along with a few handy methods for items that need to be purged regularly. This is the file: app/labor/cache_buster.rb that handles all the logic. Here’s how you would clear cache on my user profile:"/jess").
When I cleared Account A’s user profile path on Fastly, I expected to see all the consolidated activity. That was almost the case — articles, badges, and comments appeared but one of the social icons was missing (Account B’s original login method to be specific). Turns out we utilize low level Rails caching for user data. I didn’t run any ‘save’ callbacks that would have cleared the cache when I updated Account A’s profile. In order to clear this Rails cache, I needed to formally update the user — something like user.touch typically does it.
I don’t think it’s possible to run Fastly caching in development, but it is possible to run Rail’s caching with a simple rake task by toggling bin/rails dev:cache.
One last thing: aside from all of this, we also use a gem called CounterCulture. This gem keeps track of association counts like articles_count on a user and it helps us query faster. Sometimes these counts go out of sync (like when you don’t run proper callbacks when you update user activity…). If this happens to you, you can update the count directly. For example:
user.articles_count = user.articles.size

This was a bit of a ‘reverse’ view of our cache policy but I hope it provided some insight into the DEV app.