Caching in Wheels 4.0: Actions, Queries, Partials, and Invalidation #3290
bpamiri
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Your blog's home page runs eight queries. One of them — the "most popular posts this month" sidebar — is a
GROUP BYthat takes 400ms and hasn't changed in three weeks. Every visitor pays for it again. That's the caching problem, and Wheels 4.0 has four tools for it.The catch: they're four different tools, not one cache with four front doors. This post is a source-grounded field guide to all of them, and to the part nobody likes — invalidation.
Read: https://blog.wheels.dev/posts/caching-in-wheels-4
What the post covers
The thing that breaks everyone first.
cacheActions,cachePages,cachePartials,cacheQueries, andcacheImagesall default tofalsein development andtrueeverywhere else. Socaches(),includePartial(cache=...),renderView(cache=...), andfindAll(cache=...)silently do nothing on your laptop — then behave differently in production. The one exception iscacheQueriesDuringRequest, which is request-scoped and on even in dev.Action caching.
caches(actions="index,show", time=30)inconfig()caches the rendered response.static=truecaches the whole page viacfcacheand aborts the request before your before/after filters run on a hit — fast for public pages, dangerous for anything behind auth.appendToKey="session.userId"varies the key by a runtime value (and throwsWheels.KeyNotFoundif that var is missing).Query caching — the two-cache problem. This is where most confusion lives:
cacheQueriesDuringRequest, inrequest.wheels[ModelName]) dedupes identical queries within one request. Always on. Bypass withreload=true.findAll(cache=N)+cacheQueries) hands a nativecachedWithintimespan to the DB adapter — real engine-level query caching keyed on the SQL.reload=truedefeats the request-level one. It has nothing to do withcache=N. People mix these up constantly.Partial + page caching.
includePartial(cache=20)from a view,renderPartial(cache=...)/renderView(cache=...)from the controller — both gated on their settings, both using a double-checked lock so a cold cache doesn't trigger a thundering herd.Invalidation reality. There is no public
clearCache(key).clearCachableActions()only unregisters cachability — it does not evict already-cached content. Real invalidation is (1) expiry on thetimeyou set and (2) a full?reload=true, which re-inits the cache and flushescfcache. Design yourtimevalues like they're the only invalidation you have, because they nearly are.Sharp edges, all cited from source:
cacheDatePartdefault"n").cache=trueis 60.maximumItemsToCache=5000across all categories, with expired-only culling — when full and nothing's expired, new items are silently dropped. High-cardinality keys can quietly stop caching.cfcache(RustCFML).Duplicate) on every read and write (simple values like rendered HTML are returned directly).The post ties it together with a worked blog home-page example: action cache as the outer skin,
findAll(cache=60)andincludePartial(cache=20)speeding up the cold render underneath it.For discussion
appendToKey?clearCache(key)/ model-callback-driven invalidation change how you cache? What would you want the API to look like?Read the full post and let me know what's missing: https://blog.wheels.dev/posts/caching-in-wheels-4
All reactions