With russian doll caching, how do you handle pre-warming your cache on certain pages when new data comes in?


Imagine having an admin dashboard where you list all users. These users have an association with charges.

Instead of including charges you decide to use russian doll caching so you decide to render your collection of @users, use cached: true and set up touch: true on your Charge model. Basically following the official Rails guide on caching.

You visit your /admin/users dashboard page and everything loads. You refresh the page and notice you have [10 / 10] cache hits. It’s all working perfectly.

But now you send an email campaign out and 600 new people sign up. You’ve paginated your results so you see 100 users at a time.

When you reload the /admin/users page you have 90 cache misses here and end up with an explosion of queries. Realistically you may pull and display information from a few tables which leads to hundreds of queries.

The RailsWorld 2023 keynote by DHH made it seem like they have gone even further all-in with russian doll caching and using solid cache but how do you handle the above use case to avoid executing hundreds of queries? Sure I could include or preload everything but then you might as well not cache anything because that preloaded query would happen in your controller on every request.

Am I missing something? Thanks.

Sorry, this isn’t really an answer.

I think you’re exactly right, you would hit those 90 cache misses + explosion of queries. I think the real question is if that’s harmful or not?

This would be a pretty-much worst case scenario: 90% miss on your cache.

This happens for 1 user, all subsequent users do hit the cache.

How slow are those queries really?

How much does it degrade the experience of this 1 user this 1 time, compared to degrading everyone’s experience (somewhat) by preloading all associations all the time for all users: even if you don’t need to.

Whether it’s harmful or not really depends on the nature of the data, amount of reads vs. writes, amount of associations, etc. etc.

That’s just my 2 cents.


I’m curious if anyone does have a different strategy? If somehow pre-warming is a possibility.

I just don’t think it is :man_shrugging:

They’re not too slow, but there could be a lot of them.

Another good example is enrollments, they would have N+1 queries on users, courses and packages and it’s a model where if you paginated 20 of them you could expect there to be 3-4 misses on a daily basis so that’s about ~10 queries let’s say. Access wouldn’t be frequent, every once in a while (less than 10-20 times a week).

But, once the data is cached it’s likely never going to change. The same goes for charges.

It does make me think though, if these tables had more data and were accessed more frequently I don’t really have a good answer to solve it in an efficient way. It seems like there’s a constant battle between wanting to use russian doll caching or preloading but rarely both, although there’s still a benefit of caching even if you preload because rendering views tends to be one of the slowest parts of Rails to produce a response.

You bring an interesting question here. If you use views cache to save SQL queries, it somehow means that views are responsible for calling SQL queries, which is not really MVC.

Would it be better to cache the SQL queries (that you got with an includes/preload) directly in the controller and then cache the views?